@heybox/hb-sdk-protocol 0.7.4-alpha.1

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 ADDED
@@ -0,0 +1,62 @@
1
+ # @heybox/hb-sdk-protocol
2
+
3
+ 小黑盒外部小程序 SDK 与宿主 Runtime 共用的零依赖 wire contract。它只描述跨 iframe 边界传输的数据和校验规则,不执行 bridge、网络、登录、存储或任何平台能力。
4
+
5
+ ## 边界
6
+
7
+ `@heybox/hb-sdk-protocol` 拥有:
8
+
9
+ - bridge namespace、协议版本、method 常量和事件名称;
10
+ - capability metadata(module、capability、permission、risk);
11
+ - method payload/result 与错误的 wire 类型;
12
+ - `runtime_permissions` schema 解析器和相关类型。
13
+
14
+ 它不拥有:
15
+
16
+ - `@heybox/hb-sdk` 的客户端状态机或默认单例;
17
+ - `@heybox/hb-sdk-runtime` 的 iframe、Host Port、Capability Module 或 Web Host;
18
+ - HTTP 请求、凭据、Cookie、登录 UI、业务 API 或客户端原生协议;
19
+ - DOM、Node.js、Electron 或任一具体平台实现。
20
+
21
+ 依赖方向固定为:
22
+
23
+ ```text
24
+ @heybox/hb-sdk-protocol <- @heybox/hb-sdk
25
+ @heybox/hb-sdk-protocol <- @heybox/hb-sdk-runtime
26
+ ```
27
+
28
+ 协议包不得反向依赖 SDK、Runtime 或应用。三包版本按 release family 锁步发布,顺序为 protocol -> Runtime -> SDK。
29
+
30
+ ## 使用方式
31
+
32
+ 宿主/Runtime 维护代码直接使用协议包:
33
+
34
+ ```ts
35
+ import {
36
+ MINI_PROGRAM_PROTOCOL_CAPABILITIES,
37
+ type MiniProgramBridgeMessage,
38
+ } from '@heybox/hb-sdk-protocol';
39
+ ```
40
+
41
+ 小程序业务代码不应导入该包;业务只使用 `@heybox/hb-sdk`。为了兼容已有 Host/Runtime 消费者,`@heybox/hb-sdk/protocol` 继续 re-export 本包的公开值和类型,但协议 owner 是本包。
42
+
43
+ ## 权限快照
44
+
45
+ `parseMiniProgramRuntimePermissions()` 是唯一的 schema v1 fail-closed 解析器。它校验 schema、entry 唯一性、managed key 和状态;未知但结构合法的新 key 会被保留/忽略,不会让当前版本误放行能力。Runtime 再使用 `hasMiniProgramNetworkRequestPermission()` 判断 `network.request` 是否明确启用。
46
+
47
+ 协议包不决定业务授权。`auth.login()` 的 UI、账号会话、授权码签发和 OpenAPI 都由 Host/服务端负责;协议层只传递经过约束的 request/response 数据。
48
+
49
+ ## 公开入口
50
+
51
+ - `@heybox/hb-sdk-protocol`:本包唯一入口,适合 Host、Runtime 和协议维护代码。
52
+ - `@heybox/hb-sdk/protocol`:SDK 的兼容入口,适合既有消费者;不应作为新的 contract owner。
53
+
54
+ 完整符号以源码导出和生成的 TypeScript declarations 为准。Runtime 集成见 [`@heybox/hb-sdk-runtime`](../hb-sdk-runtime/README.md),客户端能力见 [`@heybox/hb-sdk`](../hb-sdk/README.md)。
55
+
56
+ ## 验证
57
+
58
+ ```bash
59
+ pnpm --filter @heybox/hb-sdk-protocol run check:boundary
60
+ pnpm --filter @heybox/hb-sdk-protocol run test:unit
61
+ pnpm --filter @heybox/hb-sdk-protocol run build:package
62
+ ```
@@ -0,0 +1,215 @@
1
+ 'use strict';
2
+
3
+ const AUTH_LOGIN_METHOD = 'auth.login';
4
+ const USER_GET_INFO_METHOD = 'user.getInfo';
5
+ const USER_REVOKE_AUTHORIZATION_METHOD = 'user.revokeAuthorization';
6
+ const USER_GET_STEAM_GAME_LIST_METHOD = 'user.getSteamGameList';
7
+ const SHARE_SHOW_SHARE_MENU_METHOD = 'share.showShareMenu';
8
+ const SHARE_SCREENSHOT_METHOD = 'share.screenshot';
9
+ const VIEWPORT_GET_WINDOW_INFO_METHOD = 'viewport.getWindowInfo';
10
+ const VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD = 'viewport.setNavigationBarStyle';
11
+ const STORAGE_GET_STORAGE_METHOD = 'storage.getStorage';
12
+ const STORAGE_SET_STORAGE_METHOD = 'storage.setStorage';
13
+ const NETWORK_REQUEST_METHOD = 'network.request';
14
+ const UI_SHOW_TOAST_METHOD = 'ui.showToast';
15
+ const UI_SHOW_LOADING_METHOD = 'ui.showLoading';
16
+ const UI_HIDE_LOADING_METHOD = 'ui.hideLoading';
17
+ const DEVICE_VIBRATE_METHOD = 'device.vibrate';
18
+ const DEVICE_SET_CLIPBOARD_METHOD = 'device.setClipboard';
19
+ const NAVIGATION_CLOSE_METHOD = 'navigation.close';
20
+ const NAVIGATION_RELOAD_METHOD = 'navigation.reload';
21
+ const NAVIGATION_OPEN_APP_PAGE_METHOD = 'navigation.openAppPage';
22
+ const CLOUD_LEADERBOARD_SUBMIT_METHOD = 'cloud.leaderboard.submit';
23
+ const CLOUD_LEADERBOARD_GET_LIST_METHOD = 'cloud.leaderboard.getList';
24
+ const CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD = 'cloud.leaderboard.getCurrentUserEntry';
25
+ const CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD = 'cloud.leaderboard.deleteCurrentUserEntry';
26
+ const CLOUD_LEADERBOARD_GET_INFO_METHOD = 'cloud.leaderboard.getInfo';
27
+ const MINI_PROGRAM_PROTOCOL_CAPABILITIES = [
28
+ { method: AUTH_LOGIN_METHOD, module: 'auth', capability: AUTH_LOGIN_METHOD, permission: 'auth.login', risk: 'medium' },
29
+ { method: USER_GET_INFO_METHOD, module: 'user', capability: USER_GET_INFO_METHOD, permission: 'user.getInfo', risk: 'medium' },
30
+ {
31
+ method: USER_REVOKE_AUTHORIZATION_METHOD,
32
+ module: 'user',
33
+ capability: USER_REVOKE_AUTHORIZATION_METHOD,
34
+ permission: 'user.revokeAuthorization',
35
+ risk: 'high',
36
+ },
37
+ {
38
+ method: USER_GET_STEAM_GAME_LIST_METHOD,
39
+ module: 'user',
40
+ capability: USER_GET_STEAM_GAME_LIST_METHOD,
41
+ permission: 'user.platformAccount.steam',
42
+ risk: 'high',
43
+ },
44
+ { method: SHARE_SHOW_SHARE_MENU_METHOD, module: 'share', capability: SHARE_SHOW_SHARE_MENU_METHOD, permission: 'share.basic', risk: 'low' },
45
+ { method: SHARE_SCREENSHOT_METHOD, module: 'share', capability: SHARE_SCREENSHOT_METHOD, permission: 'share.screenshot', risk: 'medium' },
46
+ {
47
+ method: VIEWPORT_GET_WINDOW_INFO_METHOD,
48
+ module: 'viewport',
49
+ capability: VIEWPORT_GET_WINDOW_INFO_METHOD,
50
+ permission: 'viewport.windowInfo',
51
+ risk: 'low',
52
+ },
53
+ {
54
+ method: VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD,
55
+ module: 'viewport',
56
+ capability: VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD,
57
+ permission: 'viewport.navigationBarStyle',
58
+ risk: 'low',
59
+ },
60
+ { method: STORAGE_GET_STORAGE_METHOD, module: 'storage', capability: STORAGE_GET_STORAGE_METHOD, permission: 'storage.read', risk: 'low' },
61
+ { method: STORAGE_SET_STORAGE_METHOD, module: 'storage', capability: STORAGE_SET_STORAGE_METHOD, permission: 'storage.write', risk: 'medium' },
62
+ { method: NETWORK_REQUEST_METHOD, module: 'network', capability: NETWORK_REQUEST_METHOD, permission: 'network.request', risk: 'high' },
63
+ { method: UI_SHOW_TOAST_METHOD, module: 'ui', capability: UI_SHOW_TOAST_METHOD, permission: 'ui.toast', risk: 'low' },
64
+ { method: UI_SHOW_LOADING_METHOD, module: 'ui', capability: UI_SHOW_LOADING_METHOD, permission: 'ui.loading', risk: 'low' },
65
+ { method: UI_HIDE_LOADING_METHOD, module: 'ui', capability: UI_HIDE_LOADING_METHOD, permission: 'ui.loading', risk: 'low' },
66
+ { method: DEVICE_VIBRATE_METHOD, module: 'device', capability: DEVICE_VIBRATE_METHOD, permission: 'device.vibrate', risk: 'low' },
67
+ {
68
+ method: DEVICE_SET_CLIPBOARD_METHOD,
69
+ module: 'device',
70
+ capability: DEVICE_SET_CLIPBOARD_METHOD,
71
+ permission: 'device.clipboard.write',
72
+ risk: 'medium',
73
+ },
74
+ { method: NAVIGATION_CLOSE_METHOD, module: 'navigation', capability: NAVIGATION_CLOSE_METHOD, permission: 'navigation.close', risk: 'medium' },
75
+ { method: NAVIGATION_RELOAD_METHOD, module: 'navigation', capability: NAVIGATION_RELOAD_METHOD, permission: 'navigation.reload', risk: 'medium' },
76
+ {
77
+ method: NAVIGATION_OPEN_APP_PAGE_METHOD,
78
+ module: 'navigation',
79
+ capability: NAVIGATION_OPEN_APP_PAGE_METHOD,
80
+ permission: 'navigation.openAppPage',
81
+ risk: 'medium',
82
+ },
83
+ {
84
+ method: CLOUD_LEADERBOARD_SUBMIT_METHOD,
85
+ module: 'cloud',
86
+ capability: CLOUD_LEADERBOARD_SUBMIT_METHOD,
87
+ permission: 'cloud.leaderboard.write',
88
+ risk: 'medium',
89
+ },
90
+ {
91
+ method: CLOUD_LEADERBOARD_GET_LIST_METHOD,
92
+ module: 'cloud',
93
+ capability: CLOUD_LEADERBOARD_GET_LIST_METHOD,
94
+ permission: 'cloud.leaderboard.read',
95
+ risk: 'low',
96
+ },
97
+ {
98
+ method: CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD,
99
+ module: 'cloud',
100
+ capability: CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD,
101
+ permission: 'cloud.leaderboard.currentUserEntry.read',
102
+ risk: 'medium',
103
+ },
104
+ {
105
+ method: CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD,
106
+ module: 'cloud',
107
+ capability: CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD,
108
+ permission: 'cloud.leaderboard.currentUserEntry.delete',
109
+ risk: 'medium',
110
+ },
111
+ {
112
+ method: CLOUD_LEADERBOARD_GET_INFO_METHOD,
113
+ module: 'cloud',
114
+ capability: CLOUD_LEADERBOARD_GET_INFO_METHOD,
115
+ permission: 'cloud.leaderboard.info.read',
116
+ risk: 'low',
117
+ },
118
+ ];
119
+
120
+ const MINI_PROGRAM_MESSAGE_NAMESPACE = 'heybox:miniprogram';
121
+ const MINI_PROGRAM_MESSAGE_VERSION = 2;
122
+ const MINI_PROGRAM_BRIDGE_NONCE_PARAM = 'hb_mini_bridge_nonce';
123
+ const SDK_HANDSHAKE_METHOD = 'sdk.handshake';
124
+ const RUNTIME_LOCATION_PROBE_METHOD = 'runtime.location.probe';
125
+ const SDK_LOCATION_REPORT_METHOD = 'sdk.location.report';
126
+ const SDK_CSP_VIOLATION_METHOD = 'sdk.csp.violation';
127
+
128
+ function isMiniProgramBridgeMessage(value) {
129
+ if (!value || typeof value !== 'object')
130
+ return false;
131
+ const message = value;
132
+ return (message.namespace === MINI_PROGRAM_MESSAGE_NAMESPACE &&
133
+ (message.version === 1 || message.version === 2) &&
134
+ typeof message.nonce === 'string' &&
135
+ typeof message.type === 'string');
136
+ }
137
+
138
+ /** 当前用户信息与登录能力支持的完整 scope 目录。 */
139
+ const USER_INFO_AUTHORIZATION_SCOPES = ['identity', 'profile'];
140
+
141
+ const MANAGED_RUNTIME_PERMISSION_KEYS = new Set(['network.request']);
142
+ function isManagedMiniProgramRuntimePermissionKey(key) {
143
+ return MANAGED_RUNTIME_PERMISSION_KEYS.has(key);
144
+ }
145
+ function parseMiniProgramRuntimePermissions(snapshot) {
146
+ if (!isRecord(snapshot) || snapshot.schema_version !== 1 || !Array.isArray(snapshot.entries)) {
147
+ return { valid: false, permissions: {} };
148
+ }
149
+ if (snapshot.revision !== undefined && (typeof snapshot.revision !== 'number' || !Number.isInteger(snapshot.revision) || snapshot.revision < 0)) {
150
+ return { valid: false, permissions: {} };
151
+ }
152
+ const seenKeys = new Set();
153
+ const permissions = {};
154
+ for (const rawEntry of snapshot.entries) {
155
+ if (!isRecord(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
156
+ return { valid: false, permissions: {} };
157
+ }
158
+ const key = rawEntry.key.trim();
159
+ if (seenKeys.has(key) || (rawEntry.status !== 'enabled' && rawEntry.status !== 'disabled') || !isRecord(rawEntry.config)) {
160
+ return { valid: false, permissions: {} };
161
+ }
162
+ seenKeys.add(key);
163
+ if (!isManagedMiniProgramRuntimePermissionKey(key))
164
+ continue;
165
+ if (key === 'network.request' && typeof rawEntry.config.useOfficialDomain !== 'boolean') {
166
+ return { valid: false, permissions: {} };
167
+ }
168
+ permissions[key] = {
169
+ key,
170
+ status: rawEntry.status,
171
+ config: { useOfficialDomain: rawEntry.config.useOfficialDomain },
172
+ };
173
+ }
174
+ return { valid: true, permissions };
175
+ }
176
+ function isRecord(value) {
177
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
178
+ }
179
+
180
+ exports.AUTH_LOGIN_METHOD = AUTH_LOGIN_METHOD;
181
+ exports.CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD = CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD;
182
+ exports.CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD = CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD;
183
+ exports.CLOUD_LEADERBOARD_GET_INFO_METHOD = CLOUD_LEADERBOARD_GET_INFO_METHOD;
184
+ exports.CLOUD_LEADERBOARD_GET_LIST_METHOD = CLOUD_LEADERBOARD_GET_LIST_METHOD;
185
+ exports.CLOUD_LEADERBOARD_SUBMIT_METHOD = CLOUD_LEADERBOARD_SUBMIT_METHOD;
186
+ exports.DEVICE_SET_CLIPBOARD_METHOD = DEVICE_SET_CLIPBOARD_METHOD;
187
+ exports.DEVICE_VIBRATE_METHOD = DEVICE_VIBRATE_METHOD;
188
+ exports.MINI_PROGRAM_BRIDGE_NONCE_PARAM = MINI_PROGRAM_BRIDGE_NONCE_PARAM;
189
+ exports.MINI_PROGRAM_MESSAGE_NAMESPACE = MINI_PROGRAM_MESSAGE_NAMESPACE;
190
+ exports.MINI_PROGRAM_MESSAGE_VERSION = MINI_PROGRAM_MESSAGE_VERSION;
191
+ exports.MINI_PROGRAM_PROTOCOL_CAPABILITIES = MINI_PROGRAM_PROTOCOL_CAPABILITIES;
192
+ exports.NAVIGATION_CLOSE_METHOD = NAVIGATION_CLOSE_METHOD;
193
+ exports.NAVIGATION_OPEN_APP_PAGE_METHOD = NAVIGATION_OPEN_APP_PAGE_METHOD;
194
+ exports.NAVIGATION_RELOAD_METHOD = NAVIGATION_RELOAD_METHOD;
195
+ exports.NETWORK_REQUEST_METHOD = NETWORK_REQUEST_METHOD;
196
+ exports.RUNTIME_LOCATION_PROBE_METHOD = RUNTIME_LOCATION_PROBE_METHOD;
197
+ exports.SDK_CSP_VIOLATION_METHOD = SDK_CSP_VIOLATION_METHOD;
198
+ exports.SDK_HANDSHAKE_METHOD = SDK_HANDSHAKE_METHOD;
199
+ exports.SDK_LOCATION_REPORT_METHOD = SDK_LOCATION_REPORT_METHOD;
200
+ exports.SHARE_SCREENSHOT_METHOD = SHARE_SCREENSHOT_METHOD;
201
+ exports.SHARE_SHOW_SHARE_MENU_METHOD = SHARE_SHOW_SHARE_MENU_METHOD;
202
+ exports.STORAGE_GET_STORAGE_METHOD = STORAGE_GET_STORAGE_METHOD;
203
+ exports.STORAGE_SET_STORAGE_METHOD = STORAGE_SET_STORAGE_METHOD;
204
+ exports.UI_HIDE_LOADING_METHOD = UI_HIDE_LOADING_METHOD;
205
+ exports.UI_SHOW_LOADING_METHOD = UI_SHOW_LOADING_METHOD;
206
+ exports.UI_SHOW_TOAST_METHOD = UI_SHOW_TOAST_METHOD;
207
+ exports.USER_GET_INFO_METHOD = USER_GET_INFO_METHOD;
208
+ exports.USER_GET_STEAM_GAME_LIST_METHOD = USER_GET_STEAM_GAME_LIST_METHOD;
209
+ exports.USER_INFO_AUTHORIZATION_SCOPES = USER_INFO_AUTHORIZATION_SCOPES;
210
+ exports.USER_REVOKE_AUTHORIZATION_METHOD = USER_REVOKE_AUTHORIZATION_METHOD;
211
+ exports.VIEWPORT_GET_WINDOW_INFO_METHOD = VIEWPORT_GET_WINDOW_INFO_METHOD;
212
+ exports.VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD = VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD;
213
+ exports.isManagedMiniProgramRuntimePermissionKey = isManagedMiniProgramRuntimePermissionKey;
214
+ exports.isMiniProgramBridgeMessage = isMiniProgramBridgeMessage;
215
+ exports.parseMiniProgramRuntimePermissions = parseMiniProgramRuntimePermissions;
@@ -0,0 +1,178 @@
1
+ const AUTH_LOGIN_METHOD = 'auth.login';
2
+ const USER_GET_INFO_METHOD = 'user.getInfo';
3
+ const USER_REVOKE_AUTHORIZATION_METHOD = 'user.revokeAuthorization';
4
+ const USER_GET_STEAM_GAME_LIST_METHOD = 'user.getSteamGameList';
5
+ const SHARE_SHOW_SHARE_MENU_METHOD = 'share.showShareMenu';
6
+ const SHARE_SCREENSHOT_METHOD = 'share.screenshot';
7
+ const VIEWPORT_GET_WINDOW_INFO_METHOD = 'viewport.getWindowInfo';
8
+ const VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD = 'viewport.setNavigationBarStyle';
9
+ const STORAGE_GET_STORAGE_METHOD = 'storage.getStorage';
10
+ const STORAGE_SET_STORAGE_METHOD = 'storage.setStorage';
11
+ const NETWORK_REQUEST_METHOD = 'network.request';
12
+ const UI_SHOW_TOAST_METHOD = 'ui.showToast';
13
+ const UI_SHOW_LOADING_METHOD = 'ui.showLoading';
14
+ const UI_HIDE_LOADING_METHOD = 'ui.hideLoading';
15
+ const DEVICE_VIBRATE_METHOD = 'device.vibrate';
16
+ const DEVICE_SET_CLIPBOARD_METHOD = 'device.setClipboard';
17
+ const NAVIGATION_CLOSE_METHOD = 'navigation.close';
18
+ const NAVIGATION_RELOAD_METHOD = 'navigation.reload';
19
+ const NAVIGATION_OPEN_APP_PAGE_METHOD = 'navigation.openAppPage';
20
+ const CLOUD_LEADERBOARD_SUBMIT_METHOD = 'cloud.leaderboard.submit';
21
+ const CLOUD_LEADERBOARD_GET_LIST_METHOD = 'cloud.leaderboard.getList';
22
+ const CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD = 'cloud.leaderboard.getCurrentUserEntry';
23
+ const CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD = 'cloud.leaderboard.deleteCurrentUserEntry';
24
+ const CLOUD_LEADERBOARD_GET_INFO_METHOD = 'cloud.leaderboard.getInfo';
25
+ const MINI_PROGRAM_PROTOCOL_CAPABILITIES = [
26
+ { method: AUTH_LOGIN_METHOD, module: 'auth', capability: AUTH_LOGIN_METHOD, permission: 'auth.login', risk: 'medium' },
27
+ { method: USER_GET_INFO_METHOD, module: 'user', capability: USER_GET_INFO_METHOD, permission: 'user.getInfo', risk: 'medium' },
28
+ {
29
+ method: USER_REVOKE_AUTHORIZATION_METHOD,
30
+ module: 'user',
31
+ capability: USER_REVOKE_AUTHORIZATION_METHOD,
32
+ permission: 'user.revokeAuthorization',
33
+ risk: 'high',
34
+ },
35
+ {
36
+ method: USER_GET_STEAM_GAME_LIST_METHOD,
37
+ module: 'user',
38
+ capability: USER_GET_STEAM_GAME_LIST_METHOD,
39
+ permission: 'user.platformAccount.steam',
40
+ risk: 'high',
41
+ },
42
+ { method: SHARE_SHOW_SHARE_MENU_METHOD, module: 'share', capability: SHARE_SHOW_SHARE_MENU_METHOD, permission: 'share.basic', risk: 'low' },
43
+ { method: SHARE_SCREENSHOT_METHOD, module: 'share', capability: SHARE_SCREENSHOT_METHOD, permission: 'share.screenshot', risk: 'medium' },
44
+ {
45
+ method: VIEWPORT_GET_WINDOW_INFO_METHOD,
46
+ module: 'viewport',
47
+ capability: VIEWPORT_GET_WINDOW_INFO_METHOD,
48
+ permission: 'viewport.windowInfo',
49
+ risk: 'low',
50
+ },
51
+ {
52
+ method: VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD,
53
+ module: 'viewport',
54
+ capability: VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD,
55
+ permission: 'viewport.navigationBarStyle',
56
+ risk: 'low',
57
+ },
58
+ { method: STORAGE_GET_STORAGE_METHOD, module: 'storage', capability: STORAGE_GET_STORAGE_METHOD, permission: 'storage.read', risk: 'low' },
59
+ { method: STORAGE_SET_STORAGE_METHOD, module: 'storage', capability: STORAGE_SET_STORAGE_METHOD, permission: 'storage.write', risk: 'medium' },
60
+ { method: NETWORK_REQUEST_METHOD, module: 'network', capability: NETWORK_REQUEST_METHOD, permission: 'network.request', risk: 'high' },
61
+ { method: UI_SHOW_TOAST_METHOD, module: 'ui', capability: UI_SHOW_TOAST_METHOD, permission: 'ui.toast', risk: 'low' },
62
+ { method: UI_SHOW_LOADING_METHOD, module: 'ui', capability: UI_SHOW_LOADING_METHOD, permission: 'ui.loading', risk: 'low' },
63
+ { method: UI_HIDE_LOADING_METHOD, module: 'ui', capability: UI_HIDE_LOADING_METHOD, permission: 'ui.loading', risk: 'low' },
64
+ { method: DEVICE_VIBRATE_METHOD, module: 'device', capability: DEVICE_VIBRATE_METHOD, permission: 'device.vibrate', risk: 'low' },
65
+ {
66
+ method: DEVICE_SET_CLIPBOARD_METHOD,
67
+ module: 'device',
68
+ capability: DEVICE_SET_CLIPBOARD_METHOD,
69
+ permission: 'device.clipboard.write',
70
+ risk: 'medium',
71
+ },
72
+ { method: NAVIGATION_CLOSE_METHOD, module: 'navigation', capability: NAVIGATION_CLOSE_METHOD, permission: 'navigation.close', risk: 'medium' },
73
+ { method: NAVIGATION_RELOAD_METHOD, module: 'navigation', capability: NAVIGATION_RELOAD_METHOD, permission: 'navigation.reload', risk: 'medium' },
74
+ {
75
+ method: NAVIGATION_OPEN_APP_PAGE_METHOD,
76
+ module: 'navigation',
77
+ capability: NAVIGATION_OPEN_APP_PAGE_METHOD,
78
+ permission: 'navigation.openAppPage',
79
+ risk: 'medium',
80
+ },
81
+ {
82
+ method: CLOUD_LEADERBOARD_SUBMIT_METHOD,
83
+ module: 'cloud',
84
+ capability: CLOUD_LEADERBOARD_SUBMIT_METHOD,
85
+ permission: 'cloud.leaderboard.write',
86
+ risk: 'medium',
87
+ },
88
+ {
89
+ method: CLOUD_LEADERBOARD_GET_LIST_METHOD,
90
+ module: 'cloud',
91
+ capability: CLOUD_LEADERBOARD_GET_LIST_METHOD,
92
+ permission: 'cloud.leaderboard.read',
93
+ risk: 'low',
94
+ },
95
+ {
96
+ method: CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD,
97
+ module: 'cloud',
98
+ capability: CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD,
99
+ permission: 'cloud.leaderboard.currentUserEntry.read',
100
+ risk: 'medium',
101
+ },
102
+ {
103
+ method: CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD,
104
+ module: 'cloud',
105
+ capability: CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD,
106
+ permission: 'cloud.leaderboard.currentUserEntry.delete',
107
+ risk: 'medium',
108
+ },
109
+ {
110
+ method: CLOUD_LEADERBOARD_GET_INFO_METHOD,
111
+ module: 'cloud',
112
+ capability: CLOUD_LEADERBOARD_GET_INFO_METHOD,
113
+ permission: 'cloud.leaderboard.info.read',
114
+ risk: 'low',
115
+ },
116
+ ];
117
+
118
+ const MINI_PROGRAM_MESSAGE_NAMESPACE = 'heybox:miniprogram';
119
+ const MINI_PROGRAM_MESSAGE_VERSION = 2;
120
+ const MINI_PROGRAM_BRIDGE_NONCE_PARAM = 'hb_mini_bridge_nonce';
121
+ const SDK_HANDSHAKE_METHOD = 'sdk.handshake';
122
+ const RUNTIME_LOCATION_PROBE_METHOD = 'runtime.location.probe';
123
+ const SDK_LOCATION_REPORT_METHOD = 'sdk.location.report';
124
+ const SDK_CSP_VIOLATION_METHOD = 'sdk.csp.violation';
125
+
126
+ function isMiniProgramBridgeMessage(value) {
127
+ if (!value || typeof value !== 'object')
128
+ return false;
129
+ const message = value;
130
+ return (message.namespace === MINI_PROGRAM_MESSAGE_NAMESPACE &&
131
+ (message.version === 1 || message.version === 2) &&
132
+ typeof message.nonce === 'string' &&
133
+ typeof message.type === 'string');
134
+ }
135
+
136
+ /** 当前用户信息与登录能力支持的完整 scope 目录。 */
137
+ const USER_INFO_AUTHORIZATION_SCOPES = ['identity', 'profile'];
138
+
139
+ const MANAGED_RUNTIME_PERMISSION_KEYS = new Set(['network.request']);
140
+ function isManagedMiniProgramRuntimePermissionKey(key) {
141
+ return MANAGED_RUNTIME_PERMISSION_KEYS.has(key);
142
+ }
143
+ function parseMiniProgramRuntimePermissions(snapshot) {
144
+ if (!isRecord(snapshot) || snapshot.schema_version !== 1 || !Array.isArray(snapshot.entries)) {
145
+ return { valid: false, permissions: {} };
146
+ }
147
+ if (snapshot.revision !== undefined && (typeof snapshot.revision !== 'number' || !Number.isInteger(snapshot.revision) || snapshot.revision < 0)) {
148
+ return { valid: false, permissions: {} };
149
+ }
150
+ const seenKeys = new Set();
151
+ const permissions = {};
152
+ for (const rawEntry of snapshot.entries) {
153
+ if (!isRecord(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
154
+ return { valid: false, permissions: {} };
155
+ }
156
+ const key = rawEntry.key.trim();
157
+ if (seenKeys.has(key) || (rawEntry.status !== 'enabled' && rawEntry.status !== 'disabled') || !isRecord(rawEntry.config)) {
158
+ return { valid: false, permissions: {} };
159
+ }
160
+ seenKeys.add(key);
161
+ if (!isManagedMiniProgramRuntimePermissionKey(key))
162
+ continue;
163
+ if (key === 'network.request' && typeof rawEntry.config.useOfficialDomain !== 'boolean') {
164
+ return { valid: false, permissions: {} };
165
+ }
166
+ permissions[key] = {
167
+ key,
168
+ status: rawEntry.status,
169
+ config: { useOfficialDomain: rawEntry.config.useOfficialDomain },
170
+ };
171
+ }
172
+ return { valid: true, permissions };
173
+ }
174
+ function isRecord(value) {
175
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
176
+ }
177
+
178
+ export { AUTH_LOGIN_METHOD, CLOUD_LEADERBOARD_DELETE_CURRENT_USER_ENTRY_METHOD, CLOUD_LEADERBOARD_GET_CURRENT_USER_ENTRY_METHOD, CLOUD_LEADERBOARD_GET_INFO_METHOD, CLOUD_LEADERBOARD_GET_LIST_METHOD, CLOUD_LEADERBOARD_SUBMIT_METHOD, DEVICE_SET_CLIPBOARD_METHOD, DEVICE_VIBRATE_METHOD, MINI_PROGRAM_BRIDGE_NONCE_PARAM, MINI_PROGRAM_MESSAGE_NAMESPACE, MINI_PROGRAM_MESSAGE_VERSION, MINI_PROGRAM_PROTOCOL_CAPABILITIES, NAVIGATION_CLOSE_METHOD, NAVIGATION_OPEN_APP_PAGE_METHOD, NAVIGATION_RELOAD_METHOD, NETWORK_REQUEST_METHOD, RUNTIME_LOCATION_PROBE_METHOD, SDK_CSP_VIOLATION_METHOD, SDK_HANDSHAKE_METHOD, SDK_LOCATION_REPORT_METHOD, SHARE_SCREENSHOT_METHOD, SHARE_SHOW_SHARE_MENU_METHOD, STORAGE_GET_STORAGE_METHOD, STORAGE_SET_STORAGE_METHOD, UI_HIDE_LOADING_METHOD, UI_SHOW_LOADING_METHOD, UI_SHOW_TOAST_METHOD, USER_GET_INFO_METHOD, USER_GET_STEAM_GAME_LIST_METHOD, USER_INFO_AUTHORIZATION_SCOPES, USER_REVOKE_AUTHORIZATION_METHOD, VIEWPORT_GET_WINDOW_INFO_METHOD, VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD, isManagedMiniProgramRuntimePermissionKey, isMiniProgramBridgeMessage, parseMiniProgramRuntimePermissions };
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@heybox/hb-sdk-protocol",
3
+ "version": "0.7.4-alpha.1",
4
+ "description": "Heybox mini-program iframe bridge wire contracts.",
5
+ "sideEffects": false,
6
+ "exports": {
7
+ ".": {
8
+ "types": "./types/index.d.ts",
9
+ "heybox": "./src/index.ts",
10
+ "import": "./dist/index.esm.js",
11
+ "require": "./dist/index.cjs.js",
12
+ "default": "./dist/index.esm.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "types",
18
+ "src",
19
+ "README.md"
20
+ ],
21
+ "license": "ISC",
22
+ "dependencies": {},
23
+ "devDependencies": {
24
+ "@rollup/plugin-typescript": "^11.1.6",
25
+ "@types/node": "24.10.1",
26
+ "rimraf": "^5.0.5",
27
+ "rollup": "^4.52.4",
28
+ "typescript": "^5.9.3",
29
+ "vitest": "^3.2.4",
30
+ "@heybox/hb-types": "~1.0.2"
31
+ },
32
+ "publishConfig": {
33
+ "registry": "https://registry.npmjs.org/",
34
+ "access": "public"
35
+ },
36
+ "scripts": {
37
+ "build:package": "pnpm run clean && pnpm run build:lib && pnpm run build:types",
38
+ "build:lib": "rollup -c rollup.config.ts --configPlugin 'typescript={\"tsconfig\":\"tsconfig.build.json\"}'",
39
+ "build:types": "tsc -p tsconfig.dts.json",
40
+ "test:types": "tsc -p tsconfig.dts.json --noEmit --pretty false",
41
+ "clean": "rimraf ./dist && rimraf ./types",
42
+ "check:boundary": "node scripts/check-boundary.cjs",
43
+ "test:unit": "NODE_OPTIONS='--conditions=heybox' vitest run",
44
+ "test:watch": "NODE_OPTIONS='--conditions=heybox' vitest"
45
+ }
46
+ }
package/src/bridge.ts ADDED
@@ -0,0 +1,68 @@
1
+ import { MINI_PROGRAM_MESSAGE_NAMESPACE } from './constants';
2
+ import type { UserInfoAuthorization } from './payloads';
3
+
4
+ export type MiniProgramBridgeMessageType = 'handshake' | 'request' | 'response' | 'event';
5
+ export type MiniProgramEventName =
6
+ | 'launch'
7
+ | 'ready'
8
+ | 'show'
9
+ | 'hide'
10
+ | 'unload'
11
+ | 'error'
12
+ | 'heybox_app_login_change'
13
+ | 'user_info_authorization_change';
14
+
15
+ export interface MiniProgramBridgeError {
16
+ code: string;
17
+ message: string;
18
+ data?: unknown;
19
+ }
20
+ export interface SDKHandshakePayload {
21
+ href: string;
22
+ userAgent: string;
23
+ sdkVersion: string;
24
+ }
25
+ export interface RuntimeLocationProbePayload {
26
+ probeId: string;
27
+ timestamp: number;
28
+ }
29
+ export type SDKLocationReportTrigger = 'probe' | 'history' | 'popstate' | 'hashchange' | 'pageshow' | 'resume';
30
+ export interface SDKLocationReportPayload {
31
+ probeId?: string;
32
+ href: string;
33
+ sdkVersion: string;
34
+ trigger: SDKLocationReportTrigger;
35
+ timestamp: number;
36
+ }
37
+ export type SDKCSPBlockedResourceType = 'url' | 'inline' | 'eval' | 'unknown';
38
+ export interface SDKCSPViolationPayload {
39
+ effectiveDirective: string;
40
+ violatedDirective: string;
41
+ disposition: string;
42
+ blockedResourceType: SDKCSPBlockedResourceType;
43
+ blockedOrigin?: string;
44
+ redactedPathname?: string;
45
+ sanitizedPathnameHash?: string;
46
+ sdkVersion: string;
47
+ timestamp: number;
48
+ }
49
+ export interface MiniProgramBridgeMessage<TPayload = unknown> {
50
+ namespace: typeof MINI_PROGRAM_MESSAGE_NAMESPACE;
51
+ version: 1 | 2;
52
+ nonce: string;
53
+ type: MiniProgramBridgeMessageType;
54
+ id?: string;
55
+ method?: string;
56
+ payload?: TPayload;
57
+ error?: MiniProgramBridgeError;
58
+ }
59
+ export interface MiniProgramEventPayloadMap {
60
+ launch: { timestamp: number; url?: string };
61
+ ready: { timestamp: number };
62
+ show: { timestamp: number; source?: string };
63
+ hide: { timestamp: number; source?: string };
64
+ unload: { timestamp: number };
65
+ error: MiniProgramBridgeError;
66
+ heybox_app_login_change: { isHeyboxAppLoggedIn: boolean };
67
+ user_info_authorization_change: UserInfoAuthorization;
68
+ }