@heybox/hb-sdk-protocol 0.9.1-alpha.1 → 0.9.1-alpha.11

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 DELETED
@@ -1,9 +0,0 @@
1
- export * from './bridge';
2
- export * from './capabilities';
3
- export * from './constants';
4
- export * from './guards';
5
- export * from './local-dev-grant';
6
- export * from './native-host';
7
- export * from './payloads';
8
- export * from './permission-catalog';
9
- export * from './permissions';
@@ -1,141 +0,0 @@
1
- import { MINI_PROGRAM_PERMISSION_KEYS, type MiniProgramPermissionKey } from './permission-catalog';
2
- import { parseMiniProgramRuntimePermissions, type MiniProgramRuntimePermissionsSnapshot } from './permissions';
3
-
4
- /** 仅供开发工具和 Host 使用;新增权限必须单独评估,不能从平台审批目录自动推导。 */
5
- export const LOCAL_DEV_GRANT_PERMISSION_KEYS = ['network', 'companion'] as const;
6
- export type MiniProgramLocalDevPermissionKey = (typeof LOCAL_DEV_GRANT_PERMISSION_KEYS)[number];
7
- export type MiniProgramLocalDevGrantEntry =
8
- | { key: 'network'; status: 'enabled'; config: { useOfficialDomain: false } }
9
- | { key: 'companion'; status: 'enabled'; config: Record<string, never> };
10
-
11
- /** CLI-owned Dev Context 合同,不属于小程序业务 API 或线上批准快照。 */
12
- export interface MiniProgramLocalDevGrant {
13
- schema_version: 1;
14
- revision: number;
15
- entries: MiniProgramLocalDevGrantEntry[];
16
- }
17
-
18
- /** 调用方已校验的本地声明;不存在的权限不会从 grant 获得授权。 */
19
- export type MiniProgramLocalDevPermissionDeclarations = Partial<
20
- Record<MiniProgramPermissionKey, { enabled: boolean; useOfficialDomain?: boolean }>
21
- >;
22
-
23
- export type ParsedMiniProgramLocalDevGrant =
24
- | { valid: true; grant: MiniProgramLocalDevGrant }
25
- | { valid: false; grant?: undefined };
26
-
27
- /**
28
- * 严格解析本地 grant。任何未知字段、重复权限或非法配置都拒绝整份输入。
29
- * 只校验数据合同;票据、身份、摘要、过期时间和 CLI lease 必须由 Host 另行验证。
30
- */
31
- export function parseMiniProgramLocalDevGrant(value: unknown): ParsedMiniProgramLocalDevGrant {
32
- if (
33
- !hasExactFields(value, ['schema_version', 'revision', 'entries']) ||
34
- value.schema_version !== 1 ||
35
- typeof value.revision !== 'number' ||
36
- !Number.isSafeInteger(value.revision) ||
37
- value.revision < 0 ||
38
- !Array.isArray(value.entries) ||
39
- value.entries.length > LOCAL_DEV_GRANT_PERMISSION_KEYS.length
40
- ) return { valid: false };
41
-
42
- const entries: MiniProgramLocalDevGrantEntry[] = [];
43
- const seen = new Set<string>();
44
- for (const entry of value.entries) {
45
- if (!hasExactFields(entry, ['key', 'status', 'config']) || entry.status !== 'enabled') return { valid: false };
46
- if (typeof entry.key !== 'string' || seen.has(entry.key)) return { valid: false };
47
- seen.add(entry.key);
48
- if (entry.key === 'network') {
49
- if (!hasExactFields(entry.config, ['useOfficialDomain']) || entry.config.useOfficialDomain !== false) return { valid: false };
50
- entries.push({ key: 'network', status: 'enabled', config: { useOfficialDomain: false } });
51
- } else if (entry.key === 'companion') {
52
- if (!hasExactFields(entry.config, [])) return { valid: false };
53
- entries.push({ key: 'companion', status: 'enabled', config: {} });
54
- } else {
55
- return { valid: false };
56
- }
57
- }
58
- entries.sort((a, b) => LOCAL_DEV_GRANT_PERMISSION_KEYS.indexOf(a.key) - LOCAL_DEV_GRANT_PERMISSION_KEYS.indexOf(b.key));
59
- return { valid: true, grant: { schema_version: 1, revision: value.revision, entries } };
60
- }
61
-
62
- /**
63
- * 从已校验声明生成批准缺口。Companion 默认不符合资格,由 CLI 确认平台、产物与摘要后显式加入。
64
- * 空 entries 可保留 revision,不能作为存在临时权限的判断依据。
65
- */
66
- export function createMiniProgramLocalDevGrant(options: {
67
- declaredPermissions: MiniProgramLocalDevPermissionDeclarations;
68
- runtimePermissions: unknown;
69
- revision: number;
70
- eligiblePermissionKeys?: readonly MiniProgramLocalDevPermissionKey[];
71
- }): MiniProgramLocalDevGrant {
72
- if (!Number.isSafeInteger(options.revision) || options.revision < 0) throw new Error('本地调试权限 revision 必须是非负安全整数');
73
- const approvals = parseMiniProgramRuntimePermissions(options.runtimePermissions);
74
- const eligible = new Set(options.eligiblePermissionKeys ?? ['network']);
75
- const entries: MiniProgramLocalDevGrantEntry[] = [];
76
- for (const key of LOCAL_DEV_GRANT_PERMISSION_KEYS) {
77
- if (!eligible.has(key) || options.declaredPermissions[key]?.enabled !== true) continue;
78
- if (approvals.valid && approvals.permissions[key]?.status === 'enabled') continue;
79
- entries.push(key === 'network'
80
- ? { key, status: 'enabled', config: { useOfficialDomain: false } }
81
- : { key, status: 'enabled', config: {} });
82
- }
83
- return { schema_version: 1, revision: options.revision, entries };
84
- }
85
-
86
- /**
87
- * 线上基线先与本地声明求交,再补齐临时权限,返回与输入脱离的普通 Runtime 快照。
88
- * 调用方只可在当前 Dev Session 已验证且用户接受后传入 grant;本函数不证明其可信来源。
89
- * 非法 grant 整体降权到基线,已批准配置不会被临时配置覆盖。
90
- */
91
- export function composeLocalDevRuntimePermissions(options: {
92
- declaredPermissions: MiniProgramLocalDevPermissionDeclarations;
93
- runtimePermissions: unknown;
94
- localDevGrant?: unknown;
95
- }): {
96
- runtimePermissions: MiniProgramRuntimePermissionsSnapshot;
97
- temporaryPermissionKeys: MiniProgramLocalDevPermissionKey[];
98
- grantValid: boolean;
99
- } {
100
- const baseline = parseMiniProgramRuntimePermissions(options.runtimePermissions);
101
- const parsed = parseMiniProgramLocalDevGrant(options.localDevGrant);
102
- const permissions = baseline.valid ? baseline.permissions : {};
103
- for (const key of MINI_PROGRAM_PERMISSION_KEYS) {
104
- if (options.declaredPermissions[key]?.enabled !== true) {
105
- delete permissions[key];
106
- } else if (key === 'network' && permissions.network) {
107
- permissions.network.config.useOfficialDomain = permissions.network.status === 'enabled'
108
- && permissions.network.config.useOfficialDomain === true
109
- && options.declaredPermissions.network?.useOfficialDomain === true;
110
- }
111
- }
112
- const temporaryPermissionKeys: MiniProgramLocalDevPermissionKey[] = [];
113
- if (parsed.valid) {
114
- for (const entry of parsed.grant.entries) {
115
- if (options.declaredPermissions[entry.key]?.enabled !== true || permissions[entry.key]?.status === 'enabled') continue;
116
- permissions[entry.key] = entry;
117
- temporaryPermissionKeys.push(entry.key);
118
- }
119
- }
120
- const revision = isRecord(options.runtimePermissions) && typeof options.runtimePermissions.revision === 'number'
121
- && Number.isSafeInteger(options.runtimePermissions.revision) && options.runtimePermissions.revision >= 0
122
- ? options.runtimePermissions.revision : undefined;
123
- return {
124
- runtimePermissions: {
125
- schema_version: 1,
126
- ...(revision === undefined ? {} : { revision }),
127
- entries: MINI_PROGRAM_PERMISSION_KEYS.flatMap((key) => permissions[key] ? [permissions[key]!] : []),
128
- },
129
- temporaryPermissionKeys,
130
- grantValid: parsed.valid,
131
- };
132
- }
133
-
134
- function isRecord(value: unknown): value is Record<string, unknown> {
135
- return typeof value === 'object' && value !== null && !Array.isArray(value);
136
- }
137
-
138
- function hasExactFields(value: unknown, fields: readonly string[]): value is Record<string, unknown> {
139
- return isRecord(value) && Object.keys(value).length === fields.length
140
- && fields.every((field) => Object.prototype.hasOwnProperty.call(value, field));
141
- }
@@ -1,60 +0,0 @@
1
- /** 由 scripts/generate-native-host-contract.mjs 生成,请勿手改。 */
2
- export const MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION = 1 as const;
3
- export const MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION = 1 as const;
4
- export const MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES = 65536 as const;
5
- export const MINI_PROGRAM_NATIVE_OPERATIONS = {
6
- "system": [
7
- "describe"
8
- ],
9
- "network": [
10
- "open",
11
- "read",
12
- "release",
13
- "transfer"
14
- ],
15
- "files": [
16
- "create",
17
- "remove",
18
- "exists",
19
- "openRead",
20
- "openWrite",
21
- "read",
22
- "release",
23
- "write",
24
- "stat",
25
- "list",
26
- "pickFiles",
27
- "pickDirectory",
28
- "saveFile"
29
- ]
30
- } as const;
31
- export const MINI_PROGRAM_NATIVE_HOST_DESCRIPTION = {
32
- "protocolVersion": 1,
33
- "contractRevision": 1,
34
- "operations": {
35
- "system": [
36
- "describe"
37
- ],
38
- "network": [
39
- "open",
40
- "read",
41
- "release",
42
- "transfer"
43
- ],
44
- "files": [
45
- "create",
46
- "remove",
47
- "exists",
48
- "openRead",
49
- "openWrite",
50
- "read",
51
- "release",
52
- "write",
53
- "stat",
54
- "list",
55
- "pickFiles",
56
- "pickDirectory",
57
- "saveFile"
58
- ]
59
- }
60
- } as const;
@@ -1,479 +0,0 @@
1
- {
2
- "schema": "heybox-mini-program-native-host",
3
- "protocolVersion": 1,
4
- "contractRevision": 1,
5
- "chunkMaxBytes": 65536,
6
- "operations": {
7
- "system": [
8
- "describe"
9
- ],
10
- "network": [
11
- "open",
12
- "read",
13
- "release",
14
- "transfer"
15
- ],
16
- "files": [
17
- "create",
18
- "remove",
19
- "exists",
20
- "openRead",
21
- "openWrite",
22
- "read",
23
- "release",
24
- "write",
25
- "stat",
26
- "list",
27
- "pickFiles",
28
- "pickDirectory",
29
- "saveFile"
30
- ]
31
- },
32
- "cases": [
33
- {
34
- "name": "system-describe",
35
- "valid": true,
36
- "request": {
37
- "requestId": "req_describe",
38
- "domain": "system",
39
- "operation": "describe"
40
- },
41
- "messages": [
42
- {
43
- "requestId": "req_describe",
44
- "type": "result",
45
- "payload": {
46
- "protocolVersion": 1,
47
- "contractRevision": 1,
48
- "operations": {
49
- "system": [
50
- "describe"
51
- ],
52
- "network": [
53
- "open",
54
- "read",
55
- "release",
56
- "transfer"
57
- ],
58
- "files": [
59
- "create",
60
- "remove",
61
- "exists",
62
- "openRead",
63
- "openWrite",
64
- "read",
65
- "release",
66
- "write",
67
- "stat",
68
- "list",
69
- "pickFiles",
70
- "pickDirectory",
71
- "saveFile"
72
- ]
73
- }
74
- }
75
- }
76
- ]
77
- },
78
- {
79
- "name": "network-open",
80
- "valid": true,
81
- "request": {
82
- "requestId": "req_open",
83
- "domain": "network",
84
- "operation": "open",
85
- "payload": {
86
- "purpose": "download",
87
- "url": "https://cdn.example.test/file.zip",
88
- "method": "GET",
89
- "timeoutMs": 30000
90
- }
91
- },
92
- "messages": [
93
- {
94
- "requestId": "req_open",
95
- "type": "result",
96
- "payload": {
97
- "status": 200,
98
- "statusText": "OK",
99
- "headers": {
100
- "content-length": [
101
- "4"
102
- ]
103
- },
104
- "resourceId": "resource_1"
105
- }
106
- }
107
- ]
108
- },
109
- {
110
- "name": "network-read-chunk",
111
- "valid": true,
112
- "request": {
113
- "requestId": "req_read",
114
- "domain": "network",
115
- "operation": "read",
116
- "payload": {
117
- "resourceId": "resource_1",
118
- "maxBytes": 65536
119
- }
120
- },
121
- "messages": [
122
- {
123
- "requestId": "req_read",
124
- "type": "result",
125
- "payload": {
126
- "resourceId": "resource_1",
127
- "data": "dGVzdA==",
128
- "byteLength": 4,
129
- "eof": true
130
- }
131
- }
132
- ]
133
- },
134
- {
135
- "name": "network-transfer-progress",
136
- "valid": true,
137
- "request": {
138
- "requestId": "req_transfer",
139
- "domain": "network",
140
- "operation": "transfer",
141
- "payload": {
142
- "resourceId": "resource_1",
143
- "target": {
144
- "scope": "sandbox",
145
- "kind": "file",
146
- "relativePath": "downloads/file.zip"
147
- },
148
- "mode": "upsert",
149
- "maxBytes": 2147483648,
150
- "expectedBytes": 4
151
- }
152
- },
153
- "messages": [
154
- {
155
- "requestId": "req_transfer",
156
- "type": "progress",
157
- "payload": {
158
- "resourceId": "resource_1",
159
- "loaded": 4
160
- }
161
- },
162
- {
163
- "requestId": "req_transfer",
164
- "type": "result",
165
- "payload": {
166
- "committedBytes": 4
167
- }
168
- }
169
- ]
170
- },
171
- {
172
- "name": "files-open-read",
173
- "valid": true,
174
- "request": {
175
- "requestId": "req_file_open",
176
- "domain": "files",
177
- "operation": "openRead",
178
- "payload": {
179
- "ref": {
180
- "scope": "sandbox",
181
- "kind": "file",
182
- "relativePath": "data.bin"
183
- },
184
- "maxBytes": 8388608
185
- }
186
- },
187
- "messages": [
188
- {
189
- "requestId": "req_file_open",
190
- "type": "result",
191
- "payload": {
192
- "resourceId": "file_resource_1"
193
- }
194
- }
195
- ]
196
- },
197
- {
198
- "name": "files-create",
199
- "valid": true,
200
- "request": {
201
- "requestId": "req_create",
202
- "domain": "files",
203
- "operation": "create",
204
- "payload": {
205
- "ref": {
206
- "scope": "sandbox",
207
- "kind": "file",
208
- "relativePath": "data.bin"
209
- },
210
- "recursive": false,
211
- "exclusive": true
212
- }
213
- },
214
- "messages": [
215
- {
216
- "requestId": "req_create",
217
- "type": "result"
218
- }
219
- ]
220
- },
221
- {
222
- "name": "files-open-write",
223
- "valid": true,
224
- "request": {
225
- "requestId": "req_write_open",
226
- "domain": "files",
227
- "operation": "openWrite",
228
- "payload": {
229
- "ref": {
230
- "scope": "sandbox",
231
- "kind": "file",
232
- "relativePath": "data.bin"
233
- },
234
- "maxBytes": 8388608
235
- }
236
- },
237
- "messages": [
238
- {
239
- "requestId": "req_write_open",
240
- "type": "result",
241
- "payload": {
242
- "resourceId": "file_write_1"
243
- }
244
- }
245
- ]
246
- },
247
- {
248
- "name": "files-write-chunk",
249
- "valid": true,
250
- "request": {
251
- "requestId": "req_write",
252
- "domain": "files",
253
- "operation": "write",
254
- "payload": {
255
- "resourceId": "file_write_1",
256
- "data": "AAE=",
257
- "byteLength": 2,
258
- "eof": true
259
- }
260
- },
261
- "messages": [
262
- {
263
- "requestId": "req_write",
264
- "type": "result"
265
- }
266
- ]
267
- },
268
- {
269
- "name": "files-list",
270
- "valid": true,
271
- "request": {
272
- "requestId": "req_list",
273
- "domain": "files",
274
- "operation": "list",
275
- "payload": {
276
- "ref": {
277
- "scope": "sandbox",
278
- "kind": "directory",
279
- "relativePath": ""
280
- },
281
- "limit": 1000
282
- }
283
- },
284
- "messages": [
285
- {
286
- "requestId": "req_list",
287
- "type": "result",
288
- "payload": [
289
- {
290
- "kind": "file",
291
- "mode": "readwrite",
292
- "name": "data.bin",
293
- "ref": {
294
- "scope": "sandbox",
295
- "kind": "file",
296
- "relativePath": "data.bin"
297
- }
298
- }
299
- ]
300
- }
301
- ]
302
- },
303
- {
304
- "name": "files-read-chunk",
305
- "valid": true,
306
- "request": {
307
- "requestId": "req_file_read",
308
- "domain": "files",
309
- "operation": "read",
310
- "payload": {
311
- "resourceId": "file_resource_1",
312
- "maxBytes": 65536
313
- }
314
- },
315
- "messages": [
316
- {
317
- "requestId": "req_file_read",
318
- "type": "result",
319
- "payload": {
320
- "resourceId": "file_resource_1",
321
- "data": "AAE=",
322
- "byteLength": 2,
323
- "eof": true
324
- }
325
- }
326
- ]
327
- },
328
- {
329
- "name": "cancel-race",
330
- "valid": true,
331
- "request": {
332
- "requestId": "req_cancel",
333
- "domain": "network",
334
- "operation": "open",
335
- "payload": {
336
- "purpose": "request",
337
- "url": "https://api.example.test/data",
338
- "method": "GET",
339
- "timeoutMs": 30000
340
- }
341
- },
342
- "cancel": {
343
- "type": "cancel",
344
- "requestId": "req_cancel"
345
- },
346
- "messages": [
347
- {
348
- "requestId": "req_cancel",
349
- "type": "error",
350
- "error": {
351
- "code": "REQUEST_FAILED",
352
- "message": "请求已取消"
353
- }
354
- }
355
- ]
356
- },
357
- {
358
- "name": "unsupported-operation",
359
- "valid": true,
360
- "request": {
361
- "requestId": "req_missing",
362
- "domain": "files",
363
- "operation": "unknown"
364
- },
365
- "messages": [
366
- {
367
- "requestId": "req_missing",
368
- "type": "error",
369
- "error": {
370
- "code": "METHOD_FORBIDDEN",
371
- "message": "当前客户端不支持该能力"
372
- }
373
- }
374
- ]
375
- },
376
- {
377
- "name": "invalid-shape",
378
- "valid": false,
379
- "request": {
380
- "requestId": "",
381
- "domain": "network",
382
- "operation": "open"
383
- }
384
- },
385
- {
386
- "name": "oversized-chunk",
387
- "valid": false,
388
- "message": {
389
- "requestId": "req_big",
390
- "type": "result",
391
- "payload": {
392
- "resourceId": "resource_1",
393
- "data": "",
394
- "byteLength": 65537,
395
- "eof": false
396
- }
397
- }
398
- },
399
- {
400
- "name": "zero-nonterminal-chunk",
401
- "valid": false,
402
- "message": {
403
- "requestId": "req_zero",
404
- "type": "result",
405
- "payload": {
406
- "resourceId": "resource_1",
407
- "data": "",
408
- "byteLength": 0,
409
- "eof": false
410
- }
411
- }
412
- },
413
- {
414
- "name": "duplicate-terminal",
415
- "valid": false,
416
- "messages": [
417
- {
418
- "requestId": "req_dup",
419
- "type": "result"
420
- },
421
- {
422
- "requestId": "req_dup",
423
- "type": "error",
424
- "error": {
425
- "code": "REQUEST_FAILED",
426
- "message": "重复终态"
427
- }
428
- }
429
- ]
430
- },
431
- {
432
- "name": "late-progress",
433
- "valid": false,
434
- "messages": [
435
- {
436
- "requestId": "req_late",
437
- "type": "result"
438
- },
439
- {
440
- "requestId": "req_late",
441
- "type": "progress",
442
- "payload": {
443
- "resourceId": "resource_1",
444
- "loaded": 1
445
- }
446
- }
447
- ]
448
- },
449
- {
450
- "name": "cross-session-handle",
451
- "valid": false,
452
- "request": {
453
- "requestId": "req_cross",
454
- "domain": "files",
455
- "operation": "stat",
456
- "payload": {
457
- "ref": {
458
- "scope": "grant",
459
- "id": "other_session_handle",
460
- "kind": "file",
461
- "relativePath": ""
462
- }
463
- }
464
- }
465
- },
466
- {
467
- "name": "redacted-error",
468
- "valid": true,
469
- "message": {
470
- "requestId": "req_error",
471
- "type": "error",
472
- "error": {
473
- "code": "FILE_ACCESS_DENIED",
474
- "message": "文件访问被拒绝"
475
- }
476
- }
477
- }
478
- ]
479
- }