@heybox/hb-sdk-protocol 0.8.1-alpha.9 → 0.8.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 CHANGED
@@ -11,6 +11,7 @@
11
11
  - bridge namespace、协议版本、method 常量和事件名称;
12
12
  - capability metadata(module、capability、requirement、risk)和权限机器目录;
13
13
  - method payload/result 与错误的 wire 类型;
14
+ - Mobile Mini-program Native Host 的无版本 envelope、operation vocabulary 与跨语言 fixture;
14
15
  - `runtime_permissions` schema 解析器和相关类型。
15
16
 
16
17
  它不拥有:
@@ -45,7 +46,7 @@ import { MINI_PROGRAM_PROTOCOL_CAPABILITIES, type MiniProgramBridgeMessage } fro
45
46
 
46
47
  耗时能力通过 `MiniProgramCapabilityProgressMap` 按 method 绑定进度 payload;当前覆盖 `network.download` 与 `companion.prepare`。Companion Session wire 只携带不透明 Session ID、controller generation、原始字节 chunk/ack、exit 和 ownership-lost 事件,不暴露 PID、路径或原生句柄。
47
48
 
48
- `CompanionInfo.source` 由可信 Host 标识 `local-dev` 或 `released`,与 `signatureStatus` 一起供授权展示使用;旧 Host 未提供来源时保持未知,不能推定为已审核产物。
49
+ `CompanionInfo.source` 由可信 Host 标识 `local-dev`、`preview` 或 `released`,与 `signatureStatus` 一起供授权展示使用;`preview` 表示审核前预览产物,旧 Host 未提供来源时保持未知,不能推定为已审核产物。
49
50
 
50
51
  协议包不决定业务授权。`auth.login()` 的 UI、账号会话、授权码签发和 OpenAPI 都由 Host/服务端负责;协议层只传递经过约束的 request/response 数据。
51
52
 
@@ -62,6 +63,21 @@ Runtime 可以在握手 response 中附带 `MiniProgramRuntimeEnvironmentInfo`
62
63
 
63
64
  完整符号以源码导出和生成的 TypeScript declarations 为准。Runtime 集成见 [`@heybox/hb-sdk-runtime`](../hb-sdk-runtime/README.md),客户端能力见 [`@heybox/hb-sdk`](../hb-sdk/README.md)。
64
65
 
66
+ ## Mobile Native Host contract
67
+
68
+ `src/native-host-contract.source.json` 是 operation、chunk limit 与跨语言 case 的唯一可编辑
69
+ registry;`gen:native-host-contract` 同时派生 TypeScript 常量与 Swift/Kotlin 消费的 JSON,
70
+ `check:native-host-contract` 已接入 package build/test 前置门禁。`src/native-host.ts` 提供 wire
71
+ 类型与 guards。request envelope 不携带版本号;H5 在创建 Mobile Host 时先调用
72
+ `system.describe`,读取 `protocolVersion`、`contractRevision` 和各 domain 实际支持的 operations。
73
+ 缺少 handler、握手超时、协议版本不匹配或 operation 不完整时必须按实际能力 fail closed;公开
74
+ `network.request` 保留 legacy transport,不因协商失败回归。每个请求只允许一个 terminal
75
+ message,取消通过引用原 `requestId` 的独立 control message 完成,二进制 pull 每块最多 64 KiB。
76
+
77
+ 跨语言测试输入位于 `generated/native-host-contract.json`,禁止手改。该文件固定 network
78
+ `open/read/release/transfer` 与 files operation 字段,并覆盖正常分块、取消竞态、重复终态、
79
+ 晚到进度、超大分块、跨 session handle 与错误脱敏;平台实现不得维护另一份可编辑 registry。
80
+
65
81
  ## 验证
66
82
 
67
83
  ```bash
package/dist/index.cjs.js CHANGED
@@ -334,32 +334,32 @@ const MINI_PROGRAM_PROTOCOL_CAPABILITIES = [
334
334
  ];
335
335
 
336
336
  function isMiniProgramBridgeMessage(value) {
337
- if (!isRecord$1(value))
337
+ if (!isRecord$2(value))
338
338
  return false;
339
- if (value.namespace !== MINI_PROGRAM_MESSAGE_NAMESPACE || (value.version !== 1 && value.version !== 2) || !isNonEmptyString(value.nonce)) {
339
+ if (value.namespace !== MINI_PROGRAM_MESSAGE_NAMESPACE || (value.version !== 1 && value.version !== 2) || !isNonEmptyString$1(value.nonce)) {
340
340
  return false;
341
341
  }
342
342
  if (value.type === 'handshake') {
343
- return isNonEmptyString(value.id) && value.method === SDK_HANDSHAKE_METHOD && value.error === undefined && isSDKHandshakePayload(value.payload);
343
+ return isNonEmptyString$1(value.id) && value.method === SDK_HANDSHAKE_METHOD && value.error === undefined && isSDKHandshakePayload(value.payload);
344
344
  }
345
345
  if (value.type === 'request') {
346
- return isNonEmptyString(value.id) && isNonEmptyString(value.method) && value.error === undefined;
346
+ return isNonEmptyString$1(value.id) && isNonEmptyString$1(value.method) && value.error === undefined;
347
347
  }
348
348
  if (value.type === 'response') {
349
- return (isNonEmptyString(value.id) &&
350
- (value.method === undefined || isNonEmptyString(value.method)) &&
349
+ return (isNonEmptyString$1(value.id) &&
350
+ (value.method === undefined || isNonEmptyString$1(value.method)) &&
351
351
  (value.error === undefined || isBridgeError(value.error)));
352
352
  }
353
353
  if (value.type === 'event') {
354
- if (!isNonEmptyString(value.method) || value.error !== undefined)
354
+ if (!isNonEmptyString$1(value.method) || value.error !== undefined)
355
355
  return false;
356
356
  if (value.method === MINI_PROGRAM_OPERATION_PROGRESS_METHOD) {
357
- return value.version === 2 && isNonEmptyString(value.id) && isMiniProgramOperationProgressPayload(value.payload);
357
+ return value.version === 2 && isNonEmptyString$1(value.id) && isMiniProgramOperationProgressPayload(value.payload);
358
358
  }
359
- return value.id === undefined || isNonEmptyString(value.id);
359
+ return value.id === undefined || isNonEmptyString$1(value.id);
360
360
  }
361
361
  if (value.type === 'cancel') {
362
- return (value.version === 2 && isNonEmptyString(value.id) && value.method === undefined && value.payload === undefined && value.error === undefined);
362
+ return (value.version === 2 && isNonEmptyString$1(value.id) && value.method === undefined && value.payload === undefined && value.error === undefined);
363
363
  }
364
364
  return false;
365
365
  }
@@ -372,40 +372,40 @@ function isMiniProgramRelativePath(value) {
372
372
  return value.split('/').every((segment) => Boolean(segment) && segment !== '.' && segment !== '..');
373
373
  }
374
374
  function isMiniProgramPathRootRef(value) {
375
- if (!isRecord$1(value))
375
+ if (!isRecord$2(value))
376
376
  return false;
377
377
  if (value.kind === 'sandbox')
378
378
  return hasOnlyKeys(value, ['kind']);
379
- return value.kind === 'directory' && isNonEmptyString(value.handleId) && hasOnlyKeys(value, ['kind', 'handleId']);
379
+ return value.kind === 'directory' && isNonEmptyString$1(value.handleId) && hasOnlyKeys(value, ['kind', 'handleId']);
380
380
  }
381
381
  function isMiniProgramFileRef(value) {
382
- if (!isRecord$1(value) || value.kind !== 'file')
382
+ if (!isRecord$2(value) || value.kind !== 'file')
383
383
  return false;
384
- if (isNonEmptyString(value.handleId)) {
384
+ if (isNonEmptyString$1(value.handleId)) {
385
385
  return hasOnlyKeys(value, ['kind', 'handleId']);
386
386
  }
387
387
  return (isMiniProgramPathRootRef(value.root) && isMiniProgramRelativePath(value.relativePath) && hasOnlyKeys(value, ['kind', 'root', 'relativePath']));
388
388
  }
389
389
  function isMiniProgramDirectoryRef(value) {
390
- if (!isRecord$1(value) || value.kind !== 'directory')
390
+ if (!isRecord$2(value) || value.kind !== 'directory')
391
391
  return false;
392
- if (isNonEmptyString(value.handleId)) {
392
+ if (isNonEmptyString$1(value.handleId)) {
393
393
  return hasOnlyKeys(value, ['kind', 'handleId']);
394
394
  }
395
395
  return (isMiniProgramPathRootRef(value.root) && (value.relativePath === '.' || isMiniProgramRelativePath(value.relativePath)) && hasOnlyKeys(value, ['kind', 'root', 'relativePath']));
396
396
  }
397
397
  function isMiniProgramFileDescriptor(value) {
398
- return (isRecord$1(value) &&
398
+ return (isRecord$2(value) &&
399
399
  value.kind === 'file' &&
400
- isNonEmptyString(value.name) &&
400
+ isNonEmptyString$1(value.name) &&
401
401
  isFileMode(value.mode) &&
402
402
  isMiniProgramFileRef(value.ref) &&
403
403
  hasOnlyKeys(value, ['kind', 'name', 'mode', 'ref']));
404
404
  }
405
405
  function isMiniProgramDirectoryDescriptor(value) {
406
- return (isRecord$1(value) &&
406
+ return (isRecord$2(value) &&
407
407
  value.kind === 'directory' &&
408
- isNonEmptyString(value.name) &&
408
+ isNonEmptyString$1(value.name) &&
409
409
  isFileMode(value.mode) &&
410
410
  isMiniProgramDirectoryRef(value.ref) &&
411
411
  hasOnlyKeys(value, ['kind', 'name', 'mode', 'ref']));
@@ -417,7 +417,7 @@ function isMiniProgramByteArray(value) {
417
417
  return value instanceof Uint8Array && value.buffer instanceof ArrayBuffer;
418
418
  }
419
419
  function isMiniProgramFileStat(value) {
420
- return (isRecord$1(value) &&
420
+ return (isRecord$2(value) &&
421
421
  value.kind === 'file' &&
422
422
  isNonNegativeSafeInteger(value.size) &&
423
423
  (value.modifiedAt === undefined || isNonNegativeFiniteNumber(value.modifiedAt)) &&
@@ -425,7 +425,7 @@ function isMiniProgramFileStat(value) {
425
425
  hasOnlyKeys(value, ['kind', 'size', 'modifiedAt', 'createdAt']));
426
426
  }
427
427
  function isMiniProgramDownloadProgressPayload(value) {
428
- if (!isRecord$1(value) ||
428
+ if (!isRecord$2(value) ||
429
429
  !isNonNegativeSafeInteger(value.loaded) ||
430
430
  typeof value.lengthComputable !== 'boolean' ||
431
431
  !hasOnlyKeys(value, ['loaded', 'total', 'lengthComputable'])) {
@@ -436,7 +436,7 @@ function isMiniProgramDownloadProgressPayload(value) {
436
436
  return isNonNegativeSafeInteger(value.total) && value.loaded <= value.total;
437
437
  }
438
438
  function isMiniProgramCompanionPrepareProgress(value) {
439
- if (!isRecord$1(value))
439
+ if (!isRecord$2(value))
440
440
  return false;
441
441
  if (value.phase === 'downloading') {
442
442
  return (isNonNegativeSafeInteger(value.loaded) &&
@@ -454,10 +454,10 @@ function isMiniProgramOperationProgressPayload(value) {
454
454
  return isMiniProgramDownloadProgressPayload(value) || isMiniProgramCompanionPrepareProgress(value);
455
455
  }
456
456
  function isSDKHandshakePayload(value) {
457
- return isRecord$1(value) && isNonEmptyString(value.href) && typeof value.userAgent === 'string' && isNonEmptyString(value.sdkVersion);
457
+ return isRecord$2(value) && isNonEmptyString$1(value.href) && typeof value.userAgent === 'string' && isNonEmptyString$1(value.sdkVersion);
458
458
  }
459
459
  function isBridgeError(value) {
460
- return isRecord$1(value) && isNonEmptyString(value.code) && typeof value.message === 'string';
460
+ return isRecord$2(value) && isNonEmptyString$1(value.code) && typeof value.message === 'string';
461
461
  }
462
462
  function isFileMode(value) {
463
463
  return value === 'read' || value === 'readwrite';
@@ -468,17 +468,131 @@ function isNonNegativeSafeInteger(value) {
468
468
  function isNonNegativeFiniteNumber(value) {
469
469
  return typeof value === 'number' && Number.isFinite(value) && value >= 0;
470
470
  }
471
- function isNonEmptyString(value) {
471
+ function isNonEmptyString$1(value) {
472
472
  return typeof value === 'string' && value.length > 0;
473
473
  }
474
474
  function hasOnlyKeys(value, allowedKeys) {
475
475
  const allowed = new Set(allowedKeys);
476
476
  return Object.keys(value).every((key) => allowed.has(key));
477
477
  }
478
- function isRecord$1(value) {
478
+ function isRecord$2(value) {
479
479
  return typeof value === 'object' && value !== null && !Array.isArray(value);
480
480
  }
481
481
 
482
+ /** 由 scripts/generate-native-host-contract.mjs 生成,请勿手改。 */
483
+ const MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION = 1;
484
+ const MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION = 1;
485
+ const MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES = 65536;
486
+ const MINI_PROGRAM_NATIVE_OPERATIONS = {
487
+ "system": [
488
+ "describe"
489
+ ],
490
+ "network": [
491
+ "open",
492
+ "read",
493
+ "release",
494
+ "transfer"
495
+ ],
496
+ "files": [
497
+ "create",
498
+ "remove",
499
+ "exists",
500
+ "openRead",
501
+ "openWrite",
502
+ "read",
503
+ "release",
504
+ "write",
505
+ "stat",
506
+ "list",
507
+ "pickFiles",
508
+ "pickDirectory",
509
+ "saveFile"
510
+ ]
511
+ };
512
+ const MINI_PROGRAM_NATIVE_HOST_DESCRIPTION = {
513
+ "protocolVersion": 1,
514
+ "contractRevision": 1,
515
+ "operations": {
516
+ "system": [
517
+ "describe"
518
+ ],
519
+ "network": [
520
+ "open",
521
+ "read",
522
+ "release",
523
+ "transfer"
524
+ ],
525
+ "files": [
526
+ "create",
527
+ "remove",
528
+ "exists",
529
+ "openRead",
530
+ "openWrite",
531
+ "read",
532
+ "release",
533
+ "write",
534
+ "stat",
535
+ "list",
536
+ "pickFiles",
537
+ "pickDirectory",
538
+ "saveFile"
539
+ ]
540
+ }
541
+ };
542
+
543
+ /** Android WebMessageListener object 与 iOS WKScriptMessageHandler 共用名称。 */
544
+ const MINI_PROGRAM_NATIVE_HOST_OBJECT = 'hbMiniProgramHost';
545
+ /** Native 通过主文档 CustomEvent 回送 progress/result/error。 */
546
+ const MINI_PROGRAM_NATIVE_HOST_MESSAGE_EVENT = 'heybox:miniprogram-native-host-message';
547
+ function isMiniProgramNativeHostMessage(value) {
548
+ if (!isRecord$1(value) || !isNonEmptyString(value.requestId))
549
+ return false;
550
+ if (value.type === 'progress')
551
+ return Object.prototype.hasOwnProperty.call(value, 'payload');
552
+ if (value.type === 'result')
553
+ return !Object.prototype.hasOwnProperty.call(value, 'error');
554
+ if (value.type !== 'error' || !isRecord$1(value.error))
555
+ return false;
556
+ return isNonEmptyString(value.error.code) && isNonEmptyString(value.error.message);
557
+ }
558
+ function isMiniProgramNativeHostDescription(value) {
559
+ if (!isRecord$1(value) ||
560
+ !isPositiveSafeInteger(value.protocolVersion) ||
561
+ !isPositiveSafeInteger(value.contractRevision) ||
562
+ !isRecord$1(value.operations))
563
+ return false;
564
+ const operations = value.operations;
565
+ if (!isOperationList(operations.system) ||
566
+ !isOperationList(operations.network) ||
567
+ !isOperationList(operations.files))
568
+ return false;
569
+ return operations.system.includes('describe');
570
+ }
571
+ function isMiniProgramNativeBinaryChunk(value) {
572
+ return (isRecord$1(value) &&
573
+ isNonEmptyString(value.resourceId) &&
574
+ typeof value.data === 'string' &&
575
+ Number.isSafeInteger(value.byteLength) &&
576
+ Number(value.byteLength) >= 0 &&
577
+ Number(value.byteLength) <= MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES &&
578
+ typeof value.eof === 'boolean' &&
579
+ (Number(value.byteLength) > 0 || value.eof));
580
+ }
581
+ function isRecord$1(value) {
582
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
583
+ }
584
+ function isNonEmptyString(value) {
585
+ return typeof value === 'string' && value.length > 0;
586
+ }
587
+ function isPositiveSafeInteger(value) {
588
+ return Number.isSafeInteger(value) && Number(value) > 0;
589
+ }
590
+ function isOperationList(value) {
591
+ return (Array.isArray(value) &&
592
+ value.every(operation => isNonEmptyString(operation) && operation === operation.trim()) &&
593
+ new Set(value).size === value.length);
594
+ }
595
+
482
596
  /** 当前用户信息与登录能力支持的完整 scope 目录。 */
483
597
  const USER_INFO_AUTHORIZATION_SCOPES = ['identity', 'profile'];
484
598
  /** Companion alias 的跨构建、Runtime 与 Host 规范。 */
@@ -486,6 +600,7 @@ const COMPANION_ALIAS_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
486
600
  /** Companion Host 可跨 bridge 保留的稳定领域错误码。 */
487
601
  const COMPANION_ERROR_CODES = [
488
602
  'COMPANION_UNSUPPORTED',
603
+ 'COMPANION_PREVIEW_UNSUPPORTED',
489
604
  'COMPANION_NOT_DECLARED',
490
605
  'COMPANION_TARGET_UNSUPPORTED',
491
606
  'COMPANION_NOT_PREPARED',
@@ -771,6 +886,13 @@ exports.FILE_WRITE_TEXT_METHOD = FILE_WRITE_TEXT_METHOD;
771
886
  exports.MINI_PROGRAM_BRIDGE_NONCE_PARAM = MINI_PROGRAM_BRIDGE_NONCE_PARAM;
772
887
  exports.MINI_PROGRAM_MESSAGE_NAMESPACE = MINI_PROGRAM_MESSAGE_NAMESPACE;
773
888
  exports.MINI_PROGRAM_MESSAGE_VERSION = MINI_PROGRAM_MESSAGE_VERSION;
889
+ exports.MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES = MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES;
890
+ exports.MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION = MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION;
891
+ exports.MINI_PROGRAM_NATIVE_HOST_DESCRIPTION = MINI_PROGRAM_NATIVE_HOST_DESCRIPTION;
892
+ exports.MINI_PROGRAM_NATIVE_HOST_MESSAGE_EVENT = MINI_PROGRAM_NATIVE_HOST_MESSAGE_EVENT;
893
+ exports.MINI_PROGRAM_NATIVE_HOST_OBJECT = MINI_PROGRAM_NATIVE_HOST_OBJECT;
894
+ exports.MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION = MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION;
895
+ exports.MINI_PROGRAM_NATIVE_OPERATIONS = MINI_PROGRAM_NATIVE_OPERATIONS;
774
896
  exports.MINI_PROGRAM_NO_DECLARATION_METHODS = MINI_PROGRAM_NO_DECLARATION_METHODS;
775
897
  exports.MINI_PROGRAM_OPERATION_PROGRESS_METHOD = MINI_PROGRAM_OPERATION_PROGRESS_METHOD;
776
898
  exports.MINI_PROGRAM_PERMISSION_CATALOG = MINI_PROGRAM_PERMISSION_CATALOG;
@@ -810,6 +932,9 @@ exports.isMiniProgramFileDescriptor = isMiniProgramFileDescriptor;
810
932
  exports.isMiniProgramFileRef = isMiniProgramFileRef;
811
933
  exports.isMiniProgramFileStat = isMiniProgramFileStat;
812
934
  exports.isMiniProgramFileSystemEntityDescriptor = isMiniProgramFileSystemEntityDescriptor;
935
+ exports.isMiniProgramNativeBinaryChunk = isMiniProgramNativeBinaryChunk;
936
+ exports.isMiniProgramNativeHostDescription = isMiniProgramNativeHostDescription;
937
+ exports.isMiniProgramNativeHostMessage = isMiniProgramNativeHostMessage;
813
938
  exports.isMiniProgramOperationProgressPayload = isMiniProgramOperationProgressPayload;
814
939
  exports.isMiniProgramPathRootRef = isMiniProgramPathRootRef;
815
940
  exports.isMiniProgramPermissionKey = isMiniProgramPermissionKey;
package/dist/index.esm.js CHANGED
@@ -332,32 +332,32 @@ const MINI_PROGRAM_PROTOCOL_CAPABILITIES = [
332
332
  ];
333
333
 
334
334
  function isMiniProgramBridgeMessage(value) {
335
- if (!isRecord$1(value))
335
+ if (!isRecord$2(value))
336
336
  return false;
337
- if (value.namespace !== MINI_PROGRAM_MESSAGE_NAMESPACE || (value.version !== 1 && value.version !== 2) || !isNonEmptyString(value.nonce)) {
337
+ if (value.namespace !== MINI_PROGRAM_MESSAGE_NAMESPACE || (value.version !== 1 && value.version !== 2) || !isNonEmptyString$1(value.nonce)) {
338
338
  return false;
339
339
  }
340
340
  if (value.type === 'handshake') {
341
- return isNonEmptyString(value.id) && value.method === SDK_HANDSHAKE_METHOD && value.error === undefined && isSDKHandshakePayload(value.payload);
341
+ return isNonEmptyString$1(value.id) && value.method === SDK_HANDSHAKE_METHOD && value.error === undefined && isSDKHandshakePayload(value.payload);
342
342
  }
343
343
  if (value.type === 'request') {
344
- return isNonEmptyString(value.id) && isNonEmptyString(value.method) && value.error === undefined;
344
+ return isNonEmptyString$1(value.id) && isNonEmptyString$1(value.method) && value.error === undefined;
345
345
  }
346
346
  if (value.type === 'response') {
347
- return (isNonEmptyString(value.id) &&
348
- (value.method === undefined || isNonEmptyString(value.method)) &&
347
+ return (isNonEmptyString$1(value.id) &&
348
+ (value.method === undefined || isNonEmptyString$1(value.method)) &&
349
349
  (value.error === undefined || isBridgeError(value.error)));
350
350
  }
351
351
  if (value.type === 'event') {
352
- if (!isNonEmptyString(value.method) || value.error !== undefined)
352
+ if (!isNonEmptyString$1(value.method) || value.error !== undefined)
353
353
  return false;
354
354
  if (value.method === MINI_PROGRAM_OPERATION_PROGRESS_METHOD) {
355
- return value.version === 2 && isNonEmptyString(value.id) && isMiniProgramOperationProgressPayload(value.payload);
355
+ return value.version === 2 && isNonEmptyString$1(value.id) && isMiniProgramOperationProgressPayload(value.payload);
356
356
  }
357
- return value.id === undefined || isNonEmptyString(value.id);
357
+ return value.id === undefined || isNonEmptyString$1(value.id);
358
358
  }
359
359
  if (value.type === 'cancel') {
360
- return (value.version === 2 && isNonEmptyString(value.id) && value.method === undefined && value.payload === undefined && value.error === undefined);
360
+ return (value.version === 2 && isNonEmptyString$1(value.id) && value.method === undefined && value.payload === undefined && value.error === undefined);
361
361
  }
362
362
  return false;
363
363
  }
@@ -370,40 +370,40 @@ function isMiniProgramRelativePath(value) {
370
370
  return value.split('/').every((segment) => Boolean(segment) && segment !== '.' && segment !== '..');
371
371
  }
372
372
  function isMiniProgramPathRootRef(value) {
373
- if (!isRecord$1(value))
373
+ if (!isRecord$2(value))
374
374
  return false;
375
375
  if (value.kind === 'sandbox')
376
376
  return hasOnlyKeys(value, ['kind']);
377
- return value.kind === 'directory' && isNonEmptyString(value.handleId) && hasOnlyKeys(value, ['kind', 'handleId']);
377
+ return value.kind === 'directory' && isNonEmptyString$1(value.handleId) && hasOnlyKeys(value, ['kind', 'handleId']);
378
378
  }
379
379
  function isMiniProgramFileRef(value) {
380
- if (!isRecord$1(value) || value.kind !== 'file')
380
+ if (!isRecord$2(value) || value.kind !== 'file')
381
381
  return false;
382
- if (isNonEmptyString(value.handleId)) {
382
+ if (isNonEmptyString$1(value.handleId)) {
383
383
  return hasOnlyKeys(value, ['kind', 'handleId']);
384
384
  }
385
385
  return (isMiniProgramPathRootRef(value.root) && isMiniProgramRelativePath(value.relativePath) && hasOnlyKeys(value, ['kind', 'root', 'relativePath']));
386
386
  }
387
387
  function isMiniProgramDirectoryRef(value) {
388
- if (!isRecord$1(value) || value.kind !== 'directory')
388
+ if (!isRecord$2(value) || value.kind !== 'directory')
389
389
  return false;
390
- if (isNonEmptyString(value.handleId)) {
390
+ if (isNonEmptyString$1(value.handleId)) {
391
391
  return hasOnlyKeys(value, ['kind', 'handleId']);
392
392
  }
393
393
  return (isMiniProgramPathRootRef(value.root) && (value.relativePath === '.' || isMiniProgramRelativePath(value.relativePath)) && hasOnlyKeys(value, ['kind', 'root', 'relativePath']));
394
394
  }
395
395
  function isMiniProgramFileDescriptor(value) {
396
- return (isRecord$1(value) &&
396
+ return (isRecord$2(value) &&
397
397
  value.kind === 'file' &&
398
- isNonEmptyString(value.name) &&
398
+ isNonEmptyString$1(value.name) &&
399
399
  isFileMode(value.mode) &&
400
400
  isMiniProgramFileRef(value.ref) &&
401
401
  hasOnlyKeys(value, ['kind', 'name', 'mode', 'ref']));
402
402
  }
403
403
  function isMiniProgramDirectoryDescriptor(value) {
404
- return (isRecord$1(value) &&
404
+ return (isRecord$2(value) &&
405
405
  value.kind === 'directory' &&
406
- isNonEmptyString(value.name) &&
406
+ isNonEmptyString$1(value.name) &&
407
407
  isFileMode(value.mode) &&
408
408
  isMiniProgramDirectoryRef(value.ref) &&
409
409
  hasOnlyKeys(value, ['kind', 'name', 'mode', 'ref']));
@@ -415,7 +415,7 @@ function isMiniProgramByteArray(value) {
415
415
  return value instanceof Uint8Array && value.buffer instanceof ArrayBuffer;
416
416
  }
417
417
  function isMiniProgramFileStat(value) {
418
- return (isRecord$1(value) &&
418
+ return (isRecord$2(value) &&
419
419
  value.kind === 'file' &&
420
420
  isNonNegativeSafeInteger(value.size) &&
421
421
  (value.modifiedAt === undefined || isNonNegativeFiniteNumber(value.modifiedAt)) &&
@@ -423,7 +423,7 @@ function isMiniProgramFileStat(value) {
423
423
  hasOnlyKeys(value, ['kind', 'size', 'modifiedAt', 'createdAt']));
424
424
  }
425
425
  function isMiniProgramDownloadProgressPayload(value) {
426
- if (!isRecord$1(value) ||
426
+ if (!isRecord$2(value) ||
427
427
  !isNonNegativeSafeInteger(value.loaded) ||
428
428
  typeof value.lengthComputable !== 'boolean' ||
429
429
  !hasOnlyKeys(value, ['loaded', 'total', 'lengthComputable'])) {
@@ -434,7 +434,7 @@ function isMiniProgramDownloadProgressPayload(value) {
434
434
  return isNonNegativeSafeInteger(value.total) && value.loaded <= value.total;
435
435
  }
436
436
  function isMiniProgramCompanionPrepareProgress(value) {
437
- if (!isRecord$1(value))
437
+ if (!isRecord$2(value))
438
438
  return false;
439
439
  if (value.phase === 'downloading') {
440
440
  return (isNonNegativeSafeInteger(value.loaded) &&
@@ -452,10 +452,10 @@ function isMiniProgramOperationProgressPayload(value) {
452
452
  return isMiniProgramDownloadProgressPayload(value) || isMiniProgramCompanionPrepareProgress(value);
453
453
  }
454
454
  function isSDKHandshakePayload(value) {
455
- return isRecord$1(value) && isNonEmptyString(value.href) && typeof value.userAgent === 'string' && isNonEmptyString(value.sdkVersion);
455
+ return isRecord$2(value) && isNonEmptyString$1(value.href) && typeof value.userAgent === 'string' && isNonEmptyString$1(value.sdkVersion);
456
456
  }
457
457
  function isBridgeError(value) {
458
- return isRecord$1(value) && isNonEmptyString(value.code) && typeof value.message === 'string';
458
+ return isRecord$2(value) && isNonEmptyString$1(value.code) && typeof value.message === 'string';
459
459
  }
460
460
  function isFileMode(value) {
461
461
  return value === 'read' || value === 'readwrite';
@@ -466,17 +466,131 @@ function isNonNegativeSafeInteger(value) {
466
466
  function isNonNegativeFiniteNumber(value) {
467
467
  return typeof value === 'number' && Number.isFinite(value) && value >= 0;
468
468
  }
469
- function isNonEmptyString(value) {
469
+ function isNonEmptyString$1(value) {
470
470
  return typeof value === 'string' && value.length > 0;
471
471
  }
472
472
  function hasOnlyKeys(value, allowedKeys) {
473
473
  const allowed = new Set(allowedKeys);
474
474
  return Object.keys(value).every((key) => allowed.has(key));
475
475
  }
476
- function isRecord$1(value) {
476
+ function isRecord$2(value) {
477
477
  return typeof value === 'object' && value !== null && !Array.isArray(value);
478
478
  }
479
479
 
480
+ /** 由 scripts/generate-native-host-contract.mjs 生成,请勿手改。 */
481
+ const MINI_PROGRAM_NATIVE_HOST_PROTOCOL_VERSION = 1;
482
+ const MINI_PROGRAM_NATIVE_HOST_CONTRACT_REVISION = 1;
483
+ const MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES = 65536;
484
+ const MINI_PROGRAM_NATIVE_OPERATIONS = {
485
+ "system": [
486
+ "describe"
487
+ ],
488
+ "network": [
489
+ "open",
490
+ "read",
491
+ "release",
492
+ "transfer"
493
+ ],
494
+ "files": [
495
+ "create",
496
+ "remove",
497
+ "exists",
498
+ "openRead",
499
+ "openWrite",
500
+ "read",
501
+ "release",
502
+ "write",
503
+ "stat",
504
+ "list",
505
+ "pickFiles",
506
+ "pickDirectory",
507
+ "saveFile"
508
+ ]
509
+ };
510
+ const MINI_PROGRAM_NATIVE_HOST_DESCRIPTION = {
511
+ "protocolVersion": 1,
512
+ "contractRevision": 1,
513
+ "operations": {
514
+ "system": [
515
+ "describe"
516
+ ],
517
+ "network": [
518
+ "open",
519
+ "read",
520
+ "release",
521
+ "transfer"
522
+ ],
523
+ "files": [
524
+ "create",
525
+ "remove",
526
+ "exists",
527
+ "openRead",
528
+ "openWrite",
529
+ "read",
530
+ "release",
531
+ "write",
532
+ "stat",
533
+ "list",
534
+ "pickFiles",
535
+ "pickDirectory",
536
+ "saveFile"
537
+ ]
538
+ }
539
+ };
540
+
541
+ /** Android WebMessageListener object 与 iOS WKScriptMessageHandler 共用名称。 */
542
+ const MINI_PROGRAM_NATIVE_HOST_OBJECT = 'hbMiniProgramHost';
543
+ /** Native 通过主文档 CustomEvent 回送 progress/result/error。 */
544
+ const MINI_PROGRAM_NATIVE_HOST_MESSAGE_EVENT = 'heybox:miniprogram-native-host-message';
545
+ function isMiniProgramNativeHostMessage(value) {
546
+ if (!isRecord$1(value) || !isNonEmptyString(value.requestId))
547
+ return false;
548
+ if (value.type === 'progress')
549
+ return Object.prototype.hasOwnProperty.call(value, 'payload');
550
+ if (value.type === 'result')
551
+ return !Object.prototype.hasOwnProperty.call(value, 'error');
552
+ if (value.type !== 'error' || !isRecord$1(value.error))
553
+ return false;
554
+ return isNonEmptyString(value.error.code) && isNonEmptyString(value.error.message);
555
+ }
556
+ function isMiniProgramNativeHostDescription(value) {
557
+ if (!isRecord$1(value) ||
558
+ !isPositiveSafeInteger(value.protocolVersion) ||
559
+ !isPositiveSafeInteger(value.contractRevision) ||
560
+ !isRecord$1(value.operations))
561
+ return false;
562
+ const operations = value.operations;
563
+ if (!isOperationList(operations.system) ||
564
+ !isOperationList(operations.network) ||
565
+ !isOperationList(operations.files))
566
+ return false;
567
+ return operations.system.includes('describe');
568
+ }
569
+ function isMiniProgramNativeBinaryChunk(value) {
570
+ return (isRecord$1(value) &&
571
+ isNonEmptyString(value.resourceId) &&
572
+ typeof value.data === 'string' &&
573
+ Number.isSafeInteger(value.byteLength) &&
574
+ Number(value.byteLength) >= 0 &&
575
+ Number(value.byteLength) <= MINI_PROGRAM_NATIVE_CHUNK_MAX_BYTES &&
576
+ typeof value.eof === 'boolean' &&
577
+ (Number(value.byteLength) > 0 || value.eof));
578
+ }
579
+ function isRecord$1(value) {
580
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
581
+ }
582
+ function isNonEmptyString(value) {
583
+ return typeof value === 'string' && value.length > 0;
584
+ }
585
+ function isPositiveSafeInteger(value) {
586
+ return Number.isSafeInteger(value) && Number(value) > 0;
587
+ }
588
+ function isOperationList(value) {
589
+ return (Array.isArray(value) &&
590
+ value.every(operation => isNonEmptyString(operation) && operation === operation.trim()) &&
591
+ new Set(value).size === value.length);
592
+ }
593
+
480
594
  /** 当前用户信息与登录能力支持的完整 scope 目录。 */
481
595
  const USER_INFO_AUTHORIZATION_SCOPES = ['identity', 'profile'];
482
596
  /** Companion alias 的跨构建、Runtime 与 Host 规范。 */
@@ -484,6 +598,7 @@ const COMPANION_ALIAS_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
484
598
  /** Companion Host 可跨 bridge 保留的稳定领域错误码。 */
485
599
  const COMPANION_ERROR_CODES = [
486
600
  'COMPANION_UNSUPPORTED',
601
+ 'COMPANION_PREVIEW_UNSUPPORTED',
487
602
  'COMPANION_NOT_DECLARED',
488
603
  'COMPANION_TARGET_UNSUPPORTED',
489
604
  'COMPANION_NOT_PREPARED',
@@ -726,4 +841,4 @@ function isRecord(value) {
726
841
  return typeof value === 'object' && value !== null && !Array.isArray(value);
727
842
  }
728
843
 
729
- 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, MINI_PROGRAM_BRIDGE_NONCE_PARAM, MINI_PROGRAM_MESSAGE_NAMESPACE, MINI_PROGRAM_MESSAGE_VERSION, 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_NAVIGATION_BAR_STYLE_METHOD, isManagedMiniProgramRuntimePermissionKey, isMiniProgramBridgeMessage, isMiniProgramByteArray, isMiniProgramCompanionPrepareProgress, isMiniProgramDirectoryDescriptor, isMiniProgramDirectoryRef, isMiniProgramDownloadProgressPayload, isMiniProgramFileDescriptor, isMiniProgramFileRef, isMiniProgramFileStat, isMiniProgramFileSystemEntityDescriptor, isMiniProgramOperationProgressPayload, isMiniProgramPathRootRef, isMiniProgramPermissionKey, isMiniProgramRelativePath, parseMiniProgramRuntimePermissions };
844
+ 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, 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_NAVIGATION_BAR_STYLE_METHOD, isManagedMiniProgramRuntimePermissionKey, isMiniProgramBridgeMessage, isMiniProgramByteArray, isMiniProgramCompanionPrepareProgress, isMiniProgramDirectoryDescriptor, isMiniProgramDirectoryRef, isMiniProgramDownloadProgressPayload, isMiniProgramFileDescriptor, isMiniProgramFileRef, isMiniProgramFileStat, isMiniProgramFileSystemEntityDescriptor, isMiniProgramNativeBinaryChunk, isMiniProgramNativeHostDescription, isMiniProgramNativeHostMessage, isMiniProgramOperationProgressPayload, isMiniProgramPathRootRef, isMiniProgramPermissionKey, isMiniProgramRelativePath, parseMiniProgramRuntimePermissions };