@heybox/hb-sdk-protocol 0.8.0-alpha → 0.8.0-alpha.12

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/src/index.ts CHANGED
@@ -3,4 +3,5 @@ export * from './capabilities';
3
3
  export * from './constants';
4
4
  export * from './guards';
5
5
  export * from './payloads';
6
+ export * from './permission-catalog';
6
7
  export * from './permissions';
package/src/payloads.ts CHANGED
@@ -116,7 +116,6 @@ export interface MiniProgramScreenshotRect {
116
116
  export type ShowShareMenuPayload = {
117
117
  title: string;
118
118
  desc: string;
119
- url?: string;
120
119
  extra?: unknown;
121
120
  imageUrl?: string;
122
121
  channel?: MiniProgramShareChannel;
@@ -189,6 +188,180 @@ export interface NetworkResponsePayload<T = unknown> {
189
188
  headers: MiniProgramNetworkHeaders;
190
189
  }
191
190
 
191
+ export type MiniProgramFileMode = 'read' | 'readwrite';
192
+
193
+ export interface MiniProgramSandboxRootRef {
194
+ kind: 'sandbox';
195
+ }
196
+
197
+ export interface MiniProgramDirectFileRef {
198
+ kind: 'file';
199
+ handleId: string;
200
+ }
201
+
202
+ export interface MiniProgramDirectDirectoryRef {
203
+ kind: 'directory';
204
+ handleId: string;
205
+ }
206
+
207
+ export type MiniProgramPathRootRef = MiniProgramSandboxRootRef | MiniProgramDirectDirectoryRef;
208
+
209
+ export interface MiniProgramDerivedFileRef {
210
+ kind: 'file';
211
+ root: MiniProgramPathRootRef;
212
+ relativePath: string;
213
+ }
214
+
215
+ export interface MiniProgramDerivedDirectoryRef {
216
+ kind: 'directory';
217
+ root: MiniProgramPathRootRef;
218
+ relativePath: string;
219
+ }
220
+
221
+ export type MiniProgramFileRef = MiniProgramDirectFileRef | MiniProgramDerivedFileRef;
222
+ export type MiniProgramDirectoryRef = MiniProgramDirectDirectoryRef | MiniProgramDerivedDirectoryRef;
223
+ export type MiniProgramFileSystemEntityRef = MiniProgramFileRef | MiniProgramDirectoryRef;
224
+
225
+ export interface MiniProgramFileDescriptor {
226
+ kind: 'file';
227
+ name: string;
228
+ mode: MiniProgramFileMode;
229
+ ref: MiniProgramFileRef;
230
+ }
231
+
232
+ export interface MiniProgramDirectoryDescriptor {
233
+ kind: 'directory';
234
+ name: string;
235
+ mode: MiniProgramFileMode;
236
+ ref: MiniProgramDirectoryRef;
237
+ }
238
+
239
+ export type MiniProgramFileSystemEntityDescriptor = MiniProgramFileDescriptor | MiniProgramDirectoryDescriptor;
240
+
241
+ export interface MiniProgramCreateOptions {
242
+ recursive?: boolean;
243
+ exclusive?: boolean;
244
+ }
245
+
246
+ export interface MiniProgramFileStat {
247
+ kind: 'file';
248
+ size: number;
249
+ modifiedAt?: number;
250
+ createdAt?: number;
251
+ }
252
+
253
+ export type PickFilesPayload =
254
+ | {
255
+ mode?: MiniProgramFileMode;
256
+ accept?: string[];
257
+ multiple?: boolean;
258
+ }
259
+ | undefined;
260
+ export type PickFilesResult = Array<MiniProgramFileDescriptor & { ref: MiniProgramDirectFileRef }>;
261
+
262
+ export type PickDirectoryPayload = { mode?: MiniProgramFileMode } | undefined;
263
+ export type PickDirectoryResult = MiniProgramDirectoryDescriptor & { ref: MiniProgramDirectDirectoryRef };
264
+
265
+ export interface SaveFilePayload {
266
+ suggestedName: string;
267
+ }
268
+ export type SaveFileResult = MiniProgramFileDescriptor & { ref: MiniProgramDirectFileRef };
269
+
270
+ export interface FileCreatePayload extends MiniProgramCreateOptions {
271
+ target: MiniProgramFileRef;
272
+ }
273
+ export type FileCreateResult = void;
274
+
275
+ export interface FileRemovePayload {
276
+ target: MiniProgramFileRef;
277
+ }
278
+ export type FileRemoveResult = void;
279
+
280
+ export interface FileExistsPayload {
281
+ target: MiniProgramFileRef;
282
+ }
283
+ export type FileExistsResult = boolean;
284
+
285
+ export interface FileReadTextPayload {
286
+ target: MiniProgramFileRef;
287
+ }
288
+ export type FileReadTextResult = string;
289
+
290
+ export interface FileWriteTextPayload {
291
+ target: MiniProgramFileRef;
292
+ content: string;
293
+ }
294
+ export type FileWriteTextResult = void;
295
+
296
+ export interface FileReadBytesPayload {
297
+ target: MiniProgramFileRef;
298
+ }
299
+ export type FileReadBytesResult = Uint8Array;
300
+
301
+ export interface FileWriteBytesPayload {
302
+ target: MiniProgramFileRef;
303
+ content: Uint8Array;
304
+ }
305
+ export type FileWriteBytesResult = void;
306
+
307
+ export interface FileStatPayload {
308
+ target: MiniProgramFileRef;
309
+ }
310
+ export type FileStatResult = MiniProgramFileStat;
311
+
312
+ export interface DirectoryCreatePayload extends MiniProgramCreateOptions {
313
+ target: MiniProgramDirectoryRef;
314
+ }
315
+ export type DirectoryCreateResult = void;
316
+
317
+ export interface DirectoryRemovePayload {
318
+ target: MiniProgramDirectoryRef;
319
+ recursive?: boolean;
320
+ }
321
+ export type DirectoryRemoveResult = void;
322
+
323
+ export interface DirectoryExistsPayload {
324
+ target: MiniProgramDirectoryRef;
325
+ }
326
+ export type DirectoryExistsResult = boolean;
327
+
328
+ export interface DirectoryListPayload {
329
+ target: MiniProgramDirectoryRef;
330
+ limit?: number;
331
+ }
332
+ export type DirectoryListResult = MiniProgramFileSystemEntityDescriptor[];
333
+
334
+ export interface DownloadProgressPayload {
335
+ loaded: number;
336
+ total?: number;
337
+ lengthComputable: boolean;
338
+ }
339
+
340
+ interface NetworkDownloadBasePayload {
341
+ url: string;
342
+ params?: MiniProgramNetworkParams;
343
+ headers?: MiniProgramNetworkHeaders;
344
+ timeout?: number;
345
+ withCredentials?: boolean;
346
+ maxBytes?: number;
347
+ }
348
+
349
+ export type NetworkDownloadPayload = NetworkDownloadBasePayload &
350
+ (
351
+ | {
352
+ to: MiniProgramFileRef;
353
+ suggestedName?: never;
354
+ overwrite?: never;
355
+ }
356
+ | {
357
+ to: MiniProgramDirectoryRef;
358
+ suggestedName?: string;
359
+ overwrite?: boolean;
360
+ }
361
+ );
362
+
363
+ export type NetworkDownloadResult = MiniProgramFileDescriptor;
364
+
192
365
  export type MiniProgramToastStatus = 'success' | 'error';
193
366
  export interface ShowToastPayload {
194
367
  message: string;
@@ -0,0 +1,168 @@
1
+ import type { MiniProgramBridgeMethod, MiniProgramCapabilityRisk } from './capabilities';
2
+
3
+ export const MINI_PROGRAM_PERMISSION_KEYS = [
4
+ 'userInfo',
5
+ 'steamLibrary',
6
+ 'share',
7
+ 'storage',
8
+ 'filesystem',
9
+ 'clipboard',
10
+ 'leaderboard',
11
+ 'network',
12
+ ] as const;
13
+
14
+ export type MiniProgramPermissionKey = (typeof MINI_PROGRAM_PERMISSION_KEYS)[number];
15
+ export type MiniProgramPermissionRequirement =
16
+ | { readonly kind: 'none' }
17
+ | { readonly kind: 'all'; readonly permissions: readonly MiniProgramPermissionKey[] };
18
+ export type MiniProgramPermissionAccess = 'declaration' | 'platform-approval';
19
+
20
+ export interface MiniProgramPermissionConfigFieldDefinition {
21
+ readonly type: 'boolean';
22
+ readonly required: boolean;
23
+ readonly default: boolean;
24
+ readonly description: string;
25
+ }
26
+
27
+ export interface MiniProgramPermissionDefinition {
28
+ readonly key: MiniProgramPermissionKey;
29
+ readonly name: string;
30
+ readonly description: string;
31
+ readonly access: MiniProgramPermissionAccess;
32
+ readonly risk: MiniProgramCapabilityRisk;
33
+ readonly config: Readonly<Record<string, MiniProgramPermissionConfigFieldDefinition>>;
34
+ readonly methods: readonly MiniProgramBridgeMethod[];
35
+ readonly conditions: readonly string[];
36
+ }
37
+
38
+ export const MINI_PROGRAM_PERMISSION_CATALOG = [
39
+ {
40
+ key: 'userInfo',
41
+ name: '用户信息',
42
+ description: '登录小程序并读取当前用户的授权信息。',
43
+ access: 'declaration',
44
+ risk: 'medium',
45
+ config: {},
46
+ methods: ['auth.login', 'user.getInfo'],
47
+ conditions: ['继续执行黑盒登录、用户授权和可信手势规则。'],
48
+ },
49
+ {
50
+ key: 'steamLibrary',
51
+ name: 'Steam 游戏库',
52
+ description: '读取当前用户授权的 Steam 游戏库。',
53
+ access: 'declaration',
54
+ risk: 'high',
55
+ config: {},
56
+ methods: ['user.getSteamGameList'],
57
+ conditions: ['继续执行账号绑定和数据可用性规则。'],
58
+ },
59
+ {
60
+ key: 'share',
61
+ name: '分享',
62
+ description: '使用小程序分享、分享菜单和截图能力。',
63
+ access: 'declaration',
64
+ risk: 'medium',
65
+ config: {},
66
+ methods: ['share.copyLink', 'share.showShareMenu', 'share.screenshot'],
67
+ conditions: ['继续执行分享参数校验和 Host 支持检查。'],
68
+ },
69
+ {
70
+ key: 'storage',
71
+ name: '键值存储',
72
+ description: '读写按小程序隔离的简单键值数据。',
73
+ access: 'declaration',
74
+ risk: 'medium',
75
+ config: {},
76
+ methods: ['storage.getStorage', 'storage.setStorage'],
77
+ conditions: ['仅用于简单键值存储,不包含文件系统。'],
78
+ },
79
+ {
80
+ key: 'filesystem',
81
+ name: '文件系统',
82
+ description: '访问小程序沙盒文件和用户选择的外部文件。',
83
+ access: 'declaration',
84
+ risk: 'high',
85
+ config: {},
86
+ methods: [
87
+ 'network.download',
88
+ 'files.pickFiles',
89
+ 'files.pickDirectory',
90
+ 'files.saveFile',
91
+ 'file.create',
92
+ 'file.remove',
93
+ 'file.exists',
94
+ 'file.readText',
95
+ 'file.writeText',
96
+ 'file.readBytes',
97
+ 'file.writeBytes',
98
+ 'file.stat',
99
+ 'directory.create',
100
+ 'directory.remove',
101
+ 'directory.exists',
102
+ 'directory.list',
103
+ ],
104
+ conditions: ['外部文件继续要求有效的用户选择、会话句柄和匹配的读写模式。'],
105
+ },
106
+ {
107
+ key: 'clipboard',
108
+ name: '剪贴板',
109
+ description: '向系统剪贴板写入文本。',
110
+ access: 'declaration',
111
+ risk: 'medium',
112
+ config: {},
113
+ methods: ['device.setClipboard'],
114
+ conditions: ['继续执行文本长度和 Host 支持限制。'],
115
+ },
116
+ {
117
+ key: 'leaderboard',
118
+ name: '排行榜',
119
+ description: '读写小程序云排行榜。',
120
+ access: 'declaration',
121
+ risk: 'medium',
122
+ config: {},
123
+ methods: [
124
+ 'cloud.leaderboard.submit',
125
+ 'cloud.leaderboard.getList',
126
+ 'cloud.leaderboard.getCurrentUserEntry',
127
+ 'cloud.leaderboard.deleteCurrentUserEntry',
128
+ 'cloud.leaderboard.getInfo',
129
+ ],
130
+ conditions: ['排行榜必须已创建,用户和资源规则保持不变。'],
131
+ },
132
+ {
133
+ key: 'network',
134
+ name: '网络',
135
+ description: '通过 network 模块请求或下载外部资源。',
136
+ access: 'platform-approval',
137
+ risk: 'high',
138
+ config: {
139
+ useOfficialDomain: {
140
+ type: 'boolean',
141
+ required: false,
142
+ default: false,
143
+ description: '是否申请访问小黑盒官方域名。',
144
+ },
145
+ },
146
+ methods: ['network.request', 'network.download'],
147
+ conditions: ['声明后仍需平台批准,并继续执行网络安全策略。'],
148
+ },
149
+ ] as const satisfies readonly MiniProgramPermissionDefinition[];
150
+
151
+ export const MINI_PROGRAM_NO_DECLARATION_METHODS = [
152
+ 'user.revokeAuthorization',
153
+ 'ui.showToast',
154
+ 'ui.showLoading',
155
+ 'ui.hideLoading',
156
+ 'viewport.getWindowInfo',
157
+ 'viewport.setNavigationBarStyle',
158
+ 'device.vibrate',
159
+ 'navigation.close',
160
+ 'navigation.reload',
161
+ 'navigation.openAppPage',
162
+ ] as const satisfies readonly MiniProgramBridgeMethod[];
163
+
164
+ const PERMISSION_KEY_SET = new Set<string>(MINI_PROGRAM_PERMISSION_KEYS);
165
+
166
+ export function isMiniProgramPermissionKey(key: string): key is MiniProgramPermissionKey {
167
+ return PERMISSION_KEY_SET.has(key);
168
+ }
@@ -1,11 +1,13 @@
1
- const MANAGED_RUNTIME_PERMISSION_KEYS = new Set(['network.request']);
1
+ import { MINI_PROGRAM_PERMISSION_KEYS, type MiniProgramPermissionKey } from './permission-catalog';
2
2
 
3
- export function isManagedMiniProgramRuntimePermissionKey(key: string) {
3
+ const MANAGED_RUNTIME_PERMISSION_KEYS = new Set<string>(MINI_PROGRAM_PERMISSION_KEYS);
4
+
5
+ export function isManagedMiniProgramRuntimePermissionKey(key: string): key is MiniProgramPermissionKey {
4
6
  return MANAGED_RUNTIME_PERMISSION_KEYS.has(key);
5
7
  }
6
8
  export type MiniProgramRuntimePermissionStatus = 'enabled' | 'disabled';
7
9
  export interface MiniProgramRuntimePermissionEntry {
8
- key: string;
10
+ key: MiniProgramPermissionKey;
9
11
  status: MiniProgramRuntimePermissionStatus;
10
12
  config: Record<string, unknown>;
11
13
  }
@@ -16,7 +18,7 @@ export interface MiniProgramRuntimePermissionsSnapshot {
16
18
  }
17
19
  export interface ParsedMiniProgramRuntimePermissions {
18
20
  valid: boolean;
19
- permissions: Record<string, MiniProgramRuntimePermissionEntry>;
21
+ permissions: Partial<Record<MiniProgramPermissionKey, MiniProgramRuntimePermissionEntry>>;
20
22
  }
21
23
 
22
24
  export function parseMiniProgramRuntimePermissions(snapshot: unknown): ParsedMiniProgramRuntimePermissions {
@@ -28,24 +30,40 @@ export function parseMiniProgramRuntimePermissions(snapshot: unknown): ParsedMin
28
30
  }
29
31
 
30
32
  const seenKeys = new Set<string>();
31
- const permissions: Record<string, MiniProgramRuntimePermissionEntry> = {};
33
+ const permissions: Partial<Record<MiniProgramPermissionKey, MiniProgramRuntimePermissionEntry>> = {};
32
34
  for (const rawEntry of snapshot.entries) {
33
35
  if (!isRecord(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
34
36
  return { valid: false, permissions: {} };
35
37
  }
36
- const key = rawEntry.key.trim();
37
- if (seenKeys.has(key) || (rawEntry.status !== 'enabled' && rawEntry.status !== 'disabled') || !isRecord(rawEntry.config)) {
38
+ const inputKey = rawEntry.key.trim();
39
+ const key = inputKey === 'network.request' ? 'network' : inputKey;
40
+ if (seenKeys.has(key) || (rawEntry.status !== 'enabled' && rawEntry.status !== 'disabled')) {
38
41
  return { valid: false, permissions: {} };
39
42
  }
40
43
  seenKeys.add(key);
41
- if (!isManagedMiniProgramRuntimePermissionKey(key)) continue;
42
- if (key === 'network.request' && typeof rawEntry.config.useOfficialDomain !== 'boolean') {
44
+ if (!isManagedMiniProgramRuntimePermissionKey(key)) {
45
+ if (!isRecord(rawEntry.config)) return { valid: false, permissions: {} };
46
+ continue;
47
+ }
48
+ if (key === 'network') {
49
+ const config = rawEntry.config;
50
+ if (!isRecord(config) || typeof config.useOfficialDomain !== 'boolean') {
51
+ return { valid: false, permissions: {} };
52
+ }
53
+ permissions[key] = {
54
+ key,
55
+ status: rawEntry.status,
56
+ config: { useOfficialDomain: config.useOfficialDomain },
57
+ };
58
+ continue;
59
+ }
60
+ if (rawEntry.config !== null && rawEntry.config !== undefined && (!isRecord(rawEntry.config) || Object.keys(rawEntry.config).length > 0)) {
43
61
  return { valid: false, permissions: {} };
44
62
  }
45
63
  permissions[key] = {
46
64
  key,
47
65
  status: rawEntry.status,
48
- config: { useOfficialDomain: rawEntry.config.useOfficialDomain },
66
+ config: {},
49
67
  };
50
68
  }
51
69
  return { valid: true, permissions };
package/types/bridge.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { MINI_PROGRAM_MESSAGE_NAMESPACE } from './constants';
2
- import type { UserInfoAuthorization } from './payloads';
3
- export type MiniProgramBridgeMessageType = 'handshake' | 'request' | 'response' | 'event';
1
+ import { MINI_PROGRAM_MESSAGE_NAMESPACE, MINI_PROGRAM_OPERATION_PROGRESS_METHOD } from './constants';
2
+ import type { DownloadProgressPayload, UserInfoAuthorization } from './payloads';
3
+ export type MiniProgramBridgeMessageType = 'handshake' | 'request' | 'response' | 'event' | 'cancel';
4
4
  export type MiniProgramEventName = 'launch' | 'ready' | 'show' | 'hide' | 'unload' | 'error' | 'heybox_app_login_change' | 'user_info_authorization_change';
5
5
  export interface MiniProgramBridgeError {
6
6
  code: string;
@@ -46,6 +46,22 @@ export interface MiniProgramBridgeMessage<TPayload = unknown> {
46
46
  payload?: TPayload;
47
47
  error?: MiniProgramBridgeError;
48
48
  }
49
+ export interface MiniProgramBridgeCancelMessage extends MiniProgramBridgeMessage<never> {
50
+ version: 2;
51
+ type: 'cancel';
52
+ id: string;
53
+ method?: never;
54
+ payload?: never;
55
+ error?: never;
56
+ }
57
+ export interface MiniProgramBridgeProgressMessage extends MiniProgramBridgeMessage<DownloadProgressPayload> {
58
+ version: 2;
59
+ type: 'event';
60
+ id: string;
61
+ method: typeof MINI_PROGRAM_OPERATION_PROGRESS_METHOD;
62
+ payload: DownloadProgressPayload;
63
+ error?: never;
64
+ }
49
65
  export interface MiniProgramEventPayloadMap {
50
66
  launch: {
51
67
  timestamp: number;