@heybox/hb-sdk-protocol 0.8.3-alpha.2 → 0.8.3-alpha.4
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 +20 -0
- package/dist/index.cjs.js +287 -163
- package/dist/index.esm.js +283 -164
- package/generated/permission-catalog.json +2 -1
- package/package.json +1 -1
- package/src/bridge.ts +8 -0
- package/src/capabilities.ts +13 -0
- package/src/index.ts +1 -0
- package/src/local-dev-grant.ts +141 -0
- package/src/payloads.ts +21 -0
- package/src/permission-catalog.ts +1 -0
- package/types/bridge.d.ts +7 -1
- package/types/capabilities.d.ts +13 -2
- package/types/index.d.ts +1 -0
- package/types/local-dev-grant.d.ts +63 -0
- package/types/payloads.d.ts +20 -0
- package/types/permission-catalog.d.ts +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -39,6 +39,7 @@ const USER_GET_STEAM_GAME_LIST_METHOD = 'user.getSteamGameList';
|
|
|
39
39
|
const SHARE_COPY_LINK_METHOD = 'share.copyLink';
|
|
40
40
|
const SHARE_SHOW_SHARE_MENU_METHOD = 'share.showShareMenu';
|
|
41
41
|
const SHARE_SCREENSHOT_METHOD = 'share.screenshot';
|
|
42
|
+
const VIEWPORT_SET_DISPLAY_METHOD = 'viewport.setDisplay';
|
|
42
43
|
const VIEWPORT_GET_WINDOW_INFO_METHOD = 'viewport.getWindowInfo';
|
|
43
44
|
const VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD = 'viewport.setNavigationBarStyle';
|
|
44
45
|
const STORAGE_GET_STORAGE_METHOD = 'storage.getStorage';
|
|
@@ -162,6 +163,13 @@ const MINI_PROGRAM_PROTOCOL_CAPABILITIES = [
|
|
|
162
163
|
requirement: { kind: 'none' },
|
|
163
164
|
risk: 'low',
|
|
164
165
|
},
|
|
166
|
+
{
|
|
167
|
+
method: VIEWPORT_SET_DISPLAY_METHOD,
|
|
168
|
+
module: 'viewport',
|
|
169
|
+
capability: VIEWPORT_SET_DISPLAY_METHOD,
|
|
170
|
+
requirement: { kind: 'none' },
|
|
171
|
+
risk: 'low',
|
|
172
|
+
},
|
|
165
173
|
{
|
|
166
174
|
method: STORAGE_GET_STORAGE_METHOD,
|
|
167
175
|
module: 'storage',
|
|
@@ -437,7 +445,7 @@ const MINI_PROGRAM_PROTOCOL_CAPABILITIES = [
|
|
|
437
445
|
* @see [parseMiniProgramRuntimePermissions](/reference/symbols/protocol/functions/parseMiniProgramRuntimePermissions) Runtime 权限快照解析器。
|
|
438
446
|
*/
|
|
439
447
|
function isMiniProgramBridgeMessage(value) {
|
|
440
|
-
if (!isRecord$
|
|
448
|
+
if (!isRecord$3(value))
|
|
441
449
|
return false;
|
|
442
450
|
if (value.namespace !== MINI_PROGRAM_MESSAGE_NAMESPACE || (value.version !== 1 && value.version !== 2) || !isNonEmptyString$1(value.nonce)) {
|
|
443
451
|
return false;
|
|
@@ -587,7 +595,7 @@ function isMiniProgramRelativePath(value) {
|
|
|
587
595
|
* @see [DirectoryHandle](/reference/symbols/root/interfaces/DirectoryHandle) 可作为 derived path root 的目录代理。
|
|
588
596
|
*/
|
|
589
597
|
function isMiniProgramPathRootRef(value) {
|
|
590
|
-
if (!isRecord$
|
|
598
|
+
if (!isRecord$3(value))
|
|
591
599
|
return false;
|
|
592
600
|
if (value.kind === 'sandbox')
|
|
593
601
|
return hasOnlyKeys(value, ['kind']);
|
|
@@ -653,7 +661,7 @@ function isMiniProgramPathRootRef(value) {
|
|
|
653
661
|
* @see [FileHandle](/reference/symbols/root/interfaces/FileHandle) 使用文件引用的公开 I/O 代理。
|
|
654
662
|
*/
|
|
655
663
|
function isMiniProgramFileRef(value) {
|
|
656
|
-
if (!isRecord$
|
|
664
|
+
if (!isRecord$3(value) || value.kind !== 'file')
|
|
657
665
|
return false;
|
|
658
666
|
if (isNonEmptyString$1(value.handleId)) {
|
|
659
667
|
return hasOnlyKeys(value, ['kind', 'handleId']);
|
|
@@ -720,7 +728,7 @@ function isMiniProgramFileRef(value) {
|
|
|
720
728
|
* @see [DirectoryHandle](/reference/symbols/root/interfaces/DirectoryHandle) 使用目录引用的公开路径操作代理。
|
|
721
729
|
*/
|
|
722
730
|
function isMiniProgramDirectoryRef(value) {
|
|
723
|
-
if (!isRecord$
|
|
731
|
+
if (!isRecord$3(value) || value.kind !== 'directory')
|
|
724
732
|
return false;
|
|
725
733
|
if (isNonEmptyString$1(value.handleId)) {
|
|
726
734
|
return hasOnlyKeys(value, ['kind', 'handleId']);
|
|
@@ -794,7 +802,7 @@ function isMiniProgramDirectoryRef(value) {
|
|
|
794
802
|
* @see [SaveFileResult](/reference/symbols/protocol/types/SaveFileResult) save picker 的 direct-ref 文件结果。
|
|
795
803
|
*/
|
|
796
804
|
function isMiniProgramFileDescriptor(value) {
|
|
797
|
-
return (isRecord$
|
|
805
|
+
return (isRecord$3(value) &&
|
|
798
806
|
value.kind === 'file' &&
|
|
799
807
|
isNonEmptyString$1(value.name) &&
|
|
800
808
|
isFileMode(value.mode) &&
|
|
@@ -864,7 +872,7 @@ function isMiniProgramFileDescriptor(value) {
|
|
|
864
872
|
* @see [PickDirectoryResult](/reference/symbols/protocol/types/PickDirectoryResult) picker 的 direct-ref 返回契约。
|
|
865
873
|
*/
|
|
866
874
|
function isMiniProgramDirectoryDescriptor(value) {
|
|
867
|
-
return (isRecord$
|
|
875
|
+
return (isRecord$3(value) &&
|
|
868
876
|
value.kind === 'directory' &&
|
|
869
877
|
isNonEmptyString$1(value.name) &&
|
|
870
878
|
isFileMode(value.mode) &&
|
|
@@ -1043,7 +1051,7 @@ function isMiniProgramByteArray(value) {
|
|
|
1043
1051
|
* @see [FileHandle](/reference/symbols/root/interfaces/FileHandle) 提供 `stat()` 的当前 session 文件代理。
|
|
1044
1052
|
*/
|
|
1045
1053
|
function isMiniProgramFileStat(value) {
|
|
1046
|
-
return (isRecord$
|
|
1054
|
+
return (isRecord$3(value) &&
|
|
1047
1055
|
value.kind === 'file' &&
|
|
1048
1056
|
isNonNegativeSafeInteger(value.size) &&
|
|
1049
1057
|
(value.modifiedAt === undefined || isNonNegativeFiniteNumber(value.modifiedAt)) &&
|
|
@@ -1103,7 +1111,7 @@ function isMiniProgramFileStat(value) {
|
|
|
1103
1111
|
* @see [isMiniProgramBridgeMessage](/reference/symbols/protocol/functions/isMiniProgramBridgeMessage) operation progress envelope 的最低校验。
|
|
1104
1112
|
*/
|
|
1105
1113
|
function isMiniProgramDownloadProgressPayload(value) {
|
|
1106
|
-
if (!isRecord$
|
|
1114
|
+
if (!isRecord$3(value) ||
|
|
1107
1115
|
!isNonNegativeSafeInteger(value.loaded) ||
|
|
1108
1116
|
typeof value.lengthComputable !== 'boolean' ||
|
|
1109
1117
|
!hasOnlyKeys(value, ['loaded', 'total', 'lengthComputable'])) {
|
|
@@ -1114,7 +1122,7 @@ function isMiniProgramDownloadProgressPayload(value) {
|
|
|
1114
1122
|
return isNonNegativeSafeInteger(value.total) && value.loaded <= value.total;
|
|
1115
1123
|
}
|
|
1116
1124
|
function isMiniProgramCompanionPrepareProgress(value) {
|
|
1117
|
-
if (!isRecord$
|
|
1125
|
+
if (!isRecord$3(value))
|
|
1118
1126
|
return false;
|
|
1119
1127
|
if (value.phase === 'downloading') {
|
|
1120
1128
|
return (isNonNegativeSafeInteger(value.loaded) &&
|
|
@@ -1132,10 +1140,10 @@ function isMiniProgramOperationProgressPayload(value) {
|
|
|
1132
1140
|
return isMiniProgramDownloadProgressPayload(value) || isMiniProgramCompanionPrepareProgress(value);
|
|
1133
1141
|
}
|
|
1134
1142
|
function isSDKHandshakePayload(value) {
|
|
1135
|
-
return isRecord$
|
|
1143
|
+
return isRecord$3(value) && isNonEmptyString$1(value.href) && typeof value.userAgent === 'string' && isNonEmptyString$1(value.sdkVersion);
|
|
1136
1144
|
}
|
|
1137
1145
|
function isBridgeError(value) {
|
|
1138
|
-
return isRecord$
|
|
1146
|
+
return isRecord$3(value) && isNonEmptyString$1(value.code) && typeof value.message === 'string';
|
|
1139
1147
|
}
|
|
1140
1148
|
function isFileMode(value) {
|
|
1141
1149
|
return value === 'read' || value === 'readwrite';
|
|
@@ -1153,156 +1161,10 @@ function hasOnlyKeys(value, allowedKeys) {
|
|
|
1153
1161
|
const allowed = new Set(allowedKeys);
|
|
1154
1162
|
return Object.keys(value).every((key) => allowed.has(key));
|
|
1155
1163
|
}
|
|
1156
|
-
function isRecord$
|
|
1164
|
+
function isRecord$3(value) {
|
|
1157
1165
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
1158
1166
|
}
|
|
1159
1167
|
|
|
1160
|
-
/** 由 scripts/generate-native-host-contract.mjs 生成,请勿手改。 */
|
|
1161
|
-
const MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION = 1;
|
|
1162
|
-
const MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION = 1;
|
|
1163
|
-
const MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES = 65536;
|
|
1164
|
-
const MINI_PROGRAM_NATIVE_OPERATIONS = {
|
|
1165
|
-
"system": [
|
|
1166
|
-
"describe"
|
|
1167
|
-
],
|
|
1168
|
-
"network": [
|
|
1169
|
-
"open",
|
|
1170
|
-
"read",
|
|
1171
|
-
"release",
|
|
1172
|
-
"transfer"
|
|
1173
|
-
],
|
|
1174
|
-
"files": [
|
|
1175
|
-
"create",
|
|
1176
|
-
"remove",
|
|
1177
|
-
"exists",
|
|
1178
|
-
"openRead",
|
|
1179
|
-
"openWrite",
|
|
1180
|
-
"read",
|
|
1181
|
-
"release",
|
|
1182
|
-
"write",
|
|
1183
|
-
"stat",
|
|
1184
|
-
"list",
|
|
1185
|
-
"pickFiles",
|
|
1186
|
-
"pickDirectory",
|
|
1187
|
-
"saveFile"
|
|
1188
|
-
]
|
|
1189
|
-
};
|
|
1190
|
-
const MINI_PROGRAM_NATIVE_HOST_DESCRIPTION = {
|
|
1191
|
-
"protocolVersion": 1,
|
|
1192
|
-
"contractRevision": 1,
|
|
1193
|
-
"operations": {
|
|
1194
|
-
"system": [
|
|
1195
|
-
"describe"
|
|
1196
|
-
],
|
|
1197
|
-
"network": [
|
|
1198
|
-
"open",
|
|
1199
|
-
"read",
|
|
1200
|
-
"release",
|
|
1201
|
-
"transfer"
|
|
1202
|
-
],
|
|
1203
|
-
"files": [
|
|
1204
|
-
"create",
|
|
1205
|
-
"remove",
|
|
1206
|
-
"exists",
|
|
1207
|
-
"openRead",
|
|
1208
|
-
"openWrite",
|
|
1209
|
-
"read",
|
|
1210
|
-
"release",
|
|
1211
|
-
"write",
|
|
1212
|
-
"stat",
|
|
1213
|
-
"list",
|
|
1214
|
-
"pickFiles",
|
|
1215
|
-
"pickDirectory",
|
|
1216
|
-
"saveFile"
|
|
1217
|
-
]
|
|
1218
|
-
}
|
|
1219
|
-
};
|
|
1220
|
-
|
|
1221
|
-
/** Android WebMessageListener object 与 iOS WKScriptMessageHandler 共用名称。 */
|
|
1222
|
-
const MINI_PROGRAM_NATIVE_HOST_OBJECT = 'hbMiniProgramHost';
|
|
1223
|
-
/** Native 通过主文档 CustomEvent 回送 progress/result/error。 */
|
|
1224
|
-
const MINI_PROGRAM_NATIVE_HOST_MESSAGE_EVENT = 'heybox:miniprogram-native-host-message';
|
|
1225
|
-
function isMiniProgramNativeHostMessage(value) {
|
|
1226
|
-
if (!isRecord$1(value) || !isNonEmptyString(value.requestId))
|
|
1227
|
-
return false;
|
|
1228
|
-
if (value.type === 'progress')
|
|
1229
|
-
return Object.prototype.hasOwnProperty.call(value, 'payload');
|
|
1230
|
-
if (value.type === 'result')
|
|
1231
|
-
return !Object.prototype.hasOwnProperty.call(value, 'error');
|
|
1232
|
-
if (value.type !== 'error' || !isRecord$1(value.error))
|
|
1233
|
-
return false;
|
|
1234
|
-
return isNonEmptyString(value.error.code) && isNonEmptyString(value.error.message);
|
|
1235
|
-
}
|
|
1236
|
-
function isMiniProgramNativeHostDescription(value) {
|
|
1237
|
-
if (!isRecord$1(value) ||
|
|
1238
|
-
!isPositiveSafeInteger(value.protocolVersion) ||
|
|
1239
|
-
!isPositiveSafeInteger(value.contractRevision) ||
|
|
1240
|
-
!isRecord$1(value.operations))
|
|
1241
|
-
return false;
|
|
1242
|
-
const operations = value.operations;
|
|
1243
|
-
if (!isOperationList(operations.system) ||
|
|
1244
|
-
!isOperationList(operations.network) ||
|
|
1245
|
-
!isOperationList(operations.files))
|
|
1246
|
-
return false;
|
|
1247
|
-
return operations.system.includes('describe');
|
|
1248
|
-
}
|
|
1249
|
-
function isMiniProgramNativeBinaryChunk(value) {
|
|
1250
|
-
return (isRecord$1(value) &&
|
|
1251
|
-
isNonEmptyString(value.resourceId) &&
|
|
1252
|
-
typeof value.data === 'string' &&
|
|
1253
|
-
Number.isSafeInteger(value.byteLength) &&
|
|
1254
|
-
Number(value.byteLength) >= 0 &&
|
|
1255
|
-
Number(value.byteLength) <= MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES &&
|
|
1256
|
-
typeof value.eof === 'boolean' &&
|
|
1257
|
-
(Number(value.byteLength) > 0 || value.eof));
|
|
1258
|
-
}
|
|
1259
|
-
function isRecord$1(value) {
|
|
1260
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
1261
|
-
}
|
|
1262
|
-
function isNonEmptyString(value) {
|
|
1263
|
-
return typeof value === 'string' && value.length > 0;
|
|
1264
|
-
}
|
|
1265
|
-
function isPositiveSafeInteger(value) {
|
|
1266
|
-
return Number.isSafeInteger(value) && Number(value) > 0;
|
|
1267
|
-
}
|
|
1268
|
-
function isOperationList(value) {
|
|
1269
|
-
return (Array.isArray(value) &&
|
|
1270
|
-
value.every(operation => isNonEmptyString(operation) && operation === operation.trim()) &&
|
|
1271
|
-
new Set(value).size === value.length);
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
/** 当前用户信息与登录能力支持的完整 scope 目录(canonical 顺序)。 */
|
|
1275
|
-
const USER_INFO_AUTHORIZATION_SCOPES = ['identity', 'profile', 'steam_account'];
|
|
1276
|
-
/** Companion alias 的跨构建、Runtime 与 Host 规范。 */
|
|
1277
|
-
const COMPANION_ALIAS_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
|
|
1278
|
-
/** Companion Host 可跨 bridge 保留的稳定领域错误码。 */
|
|
1279
|
-
const COMPANION_ERROR_CODES = [
|
|
1280
|
-
'COMPANION_UNSUPPORTED',
|
|
1281
|
-
'COMPANION_PREVIEW_UNSUPPORTED',
|
|
1282
|
-
'COMPANION_NOT_DECLARED',
|
|
1283
|
-
'COMPANION_TARGET_UNSUPPORTED',
|
|
1284
|
-
'COMPANION_NOT_PREPARED',
|
|
1285
|
-
'COMPANION_PREPARATION_CANCELLED',
|
|
1286
|
-
'COMPANION_DOWNLOAD_FAILED',
|
|
1287
|
-
'COMPANION_DESCRIPTOR_UNAVAILABLE',
|
|
1288
|
-
'COMPANION_ARCHIVE_INVALID',
|
|
1289
|
-
'COMPANION_INTEGRITY_FAILED',
|
|
1290
|
-
'COMPANION_ENTRYPOINT_INVALID',
|
|
1291
|
-
'COMPANION_USER_CANCELLED',
|
|
1292
|
-
'COMPANION_ELEVATION_DENIED',
|
|
1293
|
-
'COMPANION_OS_BLOCKED',
|
|
1294
|
-
'COMPANION_LAUNCH_FAILED',
|
|
1295
|
-
'COMPANION_SESSION_VERSION_MISMATCH',
|
|
1296
|
-
'COMPANION_SESSION_OWNERSHIP_LOST',
|
|
1297
|
-
'COMPANION_SESSION_EXITED',
|
|
1298
|
-
'COMPANION_PIPE_CLOSED',
|
|
1299
|
-
'COMPANION_OUTPUT_LIMIT',
|
|
1300
|
-
'COMPANION_PROCESS_CRASHED',
|
|
1301
|
-
'COMPANION_ATTACHMENT_NOT_FOUND',
|
|
1302
|
-
'COMPANION_NOTIFICATION_UNAVAILABLE',
|
|
1303
|
-
'COMPANION_TERMINATE_FAILED',
|
|
1304
|
-
];
|
|
1305
|
-
|
|
1306
1168
|
const MINI_PROGRAM_PERMISSION_KEYS = [
|
|
1307
1169
|
'userInfo',
|
|
1308
1170
|
'steamLibrary',
|
|
@@ -1456,6 +1318,7 @@ const MINI_PROGRAM_NO_DECLARATION_METHODS = [
|
|
|
1456
1318
|
'ui.hideLoading',
|
|
1457
1319
|
'viewport.getWindowInfo',
|
|
1458
1320
|
'viewport.setNavigationBarStyle',
|
|
1321
|
+
'viewport.setDisplay',
|
|
1459
1322
|
'device.vibrate',
|
|
1460
1323
|
'navigation.close',
|
|
1461
1324
|
'navigation.reload',
|
|
@@ -1596,7 +1459,7 @@ function isManagedMiniProgramRuntimePermissionKey(key) {
|
|
|
1596
1459
|
* @see {@link https://docs.xiaoheihe.cn/hb_sdk/guide/permissions | 权限声明}
|
|
1597
1460
|
*/
|
|
1598
1461
|
function parseMiniProgramRuntimePermissions(snapshot) {
|
|
1599
|
-
if (!isRecord(snapshot) || snapshot.schema_version !== 1 || !Array.isArray(snapshot.entries)) {
|
|
1462
|
+
if (!isRecord$2(snapshot) || snapshot.schema_version !== 1 || !Array.isArray(snapshot.entries)) {
|
|
1600
1463
|
return { valid: false, permissions: {} };
|
|
1601
1464
|
}
|
|
1602
1465
|
if (snapshot.revision !== undefined && (typeof snapshot.revision !== 'number' || !Number.isInteger(snapshot.revision) || snapshot.revision < 0)) {
|
|
@@ -1605,7 +1468,7 @@ function parseMiniProgramRuntimePermissions(snapshot) {
|
|
|
1605
1468
|
const seenKeys = new Set();
|
|
1606
1469
|
const permissions = {};
|
|
1607
1470
|
for (const rawEntry of snapshot.entries) {
|
|
1608
|
-
if (!isRecord(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
|
|
1471
|
+
if (!isRecord$2(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
|
|
1609
1472
|
return { valid: false, permissions: {} };
|
|
1610
1473
|
}
|
|
1611
1474
|
const inputKey = rawEntry.key.trim();
|
|
@@ -1621,7 +1484,7 @@ function parseMiniProgramRuntimePermissions(snapshot) {
|
|
|
1621
1484
|
}
|
|
1622
1485
|
if (key === 'network') {
|
|
1623
1486
|
const config = rawEntry.config;
|
|
1624
|
-
if (!isRecord(config) || typeof config.useOfficialDomain !== 'boolean') {
|
|
1487
|
+
if (!isRecord$2(config) || typeof config.useOfficialDomain !== 'boolean') {
|
|
1625
1488
|
return { valid: false, permissions: {} };
|
|
1626
1489
|
}
|
|
1627
1490
|
permissions[key] = {
|
|
@@ -1631,7 +1494,7 @@ function parseMiniProgramRuntimePermissions(snapshot) {
|
|
|
1631
1494
|
};
|
|
1632
1495
|
continue;
|
|
1633
1496
|
}
|
|
1634
|
-
if (rawEntry.config !== null && rawEntry.config !== undefined && (!isRecord(rawEntry.config) || Object.keys(rawEntry.config).length > 0)) {
|
|
1497
|
+
if (rawEntry.config !== null && rawEntry.config !== undefined && (!isRecord$2(rawEntry.config) || Object.keys(rawEntry.config).length > 0)) {
|
|
1635
1498
|
return { valid: false, permissions: {} };
|
|
1636
1499
|
}
|
|
1637
1500
|
permissions[key] = {
|
|
@@ -1642,8 +1505,264 @@ function parseMiniProgramRuntimePermissions(snapshot) {
|
|
|
1642
1505
|
}
|
|
1643
1506
|
return { valid: true, permissions };
|
|
1644
1507
|
}
|
|
1645
|
-
function isRecord(value) {
|
|
1508
|
+
function isRecord$2(value) {
|
|
1646
1509
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
1647
1510
|
}
|
|
1648
1511
|
|
|
1649
|
-
|
|
1512
|
+
/** 仅供开发工具和 Host 使用;新增权限必须单独评估,不能从平台审批目录自动推导。 */
|
|
1513
|
+
const LOCAL_DEV_GRANT_PERMISSION_KEYS = ['network', 'companion'];
|
|
1514
|
+
/**
|
|
1515
|
+
* 严格解析本地 grant。任何未知字段、重复权限或非法配置都拒绝整份输入。
|
|
1516
|
+
* 只校验数据合同;票据、身份、摘要、过期时间和 CLI lease 必须由 Host 另行验证。
|
|
1517
|
+
*/
|
|
1518
|
+
function parseMiniProgramLocalDevGrant(value) {
|
|
1519
|
+
if (!hasExactFields(value, ['schema_version', 'revision', 'entries']) ||
|
|
1520
|
+
value.schema_version !== 1 ||
|
|
1521
|
+
typeof value.revision !== 'number' ||
|
|
1522
|
+
!Number.isSafeInteger(value.revision) ||
|
|
1523
|
+
value.revision < 0 ||
|
|
1524
|
+
!Array.isArray(value.entries) ||
|
|
1525
|
+
value.entries.length > LOCAL_DEV_GRANT_PERMISSION_KEYS.length)
|
|
1526
|
+
return { valid: false };
|
|
1527
|
+
const entries = [];
|
|
1528
|
+
const seen = new Set();
|
|
1529
|
+
for (const entry of value.entries) {
|
|
1530
|
+
if (!hasExactFields(entry, ['key', 'status', 'config']) || entry.status !== 'enabled')
|
|
1531
|
+
return { valid: false };
|
|
1532
|
+
if (typeof entry.key !== 'string' || seen.has(entry.key))
|
|
1533
|
+
return { valid: false };
|
|
1534
|
+
seen.add(entry.key);
|
|
1535
|
+
if (entry.key === 'network') {
|
|
1536
|
+
if (!hasExactFields(entry.config, ['useOfficialDomain']) || entry.config.useOfficialDomain !== false)
|
|
1537
|
+
return { valid: false };
|
|
1538
|
+
entries.push({ key: 'network', status: 'enabled', config: { useOfficialDomain: false } });
|
|
1539
|
+
}
|
|
1540
|
+
else if (entry.key === 'companion') {
|
|
1541
|
+
if (!hasExactFields(entry.config, []))
|
|
1542
|
+
return { valid: false };
|
|
1543
|
+
entries.push({ key: 'companion', status: 'enabled', config: {} });
|
|
1544
|
+
}
|
|
1545
|
+
else {
|
|
1546
|
+
return { valid: false };
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
entries.sort((a, b) => LOCAL_DEV_GRANT_PERMISSION_KEYS.indexOf(a.key) - LOCAL_DEV_GRANT_PERMISSION_KEYS.indexOf(b.key));
|
|
1550
|
+
return { valid: true, grant: { schema_version: 1, revision: value.revision, entries } };
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* 从已校验声明生成批准缺口。Companion 默认不符合资格,由 CLI 确认平台、产物与摘要后显式加入。
|
|
1554
|
+
* 空 entries 可保留 revision,不能作为存在临时权限的判断依据。
|
|
1555
|
+
*/
|
|
1556
|
+
function createMiniProgramLocalDevGrant(options) {
|
|
1557
|
+
if (!Number.isSafeInteger(options.revision) || options.revision < 0)
|
|
1558
|
+
throw new Error('本地调试权限 revision 必须是非负安全整数');
|
|
1559
|
+
const approvals = parseMiniProgramRuntimePermissions(options.runtimePermissions);
|
|
1560
|
+
const eligible = new Set(options.eligiblePermissionKeys ?? ['network']);
|
|
1561
|
+
const entries = [];
|
|
1562
|
+
for (const key of LOCAL_DEV_GRANT_PERMISSION_KEYS) {
|
|
1563
|
+
if (!eligible.has(key) || options.declaredPermissions[key]?.enabled !== true)
|
|
1564
|
+
continue;
|
|
1565
|
+
if (approvals.valid && approvals.permissions[key]?.status === 'enabled')
|
|
1566
|
+
continue;
|
|
1567
|
+
entries.push(key === 'network'
|
|
1568
|
+
? { key, status: 'enabled', config: { useOfficialDomain: false } }
|
|
1569
|
+
: { key, status: 'enabled', config: {} });
|
|
1570
|
+
}
|
|
1571
|
+
return { schema_version: 1, revision: options.revision, entries };
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* 线上基线先与本地声明求交,再补齐临时权限,返回与输入脱离的普通 Runtime 快照。
|
|
1575
|
+
* 调用方只可在当前 Dev Session 已验证且用户接受后传入 grant;本函数不证明其可信来源。
|
|
1576
|
+
* 非法 grant 整体降权到基线,已批准配置不会被临时配置覆盖。
|
|
1577
|
+
*/
|
|
1578
|
+
function composeLocalDevRuntimePermissions(options) {
|
|
1579
|
+
const baseline = parseMiniProgramRuntimePermissions(options.runtimePermissions);
|
|
1580
|
+
const parsed = parseMiniProgramLocalDevGrant(options.localDevGrant);
|
|
1581
|
+
const permissions = baseline.valid ? baseline.permissions : {};
|
|
1582
|
+
for (const key of MINI_PROGRAM_PERMISSION_KEYS) {
|
|
1583
|
+
if (options.declaredPermissions[key]?.enabled !== true) {
|
|
1584
|
+
delete permissions[key];
|
|
1585
|
+
}
|
|
1586
|
+
else if (key === 'network' && permissions.network) {
|
|
1587
|
+
permissions.network.config.useOfficialDomain = permissions.network.status === 'enabled'
|
|
1588
|
+
&& permissions.network.config.useOfficialDomain === true
|
|
1589
|
+
&& options.declaredPermissions.network?.useOfficialDomain === true;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
const temporaryPermissionKeys = [];
|
|
1593
|
+
if (parsed.valid) {
|
|
1594
|
+
for (const entry of parsed.grant.entries) {
|
|
1595
|
+
if (options.declaredPermissions[entry.key]?.enabled !== true || permissions[entry.key]?.status === 'enabled')
|
|
1596
|
+
continue;
|
|
1597
|
+
permissions[entry.key] = entry;
|
|
1598
|
+
temporaryPermissionKeys.push(entry.key);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
const revision = isRecord$1(options.runtimePermissions) && typeof options.runtimePermissions.revision === 'number'
|
|
1602
|
+
&& Number.isSafeInteger(options.runtimePermissions.revision) && options.runtimePermissions.revision >= 0
|
|
1603
|
+
? options.runtimePermissions.revision : undefined;
|
|
1604
|
+
return {
|
|
1605
|
+
runtimePermissions: {
|
|
1606
|
+
schema_version: 1,
|
|
1607
|
+
...(revision === undefined ? {} : { revision }),
|
|
1608
|
+
entries: MINI_PROGRAM_PERMISSION_KEYS.flatMap((key) => permissions[key] ? [permissions[key]] : []),
|
|
1609
|
+
},
|
|
1610
|
+
temporaryPermissionKeys,
|
|
1611
|
+
grantValid: parsed.valid,
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
function isRecord$1(value) {
|
|
1615
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
1616
|
+
}
|
|
1617
|
+
function hasExactFields(value, fields) {
|
|
1618
|
+
return isRecord$1(value) && Object.keys(value).length === fields.length
|
|
1619
|
+
&& fields.every((field) => Object.prototype.hasOwnProperty.call(value, field));
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
/** 由 scripts/generate-native-host-contract.mjs 生成,请勿手改。 */
|
|
1623
|
+
const MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION = 1;
|
|
1624
|
+
const MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION = 1;
|
|
1625
|
+
const MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES = 65536;
|
|
1626
|
+
const MINI_PROGRAM_NATIVE_OPERATIONS = {
|
|
1627
|
+
"system": [
|
|
1628
|
+
"describe"
|
|
1629
|
+
],
|
|
1630
|
+
"network": [
|
|
1631
|
+
"open",
|
|
1632
|
+
"read",
|
|
1633
|
+
"release",
|
|
1634
|
+
"transfer"
|
|
1635
|
+
],
|
|
1636
|
+
"files": [
|
|
1637
|
+
"create",
|
|
1638
|
+
"remove",
|
|
1639
|
+
"exists",
|
|
1640
|
+
"openRead",
|
|
1641
|
+
"openWrite",
|
|
1642
|
+
"read",
|
|
1643
|
+
"release",
|
|
1644
|
+
"write",
|
|
1645
|
+
"stat",
|
|
1646
|
+
"list",
|
|
1647
|
+
"pickFiles",
|
|
1648
|
+
"pickDirectory",
|
|
1649
|
+
"saveFile"
|
|
1650
|
+
]
|
|
1651
|
+
};
|
|
1652
|
+
const MINI_PROGRAM_NATIVE_HOST_DESCRIPTION = {
|
|
1653
|
+
"protocolVersion": 1,
|
|
1654
|
+
"contractRevision": 1,
|
|
1655
|
+
"operations": {
|
|
1656
|
+
"system": [
|
|
1657
|
+
"describe"
|
|
1658
|
+
],
|
|
1659
|
+
"network": [
|
|
1660
|
+
"open",
|
|
1661
|
+
"read",
|
|
1662
|
+
"release",
|
|
1663
|
+
"transfer"
|
|
1664
|
+
],
|
|
1665
|
+
"files": [
|
|
1666
|
+
"create",
|
|
1667
|
+
"remove",
|
|
1668
|
+
"exists",
|
|
1669
|
+
"openRead",
|
|
1670
|
+
"openWrite",
|
|
1671
|
+
"read",
|
|
1672
|
+
"release",
|
|
1673
|
+
"write",
|
|
1674
|
+
"stat",
|
|
1675
|
+
"list",
|
|
1676
|
+
"pickFiles",
|
|
1677
|
+
"pickDirectory",
|
|
1678
|
+
"saveFile"
|
|
1679
|
+
]
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
/** Android WebMessageListener object 与 iOS WKScriptMessageHandler 共用名称。 */
|
|
1684
|
+
const MINI_PROGRAM_NATIVE_HOST_OBJECT = 'hbMiniProgramHost';
|
|
1685
|
+
/** Native 通过主文档 CustomEvent 回送 progress/result/error。 */
|
|
1686
|
+
const MINI_PROGRAM_NATIVE_HOST_MESSAGE_EVENT = 'heybox:miniprogram-native-host-message';
|
|
1687
|
+
function isMiniProgramNativeHostMessage(value) {
|
|
1688
|
+
if (!isRecord(value) || !isNonEmptyString(value.requestId))
|
|
1689
|
+
return false;
|
|
1690
|
+
if (value.type === 'progress')
|
|
1691
|
+
return Object.prototype.hasOwnProperty.call(value, 'payload');
|
|
1692
|
+
if (value.type === 'result')
|
|
1693
|
+
return !Object.prototype.hasOwnProperty.call(value, 'error');
|
|
1694
|
+
if (value.type !== 'error' || !isRecord(value.error))
|
|
1695
|
+
return false;
|
|
1696
|
+
return isNonEmptyString(value.error.code) && isNonEmptyString(value.error.message);
|
|
1697
|
+
}
|
|
1698
|
+
function isMiniProgramNativeHostDescription(value) {
|
|
1699
|
+
if (!isRecord(value) ||
|
|
1700
|
+
!isPositiveSafeInteger(value.protocolVersion) ||
|
|
1701
|
+
!isPositiveSafeInteger(value.contractRevision) ||
|
|
1702
|
+
!isRecord(value.operations))
|
|
1703
|
+
return false;
|
|
1704
|
+
const operations = value.operations;
|
|
1705
|
+
if (!isOperationList(operations.system) ||
|
|
1706
|
+
!isOperationList(operations.network) ||
|
|
1707
|
+
!isOperationList(operations.files))
|
|
1708
|
+
return false;
|
|
1709
|
+
return operations.system.includes('describe');
|
|
1710
|
+
}
|
|
1711
|
+
function isMiniProgramNativeBinaryChunk(value) {
|
|
1712
|
+
return (isRecord(value) &&
|
|
1713
|
+
isNonEmptyString(value.resourceId) &&
|
|
1714
|
+
typeof value.data === 'string' &&
|
|
1715
|
+
Number.isSafeInteger(value.byteLength) &&
|
|
1716
|
+
Number(value.byteLength) >= 0 &&
|
|
1717
|
+
Number(value.byteLength) <= MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES &&
|
|
1718
|
+
typeof value.eof === 'boolean' &&
|
|
1719
|
+
(Number(value.byteLength) > 0 || value.eof));
|
|
1720
|
+
}
|
|
1721
|
+
function isRecord(value) {
|
|
1722
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
1723
|
+
}
|
|
1724
|
+
function isNonEmptyString(value) {
|
|
1725
|
+
return typeof value === 'string' && value.length > 0;
|
|
1726
|
+
}
|
|
1727
|
+
function isPositiveSafeInteger(value) {
|
|
1728
|
+
return Number.isSafeInteger(value) && Number(value) > 0;
|
|
1729
|
+
}
|
|
1730
|
+
function isOperationList(value) {
|
|
1731
|
+
return (Array.isArray(value) &&
|
|
1732
|
+
value.every(operation => isNonEmptyString(operation) && operation === operation.trim()) &&
|
|
1733
|
+
new Set(value).size === value.length);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
/** 当前用户信息与登录能力支持的完整 scope 目录(canonical 顺序)。 */
|
|
1737
|
+
const USER_INFO_AUTHORIZATION_SCOPES = ['identity', 'profile', 'steam_account'];
|
|
1738
|
+
/** Companion alias 的跨构建、Runtime 与 Host 规范。 */
|
|
1739
|
+
const COMPANION_ALIAS_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
|
|
1740
|
+
/** Companion Host 可跨 bridge 保留的稳定领域错误码。 */
|
|
1741
|
+
const COMPANION_ERROR_CODES = [
|
|
1742
|
+
'COMPANION_UNSUPPORTED',
|
|
1743
|
+
'COMPANION_PREVIEW_UNSUPPORTED',
|
|
1744
|
+
'COMPANION_NOT_DECLARED',
|
|
1745
|
+
'COMPANION_TARGET_UNSUPPORTED',
|
|
1746
|
+
'COMPANION_NOT_PREPARED',
|
|
1747
|
+
'COMPANION_PREPARATION_CANCELLED',
|
|
1748
|
+
'COMPANION_DOWNLOAD_FAILED',
|
|
1749
|
+
'COMPANION_DESCRIPTOR_UNAVAILABLE',
|
|
1750
|
+
'COMPANION_ARCHIVE_INVALID',
|
|
1751
|
+
'COMPANION_INTEGRITY_FAILED',
|
|
1752
|
+
'COMPANION_ENTRYPOINT_INVALID',
|
|
1753
|
+
'COMPANION_USER_CANCELLED',
|
|
1754
|
+
'COMPANION_ELEVATION_DENIED',
|
|
1755
|
+
'COMPANION_OS_BLOCKED',
|
|
1756
|
+
'COMPANION_LAUNCH_FAILED',
|
|
1757
|
+
'COMPANION_SESSION_VERSION_MISMATCH',
|
|
1758
|
+
'COMPANION_SESSION_OWNERSHIP_LOST',
|
|
1759
|
+
'COMPANION_SESSION_EXITED',
|
|
1760
|
+
'COMPANION_PIPE_CLOSED',
|
|
1761
|
+
'COMPANION_OUTPUT_LIMIT',
|
|
1762
|
+
'COMPANION_PROCESS_CRASHED',
|
|
1763
|
+
'COMPANION_ATTACHMENT_NOT_FOUND',
|
|
1764
|
+
'COMPANION_NOTIFICATION_UNAVAILABLE',
|
|
1765
|
+
'COMPANION_TERMINATE_FAILED',
|
|
1766
|
+
];
|
|
1767
|
+
|
|
1768
|
+
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, COMPANION_ALIAS_PATTERN, COMPANION_CANCEL_PREPARATION_METHOD, COMPANION_ERROR_CODES, COMPANION_GET_ACTIVE_SESSION_METHOD, COMPANION_GET_INFO_METHOD, COMPANION_GET_PREPARATION_STATUS_METHOD, COMPANION_LAUNCH_METHOD, COMPANION_OPEN_ATTACHMENT_METHOD, COMPANION_PREPARE_METHOD, COMPANION_SESSION_ACK_OUTPUT_METHOD, COMPANION_SESSION_CLOSE_STDIN_METHOD, COMPANION_SESSION_EXIT_EVENT, COMPANION_SESSION_OUTPUT_EVENT, COMPANION_SESSION_OWNERSHIP_LOST_EVENT, COMPANION_SESSION_TERMINATE_METHOD, COMPANION_SESSION_WRITE_METHOD, COMPANION_SHOW_NOTIFICATION_METHOD, DEVICE_SET_CLIPBOARD_METHOD, DEVICE_VIBRATE_METHOD, DIRECTORY_CREATE_METHOD, DIRECTORY_EXISTS_METHOD, DIRECTORY_LIST_METHOD, DIRECTORY_REMOVE_METHOD, FILES_PICK_DIRECTORY_METHOD, FILES_PICK_FILES_METHOD, FILES_SAVE_FILE_METHOD, FILE_CREATE_METHOD, FILE_EXISTS_METHOD, FILE_READ_BYTES_METHOD, FILE_READ_TEXT_METHOD, FILE_REMOVE_METHOD, FILE_STAT_METHOD, FILE_WRITE_BYTES_METHOD, FILE_WRITE_TEXT_METHOD, LOCAL_DEV_GRANT_PERMISSION_KEYS, MINI_PROGRAM_BRIDGE_NONCE_PARAM, MINI_PROGRAM_MESSAGE_NAMESPACE, MINI_PROGRAM_MESSAGE_VERSION, MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES, MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION, MINI_PROGRAM_NATIVE_HOST_DESCRIPTION, MINI_PROGRAM_NATIVE_HOST_MESSAGE_EVENT, MINI_PROGRAM_NATIVE_HOST_OBJECT, MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION, MINI_PROGRAM_NATIVE_OPERATIONS, MINI_PROGRAM_NO_DECLARATION_METHODS, MINI_PROGRAM_OPERATION_PROGRESS_METHOD, MINI_PROGRAM_PERMISSION_CATALOG, MINI_PROGRAM_PERMISSION_KEYS, MINI_PROGRAM_PROTOCOL_CAPABILITIES, NAVIGATION_CLOSE_METHOD, NAVIGATION_OPEN_APP_PAGE_METHOD, NAVIGATION_RELOAD_METHOD, NETWORK_DOWNLOAD_METHOD, NETWORK_REQUEST_METHOD, RUNTIME_LOCATION_PROBE_METHOD, SDK_CSP_VIOLATION_METHOD, SDK_HANDSHAKE_METHOD, SDK_LOCATION_REPORT_METHOD, SHARE_COPY_LINK_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_DISPLAY_METHOD, VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD, composeLocalDevRuntimePermissions, createMiniProgramLocalDevGrant, isManagedMiniProgramRuntimePermissionKey, isMiniProgramBridgeMessage, isMiniProgramByteArray, isMiniProgramCompanionPrepareProgress, isMiniProgramDirectoryDescriptor, isMiniProgramDirectoryRef, isMiniProgramDownloadProgressPayload, isMiniProgramFileDescriptor, isMiniProgramFileRef, isMiniProgramFileStat, isMiniProgramFileSystemEntityDescriptor, isMiniProgramNativeBinaryChunk, isMiniProgramNativeHostDescription, isMiniProgramNativeHostMessage, isMiniProgramOperationProgressPayload, isMiniProgramPathRootRef, isMiniProgramPermissionKey, isMiniProgramRelativePath, parseMiniProgramLocalDevGrant, parseMiniProgramRuntimePermissions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
2
|
+
"hash": "6a5978e344f22fd060ff55f77a1248a7c161cd8fbf5be2b8c73eddd308e8fe78",
|
|
3
3
|
"permissions": [
|
|
4
4
|
{
|
|
5
5
|
"key": "userInfo",
|
|
@@ -177,6 +177,7 @@
|
|
|
177
177
|
"ui.hideLoading",
|
|
178
178
|
"viewport.getWindowInfo",
|
|
179
179
|
"viewport.setNavigationBarStyle",
|
|
180
|
+
"viewport.setDisplay",
|
|
180
181
|
"device.vibrate",
|
|
181
182
|
"navigation.close",
|
|
182
183
|
"navigation.reload",
|
package/package.json
CHANGED
package/src/bridge.ts
CHANGED
|
@@ -18,6 +18,8 @@ import type { MiniProgramCapabilityProgress, MiniProgramProgressMethod } from '.
|
|
|
18
18
|
export type MiniProgramBridgeMessageType = 'handshake' | 'request' | 'response' | 'event' | 'cancel';
|
|
19
19
|
export type MiniProgramEventName =
|
|
20
20
|
| 'launch'
|
|
21
|
+
| 'viewport_change'
|
|
22
|
+
| 'display_change'
|
|
21
23
|
| 'ready'
|
|
22
24
|
| 'show'
|
|
23
25
|
| 'hide'
|
|
@@ -123,6 +125,12 @@ export interface MiniProgramBridgeProgressMessage<
|
|
|
123
125
|
error?: never;
|
|
124
126
|
}
|
|
125
127
|
export interface MiniProgramEventPayloadMap {
|
|
128
|
+
/** 展示状态实际变化后通知;不回放初始状态,不支持或失败时不通知。 */
|
|
129
|
+
display_change: import('./payloads').MiniProgramDisplayState & {
|
|
130
|
+
/** api 为开发者调用;user 为用户点击宿主退出全屏按钮。同目标合并时保留首次发起来源。旧宿主可能不提供。 */
|
|
131
|
+
source?: 'api' | 'user';
|
|
132
|
+
};
|
|
133
|
+
viewport_change: import('./payloads').MiniProgramWindowInfoResult;
|
|
126
134
|
launch: { timestamp: number; url?: string };
|
|
127
135
|
ready: { timestamp: number };
|
|
128
136
|
show: { timestamp: number; source?: string };
|