@heybox/hb-sdk 0.9.0-alpha.0 → 0.9.0-alpha.10

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +16 -1
  3. package/dist/cli-chunks/{build-Dv5vWsBh.cjs → build-CT6E9KRd.cjs} +5 -5
  4. package/dist/cli-chunks/{context-B15FzPf9.cjs → context--dJRx4eH.cjs} +2 -2
  5. package/dist/cli-chunks/{create-BtZUsxJd.cjs → create-D6SiqyyQ.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-tAThflC6.cjs → dev-CoWE5lyA.cjs} +228 -19
  7. package/dist/cli-chunks/{doctor-PE_MhGBX.cjs → doctor-IQ5wPkWD.cjs} +1 -1
  8. package/dist/cli-chunks/{index-Dd_eGaDz.cjs → index-CYxcLlON.cjs} +15 -15
  9. package/dist/cli-chunks/{index-CeA8xI0T.cjs → index-CnOLdO_-.cjs} +2 -2
  10. package/dist/cli-chunks/{index.esm-Bw3R5BAL.cjs → index.esm-07KOgDkI.cjs} +7 -7
  11. package/dist/cli-chunks/{login-5FPaFRi0.cjs → login-BszmxuLI.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-ckDtbYtt.cjs → project-vite-tMo1gavS.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-DCHqFvmB.cjs → remote-2oOP8M5C.cjs} +83 -17
  14. package/dist/cli-chunks/{runtime-gate-DkTbgx4d.cjs → runtime-gate-CNBf6Zkh.cjs} +8 -1
  15. package/dist/cli-chunks/{runtime-permission-env-DR89buKQ.cjs → runtime-permission-env-GH_vWEVx.cjs} +86 -57
  16. package/dist/cli-chunks/{session-BiT-5VHK.cjs → session-DrhTp-x-.cjs} +1 -1
  17. package/dist/cli-chunks/{skill-C5EoUf2T.cjs → skill-NfC1c0iQ.cjs} +2 -2
  18. package/dist/cli-chunks/{version-CJ7rfbl-.cjs → version-DA6v9R62.cjs} +1 -1
  19. package/dist/cli.cjs +1 -1
  20. package/dist/devtools/browser-dev-host/assets/browser-dev-host-C3c3yud2.js +102 -0
  21. package/dist/devtools/browser-dev-host/assets/desktop-app-launch-CHZKVQmQ.js +6 -0
  22. package/dist/devtools/browser-dev-host/assets/{index-0Ac39Njs.css → index-B5aFVoao.css} +1 -1
  23. package/dist/devtools/browser-dev-host/assets/{index-B1ZPOArZ.js → index-BmiQPZvl.js} +4 -4
  24. package/dist/devtools/browser-dev-host/index.html +3 -3
  25. package/dist/index.cjs.js +10 -3
  26. package/dist/index.esm.js +10 -3
  27. package/dist/miniapp-publish.cjs.js +121 -57
  28. package/dist/miniapp-publish.esm.js +121 -57
  29. package/dist/vite.cjs.js +33 -4
  30. package/dist/vite.esm.js +33 -4
  31. package/docs/runtime-host-migration.md +3 -1
  32. package/package.json +7 -7
  33. package/skill/skill.json +4 -4
  34. package/types/core/singleton.d.ts +1 -1
  35. package/types/miniapp-manifest/basic-info-browser.d.ts +29 -1
  36. package/types/miniapp-manifest/basic-info.d.ts +23 -2
  37. package/types/miniapp-manifest/category.d.ts +9 -2
  38. package/types/miniapp-manifest/companion-types.d.ts +25 -0
  39. package/types/miniapp-manifest/permissions.d.ts +12 -0
  40. package/types/miniapp-manifest/runtime-gate.d.ts +7 -0
  41. package/types/miniapp-manifest/schema.d.ts +23 -0
  42. package/types/miniapp-publish/index.d.ts +23 -51
  43. package/types/modules/auth/index.d.ts +5 -1
  44. package/types/modules/companion/index.d.ts +27 -34
  45. package/types/modules/navigation/index.d.ts +8 -0
  46. package/types/modules/network/index.d.ts +12 -2
  47. package/types/modules/user/index.d.ts +12 -1
  48. package/types/modules/user/steam-game-list.d.ts +2 -2
  49. package/types/modules/viewport/index.d.ts +21 -1
  50. package/types/vite/index.d.ts +5 -0
  51. package/dist/devtools/browser-dev-host/assets/browser-dev-host-Cu0OUKXf.js +0 -102
  52. package/dist/devtools/browser-dev-host/assets/desktop-app-launch-2BQ4uwPZ.js +0 -6
@@ -1,4 +1,11 @@
1
- /** 校验配置或产物中的类别,省略与显式非法值严格区分。 */
1
+ /**
2
+ * 校验项目配置或产物中的小程序类别。
3
+ *
4
+ * @param value - 待校验值,只接受 `tool`、`game`、`other` 或 `undefined`;不做 trim 或大小写转换。
5
+ * @param sourceLabel - 错误消息中的字段来源,默认 `package.json#heybox.category`。
6
+ * @returns 合法类别原值;输入 `undefined` 时返回 `undefined`,由发布流程另行检查是否必填。
7
+ * @throws `Error` 输入为其他值(包括 null 或空字符串)时抛出带字段来源的错误。
8
+ */
2
9
  function parseMiniappCategory(value, sourceLabel = 'package.json#heybox.category') {
3
10
  if (value === undefined)
4
11
  return undefined;
@@ -2794,7 +2801,14 @@ var semverExports = requireSemver();
2794
2801
 
2795
2802
  const BASIC_INFO_MAX_BYTES = 10 * 1024 * 1024;
2796
2803
  const BASIC_INFO_MAX_PIXELS = 40_000_000;
2797
- /** 按 NFKC 和 Unicode 空白规范化名称,并校验 1–40 个字符及禁用字符。 */
2804
+ /**
2805
+ * 规范化并校验小程序展示名称。
2806
+ *
2807
+ * @param raw - 原始名称,必须是字符串。
2808
+ * @returns NFKC 规范化、去除首尾 Unicode White_Space 后的名称;不折叠规范化后的内部空白。
2809
+ * @throws `Error` 输入不是字符串,或规范化后不是 1–40 个 Unicode code point、不含文字或数字,或包含控制字符、
2810
+ * 格式字符、行/段分隔符以及 HTML 特殊字符 `<`、`>`、`&`、双引号或单引号时抛出。
2811
+ */
2798
2812
  function normalizeBasicInfoName(raw) {
2799
2813
  if (typeof raw !== 'string')
2800
2814
  throw new Error('heybox.name 必须是字符串');
@@ -2815,7 +2829,17 @@ function validateBasicInfoPath(raw) {
2815
2829
  throw new Error('资料图片仅支持 JPEG、PNG、GIF、WebP');
2816
2830
  return raw;
2817
2831
  }
2818
- /** 解析项目或构建资料;仅早于 0.8.2 且三项全部缺失时返回 undefined。 */
2832
+ /**
2833
+ * 校验项目声明或 Manifest 中的小程序展示资料。
2834
+ *
2835
+ * @param value - `package.json#heybox` 或 Manifest 对象,读取 `name`、`icon`、`coverImages`。
2836
+ * @param sdkVersion - 产物 SDK 版本,默认 `0.8.2`;用于判断历史产物是否允许缺失全部资料。
2837
+ * @returns 名称规范化后的新资料对象;仅版本早于 `0.8.2` 且三项均无自有属性时返回 `undefined`。
2838
+ * @throws `Error` SDK 版本非法、资料字段不齐、名称/图片路径非法,或封面不是 1–5 个互不重复的路径时抛出。
2839
+ * @remarks
2840
+ * 图片路径必须使用 `/` 分隔的非空相对路径,扩展名为 JPEG、PNG、GIF 或 WebP;拒绝 URL、点段、
2841
+ * 控制字符和构建/缓存等保留目录。此函数只校验声明,不读取文件,也不验证图片字节、尺寸或存在性。
2842
+ */
2819
2843
  function parseMiniappBasicInfo(value, sdkVersion = '0.8.2') {
2820
2844
  sdkVersion = sdkVersion.trim();
2821
2845
  if (!semverExports.valid(sdkVersion) || sdkVersion.startsWith('v') || sdkVersion.includes('+'))
@@ -3218,6 +3242,16 @@ function validateMiniappManifestVersion(version, sourceLabel = 'manifest.version
3218
3242
  }
3219
3243
  return String(version).trim();
3220
3244
  }
3245
+ /**
3246
+ * 校验发布 Manifest 并返回规范化后的已知字段。
3247
+ *
3248
+ * @param manifest - 从构建产物读取的 Manifest,图片和 Companion 路径相对构建目录。
3249
+ * @returns 新对象:规范化版本、名称、平台与游戏绑定,省略空绑定及未声明的可选字段;不保留未知字段。
3250
+ * @throws `Error` 版本、平台、资料、权限、窗口、游戏绑定或生成的 Companion 声明非法,以及类别缺失时抛出。
3251
+ * @remarks
3252
+ * 不修改输入对象,不执行文件 I/O;不会验证图片/归档是否存在、内容摘要是否匹配,也不查询远端发布资格。
3253
+ * 成功仅表示 Manifest 字段通过校验,不能替代文件检查与服务端发布预检。
3254
+ */
3221
3255
  function validateMiniappManifestForDeploy(manifest) {
3222
3256
  const version = validateMiniappManifestVersion(manifest.version, 'manifest.version');
3223
3257
  const sdkVersion = validateSdkVersion(manifest.sdkVersion, 'manifest.sdkVersion');
@@ -3250,6 +3284,7 @@ function validateGeneratedCompanions(value) {
3250
3284
  return undefined;
3251
3285
  if (!isRecord$1(value) || Object.keys(value).length === 0)
3252
3286
  throw new Error('manifest.companions 必须是非空对象');
3287
+ let descriptorCount = 0;
3253
3288
  for (const [alias, definition] of Object.entries(value)) {
3254
3289
  if (!/^[a-z][a-z0-9-]{0,31}$/.test(alias) ||
3255
3290
  !isRecord$1(definition) ||
@@ -3263,6 +3298,9 @@ function validateGeneratedCompanions(value) {
3263
3298
  Object.keys(definition.targets).length === 0)
3264
3299
  throw new Error(`manifest.companions.${alias} 不合法`);
3265
3300
  for (const [target, artifact] of Object.entries(definition.targets)) {
3301
+ descriptorCount += 1;
3302
+ if (descriptorCount > 64)
3303
+ throw new Error('manifest.companions 最多允许 64 个 target 描述符');
3266
3304
  if (isRecord$1(artifact) && artifact.elevation === 'required') {
3267
3305
  throw new Error(`manifest.companions.${alias}.targets.${target}.elevation V1 仅支持 none,暂不支持管理员权限启动`);
3268
3306
  }
@@ -3550,7 +3588,35 @@ function readBasicInfoImageHeader(bytes) {
3550
3588
  // 脚手架开发占位图;构建可用,提审前必须替换。
3551
3589
  const BASIC_INFO_PLACEHOLDER_SHA256 = 'd14e54b30f5e6d1bcbf51267bc82b06a0af7c333f2945bcc16b4e1adc3b123dd';
3552
3590
 
3553
- /** 只消费构建目录中的字节,不生成或回写 Manifest。返回 URL 的释放由页面负责。 */
3591
+ /**
3592
+ * 在浏览器中校验构建产物的展示资料图片,并创建预览 URL。
3593
+ *
3594
+ * @param manifest - 构建产物 Manifest,必须包含合法的 `sdkVersion`。
3595
+ * @param files - 构建文件列表;`relativePath` 必须精确匹配 Manifest 中的图片路径。
3596
+ * @returns 名称、图标 `icon_url` 和按原顺序排列的 `cover_image_urls`;允许缺失资料的历史产物返回 `undefined`。
3597
+ * @throws `Error` 资料非法、图片缺失/为空/超过 10 MiB、格式与扩展名不符、超过 4000 万像素、
3598
+ * icon 不是 200×200,或仍使用脚手架占位图片时拒绝;浏览器解码和摘要计算失败也会拒绝。
3599
+ * @remarks
3600
+ * 需要浏览器提供 `crypto.subtle`、`createImageBitmap` 和 object URL API;不生成或回写 Manifest。
3601
+ * 失败时会释放本次已创建的 URL;成功后所有 URL 由调用方在预览结束或替换时释放。
3602
+ * @example
3603
+ * ```ts
3604
+ * import { previewMiniappBasicInfo } from '@heybox/hb-sdk/miniapp-publish';
3605
+ *
3606
+ * const preview = await previewMiniappBasicInfo(manifest, files);
3607
+ * if (preview) {
3608
+ * try {
3609
+ * const image = new Image();
3610
+ * image.src = preview.icon_url;
3611
+ * await image.decode();
3612
+ * document.body.append(image);
3613
+ * } finally {
3614
+ * // 已加载的图像可继续显示;不再需要从这些 URL 加载时释放。
3615
+ * [preview.icon_url, ...preview.cover_image_urls].forEach(URL.revokeObjectURL);
3616
+ * }
3617
+ * }
3618
+ * ```
3619
+ */
3554
3620
  async function previewMiniappBasicInfo(manifest, files) {
3555
3621
  const profile = parseMiniappBasicInfo(manifest, String(manifest.sdkVersion ?? ''));
3556
3622
  if (!profile)
@@ -11846,6 +11912,13 @@ function parse(html, options) {
11846
11912
  const RUNTIME_GATE_MARKER = 'data-heybox-runtime-gate';
11847
11913
  const RUNTIME_GATE_STYLE_MARKER = 'data-heybox-runtime-gate-style';
11848
11914
  const RUNTIME_GATE_BOOTSTRAP_MARKER = 'data-heybox-runtime-gate-bootstrap';
11915
+ /**
11916
+ * 检查 HTML 是否包含 Runtime Gate 的三个结构标记。
11917
+ *
11918
+ * @param html - 待检查的完整 HTML 文本,使用 HTML parser 解析。
11919
+ * @returns Gate、隐藏样式及 bootstrap 标记均出现时返回 `true`,否则返回 `false`。
11920
+ * @remarks 只识别标记,不验证脚本内容、标记所在节点或宿主握手;不能据此判断页面安全或实际可运行。
11921
+ */
11849
11922
  function hasMiniappRuntimeGate(html) {
11850
11923
  const document = parse(html);
11851
11924
  let hasGate = false;
@@ -11937,30 +12010,13 @@ const textEncoder = new TextEncoder();
11937
12010
  /**
11938
12011
  * 将扫描到的相对路径转换为统一的 `/` 分隔形式。
11939
12012
  *
11940
- * @param relativePath - 待整理的构建产物路径。TypeScript 入口声明为字符串;JavaScript 运行时会
11941
- * 先计算 `relativePath || ''`,再通过 `String(...)` 强制转换。
11942
- * @returns 仅统一分隔符形态的新字符串:所有 `\\` 转为 `/`,所有前导 `/` 被删除,其余连续
11943
- * `/` 合并为一个。空字符串以及运行时传入的 `undefined`、`null`、`false`、`0`、`NaN` 等
11944
- * falsy 值返回 `''`;truthy 非字符串按标准 `String(value)` 结果继续整理。
12013
+ * @param relativePath - 待整理的构建产物路径。
12014
+ * @returns 反斜杠转为 `/`、删除前导 `/`、合并连续 `/` 后的新字符串;空输入返回空字符串。
11945
12015
  *
11946
12016
  * @remarks
11947
- * 这是面向 build/deploy 文件扫描结果的**格式 helper**,不是路径安全校验或 canonical path
11948
- * parser。它不会 trim、URL decode、Unicode normalize、解析盘符,也不会拒绝或消解 `.` / `..`
11949
- * segment、控制字符、Windows drive prefix 或尾随 `/`。例如 `/etc/passwd` 会变成
11950
- * `etc/passwd`,`C:\\temp\\app.js` 会变成 `C:/temp/app.js`,`assets/../secret/` 仍保留点段
11951
- * 和尾随 slash;调用方不能根据返回值推断原输入是安全相对路径。
11952
- *
11953
- * SDK 的 build/deploy 流程会把扫描路径先用本函数统一分隔符,再分别使用
11954
- * {@link relativePathContainsNodeModulesSegment} 排除完整 `node_modules` 目录段、用
11955
- * {@link shouldUploadDistFile} 过滤根 `manifest.json` / `.DS_Store` / source map。`hb-sdk build`
11956
- * 随后校验大小预算;`hb-sdk remote deploy` 还会在签名和上传前通过
11957
- * `validateUploadPaths()`、`prepareMiniappArtifactFiles()` 或
11958
- * `validateMiniappUploadPathLengths()` 执行真正的空路径、点段、控制字符、重复和长度校验。
11959
- * 这些步骤不能由本函数单独替代;`shouldUploadDistFile()` 也不会自行检查 `node_modules`。
11960
- *
11961
- * 不要把本函数与 `@heybox/hb-sdk/protocol` 的 `isMiniProgramRelativePath()` 混用:协议 guard
11962
- * 不做转换,只接受已经规范的非空字符串,并拒绝前导/尾随 `/`、反斜杠、空 segment、`.`、
11963
- * `..` 与控制字符;本函数则会改写部分非法形态并保留其余不安全内容。
12017
+ * 仅整理文本格式,不做路径安全校验:保留点段、控制字符、盘符和尾随 `/`,不 trim 或 URL decode。
12018
+ * 上传前仍需校验路径安全、唯一性与长度。协议 `isMiniProgramRelativePath()` 则只校验、不改写输入。
12019
+ * JavaScript 非字符串输入按 `String(relativePath || '')` 转换,falsy 值回退为空串。
11964
12020
  *
11965
12021
  * @example
11966
12022
  * ```ts
@@ -11968,8 +12024,6 @@ const textEncoder = new TextEncoder();
11968
12024
  *
11969
12025
  * normalizeRelativePath('///dist\\assets//app.js'); // 'dist/assets/app.js'
11970
12026
  * normalizeRelativePath('assets/../secret///'); // 'assets/../secret/',仍需安全校验
11971
- * normalizeRelativePath(123 as unknown as string); // '123',JavaScript 运行时强制转换
11972
- * normalizeRelativePath(0 as unknown as string); // '',falsy 值先回退为空串
11973
12027
  * ```
11974
12028
  *
11975
12029
  * @see {@link relativePathContainsNodeModulesSegment}
@@ -11985,40 +12039,21 @@ function normalizeRelativePath(relativePath) {
11985
12039
  /**
11986
12040
  * 判断路径中是否包含大小写不敏感的完整 `node_modules` 目录段。
11987
12041
  *
11988
- * @param relativePath - 待检查的构建产物路径。函数先通过 {@link normalizeRelativePath} 把
11989
- * 反斜杠改为 `/`、删除前导 `/` 并合并连续 `/`,再按 `/` 分段。
11990
- * @returns 至少一个非空段大小写不敏感地等于完整 `node_modules` 时返回 `true`;空路径、
11991
- * 空段及 `node_modules.txt`、`node_modules-old`、`@node_modules` 等相似名称返回 `false`。
12042
+ * @param relativePath - 构建产物路径,先按 {@link normalizeRelativePath} 整理分隔符再分段比较。
12043
+ * @returns 任意目录段大小写不敏感地等于 `node_modules` 时返回 `true`;空路径和相似名称返回 `false`。
11992
12044
  *
11993
12045
  * @remarks
11994
- * 比较使用每个非空 segment 的 `toLowerCase() === 'node_modules'`,因此根目录或任意深度的
11995
- * `node_modules`、`NODE_MODULES`、`Node_Modules` 都会命中。前导和重复 slash 会先被
11996
- * `normalizeRelativePath` 整理;尾随 slash 产生的空段会被忽略。
11997
- *
11998
- * 这是同步、无副作用的**单一 predicate**,只回答“规范化后的文本是否包含该完整段”。它
11999
- * 不 trim segment、不进行 URL/percent decode、Unicode normalize 或文件系统解析。例如
12000
- * `node_modules%2Fpkg/index.js`、`%6eode_modules/pkg.js` 和 `node_modules.txt` 都不会命中;调用方
12001
- * 不应传 URL,也不能把未命中解释为路径安全。
12002
- *
12003
- * 本函数不会拒绝或消解 `.` / `..`、绝对路径、Windows drive prefix、控制字符、空路径、
12004
- * symlink、重复路径或超长路径。`assets/../node_modules/pkg.js` 仍会命中,因为点段保持原样;
12005
- * 不含 `node_modules` 的危险路径则仍可能返回 `false`。签名或上传前必须继续执行对应的上传
12006
- * 路径规范、唯一性和长度校验。
12007
- *
12008
- * SDK build/deploy 会在文件扫描后用本函数拒绝整个 `node_modules` 树,再用
12009
- * {@link shouldUploadDistFile} 排除根 `manifest.json`、`.DS_Store` 和 source map。build 随后
12010
- * 校验大小预算;deploy 还会执行上传路径安全、唯一性、长度与签名校验。这些步骤互不替代:`shouldUploadDistFile()` 本身不检查
12011
- * `node_modules`,本函数也不决定普通文件是否应该上传。
12046
+ * 只检查目录段文本,不 trim、URL decode 或解析文件系统。未命中不表示路径安全;点段仍保留。
12047
+ * SDK 用它排除 `node_modules` 树,再用 {@link shouldUploadDistFile} 过滤其他不上传的文件;
12048
+ * 路径安全、唯一性、长度与上传大小需分别校验。
12012
12049
  *
12013
12050
  * @example
12014
12051
  * ```ts
12015
12052
  * import { relativePathContainsNodeModulesSegment } from '@heybox/hb-sdk/miniapp-publish';
12016
12053
  *
12017
12054
  * relativePathContainsNodeModulesSegment('dist\\NODE_MODULES/pkg/index.js'); // true
12018
- * relativePathContainsNodeModulesSegment('dist//vendor///node_modules/'); // true
12019
12055
  * relativePathContainsNodeModulesSegment('dist/node_modules.txt'); // false
12020
12056
  * relativePathContainsNodeModulesSegment('dist/node_modules%2Fpkg.js'); // false,不做 URL decode
12021
- * relativePathContainsNodeModulesSegment('assets/../secret.js'); // false,但这不代表路径安全
12022
12057
  * ```
12023
12058
  *
12024
12059
  * @see [normalizeRelativePath](/reference/symbols/miniapp-publish/functions/normalizeRelativePath)
@@ -12398,8 +12433,9 @@ function createMiniappArtifactFileHeader(file) {
12398
12433
  * 校验服务端 session 文件映射,并计算仍需上传的文件。
12399
12434
  *
12400
12435
  * @param localFiles - 本地构建产物 receipt;除 `relativePath` 和 `size` 外,每项必须包含 64 位小写十六进制 `sha256`。
12401
- * @param serverFiles - 服务端签发的文件映射;数量、路径、大小和 SHA-256 必须与本地产物一一一致。
12436
+ * @param serverFiles - 服务端签发的会话文件映射;与复用的 Companion 合起来必须覆盖本地产物。
12402
12437
  * @param uploadedKeys - 服务端已确认上传成功的 key;每个值都必须属于当前会话,重复值会被去重。
12438
+ * @param reusedCompanionFiles - 已验证 Blob 引用;仅允许当前产物中的 Companion 文件。
12403
12439
  * @returns
12404
12440
  * 包含三个字段的对象:`files` 是按路径 UTF-8 字节序排列的全部 `{ file, key }` 映射,
12405
12441
  * `missingFiles` 是其中尚未确认上传的映射,`uploadedKeys` 是去重后的已上传 key。
@@ -12415,15 +12451,38 @@ function createMiniappArtifactFileHeader(file) {
12415
12451
  * sha256: 'a'.repeat(64),
12416
12452
  * }],
12417
12453
  * [],
12454
+ * [],
12418
12455
  * );
12419
12456
  *
12420
12457
  * console.log(resolved.missingFiles.length); // 1
12421
12458
  * ```
12422
12459
  */
12423
- function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys) {
12460
+ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys, reusedCompanionFiles) {
12424
12461
  const preparedFiles = prepareMiniappArtifactFiles(localFiles);
12425
- if (serverFiles.length !== preparedFiles.length) {
12426
- throw new Error(`上传会话文件数量异常:期望 ${preparedFiles.length},实际 ${serverFiles.length}`);
12462
+ if (serverFiles.length + reusedCompanionFiles.length !== preparedFiles.length) {
12463
+ throw new Error(`上传会话文件数量异常:期望 ${preparedFiles.length},实际 ${serverFiles.length + reusedCompanionFiles.length}`);
12464
+ }
12465
+ const localByPath = new Map(preparedFiles.map((file) => [file.relativePath, file]));
12466
+ const reused = new Map();
12467
+ for (const reference of reusedCompanionFiles) {
12468
+ const relativePath = normalizeMiniappArtifactRelativePath(reference.relative_path);
12469
+ const local = localByPath.get(relativePath);
12470
+ if (!relativePath.startsWith('companions/') || !local) {
12471
+ throw new Error(`上传会话返回了不属于当前 Companion 产物的 Blob 引用:${relativePath}`);
12472
+ }
12473
+ if (reused.has(relativePath)) {
12474
+ throw new Error(`上传会话返回重复 Blob 引用:${relativePath}`);
12475
+ }
12476
+ if (!Number.isSafeInteger(reference.size) || reference.size < 0 || reference.size !== local.size) {
12477
+ throw new Error(`上传会话 Blob 文件大小与本地构建不一致:${relativePath}`);
12478
+ }
12479
+ if (!('sha256' in local) || !/^[a-f0-9]{64}$/.test(reference.sha256) || reference.sha256 !== local.sha256) {
12480
+ throw new Error(`上传会话 Blob 文件 SHA-256 与本地构建不一致:${relativePath}`);
12481
+ }
12482
+ if (typeof reference.blob_id !== 'string' || !reference.blob_id.trim()) {
12483
+ throw new Error(`上传会话 Blob 引用 ID 无效:${relativePath}`);
12484
+ }
12485
+ reused.set(relativePath, reference);
12427
12486
  }
12428
12487
  const mappings = new Map();
12429
12488
  const serverSizes = new Map();
@@ -12434,6 +12493,9 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
12434
12493
  if (mappings.has(relativePath)) {
12435
12494
  throw new Error(`上传会话返回重复文件路径:${relativePath}`);
12436
12495
  }
12496
+ if (reused.has(relativePath)) {
12497
+ throw new Error(`上传会话同时返回文件 key 和 Blob 引用:${relativePath}`);
12498
+ }
12437
12499
  const key = String(serverFile.key || '');
12438
12500
  if (!key) {
12439
12501
  throw new Error(`上传会话未返回文件 key:${relativePath}`);
@@ -12454,7 +12516,8 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
12454
12516
  serverHashes.set(relativePath, sha256);
12455
12517
  knownKeys.add(key);
12456
12518
  }
12457
- const files = preparedFiles.map((file) => {
12519
+ const sessionFiles = preparedFiles.filter((file) => !reused.has(file.relativePath));
12520
+ const files = sessionFiles.map((file) => {
12458
12521
  const key = mappings.get(file.relativePath);
12459
12522
  if (!key) {
12460
12523
  throw new Error(`上传会话缺少文件映射:${file.relativePath}`);
@@ -12479,6 +12542,7 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
12479
12542
  files,
12480
12543
  missingFiles: files.filter((file) => !completed.has(file.key)),
12481
12544
  uploadedKeys: [...completed],
12545
+ reusedCompanionFiles: [...reused.values()],
12482
12546
  };
12483
12547
  }
12484
12548
  /**
package/dist/vite.cjs.js CHANGED
@@ -2797,7 +2797,14 @@ var semverExports = requireSemver();
2797
2797
 
2798
2798
  const BASIC_INFO_MAX_BYTES = 10 * 1024 * 1024;
2799
2799
  const BASIC_INFO_MAX_PIXELS = 40_000_000;
2800
- /** 按 NFKC 和 Unicode 空白规范化名称,并校验 1–40 个字符及禁用字符。 */
2800
+ /**
2801
+ * 规范化并校验小程序展示名称。
2802
+ *
2803
+ * @param raw - 原始名称,必须是字符串。
2804
+ * @returns NFKC 规范化、去除首尾 Unicode White_Space 后的名称;不折叠规范化后的内部空白。
2805
+ * @throws `Error` 输入不是字符串,或规范化后不是 1–40 个 Unicode code point、不含文字或数字,或包含控制字符、
2806
+ * 格式字符、行/段分隔符以及 HTML 特殊字符 `<`、`>`、`&`、双引号或单引号时抛出。
2807
+ */
2801
2808
  function normalizeBasicInfoName(raw) {
2802
2809
  if (typeof raw !== 'string')
2803
2810
  throw new Error('heybox.name 必须是字符串');
@@ -2818,7 +2825,17 @@ function validateBasicInfoPath(raw) {
2818
2825
  throw new Error('资料图片仅支持 JPEG、PNG、GIF、WebP');
2819
2826
  return raw;
2820
2827
  }
2821
- /** 解析项目或构建资料;仅早于 0.8.2 且三项全部缺失时返回 undefined。 */
2828
+ /**
2829
+ * 校验项目声明或 Manifest 中的小程序展示资料。
2830
+ *
2831
+ * @param value - `package.json#heybox` 或 Manifest 对象,读取 `name`、`icon`、`coverImages`。
2832
+ * @param sdkVersion - 产物 SDK 版本,默认 `0.8.2`;用于判断历史产物是否允许缺失全部资料。
2833
+ * @returns 名称规范化后的新资料对象;仅版本早于 `0.8.2` 且三项均无自有属性时返回 `undefined`。
2834
+ * @throws `Error` SDK 版本非法、资料字段不齐、名称/图片路径非法,或封面不是 1–5 个互不重复的路径时抛出。
2835
+ * @remarks
2836
+ * 图片路径必须使用 `/` 分隔的非空相对路径,扩展名为 JPEG、PNG、GIF 或 WebP;拒绝 URL、点段、
2837
+ * 控制字符和构建/缓存等保留目录。此函数只校验声明,不读取文件,也不验证图片字节、尺寸或存在性。
2838
+ */
2822
2839
  function parseMiniappBasicInfo(value, sdkVersion = '0.8.2') {
2823
2840
  sdkVersion = sdkVersion.trim();
2824
2841
  if (!semverExports.valid(sdkVersion) || sdkVersion.startsWith('v') || sdkVersion.includes('+'))
@@ -2948,7 +2965,7 @@ async function ensureBasicInfoDirectory(rootPath, relative) {
2948
2965
  /** 构建时替换为当前发布包的实际版本。 */
2949
2966
  const HB_SDK_VERSION = typeof undefined === 'string'
2950
2967
  ? undefined
2951
- : '0.9.0-alpha.0';
2968
+ : '0.9.0-alpha.10';
2952
2969
 
2953
2970
  /**
2954
2971
  * iframe 与调试台页面的开发期 console 捕获转发。
@@ -3350,7 +3367,14 @@ function parseMiniappBindAppIds(value, options = {}) {
3350
3367
  return Object.freeze(appIds);
3351
3368
  }
3352
3369
 
3353
- /** 校验配置或产物中的类别,省略与显式非法值严格区分。 */
3370
+ /**
3371
+ * 校验项目配置或产物中的小程序类别。
3372
+ *
3373
+ * @param value - 待校验值,只接受 `tool`、`game`、`other` 或 `undefined`;不做 trim 或大小写转换。
3374
+ * @param sourceLabel - 错误消息中的字段来源,默认 `package.json#heybox.category`。
3375
+ * @returns 合法类别原值;输入 `undefined` 时返回 `undefined`,由发布流程另行检查是否必填。
3376
+ * @throws `Error` 输入为其他值(包括 null 或空字符串)时抛出带字段来源的错误。
3377
+ */
3354
3378
  function parseMiniappCategory(value, sourceLabel = 'package.json#heybox.category') {
3355
3379
  if (value === undefined)
3356
3380
  return undefined;
@@ -13339,6 +13363,7 @@ const devSnapshotStores = devSnapshotRegistry[devSnapshotStoreKey];
13339
13363
  * 不符合小程序 HTML 策略时,`transformIndexHtml` / 生产产物复检抛出。
13340
13364
  * @throws `Error` 生产构建无法读取或解析最近的 `package.json`,`version`、`heybox.platforms`、
13341
13365
  * `heybox.permissions`、`heybox.window`、`heybox.bindAppIds` 或 `heybox.companions` 声明非法时抛出。
13366
+ * @throws `Error` 展示资料缺失、名称/图片路径非法、图片无法解码或不符合大小/尺寸约束,或类别非法时抛出。
13342
13367
  * @throws `Error` 生产 `build.outDir` 缺少根 `index.html`、递归发现额外 HTML,或 Companion 权限、
13343
13368
  * 目标平台、来源目录、归档结构、入口二进制不符合约束时抛出;更早的 Rollup/Vite 错误会原样优先重抛。
13344
13369
  *
@@ -13349,6 +13374,10 @@ const devSnapshotStores = devSnapshotRegistry[devSnapshotStoreKey];
13349
13374
  *
13350
13375
  * - `version`:发布版本;trim 后必须是完整 SemVer,可含 prerelease,不允许 build metadata 或模板值
13351
13376
  * `0.0.0`;
13377
+ * - `heybox.name`、`heybox.icon`、`heybox.coverImages`:SDK `0.8.2` 起须完整提供的展示资料。
13378
+ * 图片源路径相对项目目录;icon 为 200×200,封面 1–5 张,每张不超过 10 MiB / 4000 万像素。
13379
+ * build 会复制图片到输出目录 `_hb/basic-info/`,并将 Manifest 路径改为生成路径,不改写源图片;
13380
+ * - `heybox.category`:`tool`、`game` 或 `other`;构建时允许缺省,发布预检要求提供;
13352
13381
  * - `heybox.platforms`:项目实际承诺适配的非空、无重复平台 allowlist;输出按平台词表规范排序。
13353
13382
  * 声明仍停留在旧模板移动端默认(`android`、`ios`、`ohos`)时,`serve` 与 `build` 都只输出
13354
13383
  * 一条非阻断提示,不影响构建结果;
package/dist/vite.esm.js CHANGED
@@ -2794,7 +2794,14 @@ var semverExports = requireSemver();
2794
2794
 
2795
2795
  const BASIC_INFO_MAX_BYTES = 10 * 1024 * 1024;
2796
2796
  const BASIC_INFO_MAX_PIXELS = 40_000_000;
2797
- /** 按 NFKC 和 Unicode 空白规范化名称,并校验 1–40 个字符及禁用字符。 */
2797
+ /**
2798
+ * 规范化并校验小程序展示名称。
2799
+ *
2800
+ * @param raw - 原始名称,必须是字符串。
2801
+ * @returns NFKC 规范化、去除首尾 Unicode White_Space 后的名称;不折叠规范化后的内部空白。
2802
+ * @throws `Error` 输入不是字符串,或规范化后不是 1–40 个 Unicode code point、不含文字或数字,或包含控制字符、
2803
+ * 格式字符、行/段分隔符以及 HTML 特殊字符 `<`、`>`、`&`、双引号或单引号时抛出。
2804
+ */
2798
2805
  function normalizeBasicInfoName(raw) {
2799
2806
  if (typeof raw !== 'string')
2800
2807
  throw new Error('heybox.name 必须是字符串');
@@ -2815,7 +2822,17 @@ function validateBasicInfoPath(raw) {
2815
2822
  throw new Error('资料图片仅支持 JPEG、PNG、GIF、WebP');
2816
2823
  return raw;
2817
2824
  }
2818
- /** 解析项目或构建资料;仅早于 0.8.2 且三项全部缺失时返回 undefined。 */
2825
+ /**
2826
+ * 校验项目声明或 Manifest 中的小程序展示资料。
2827
+ *
2828
+ * @param value - `package.json#heybox` 或 Manifest 对象,读取 `name`、`icon`、`coverImages`。
2829
+ * @param sdkVersion - 产物 SDK 版本,默认 `0.8.2`;用于判断历史产物是否允许缺失全部资料。
2830
+ * @returns 名称规范化后的新资料对象;仅版本早于 `0.8.2` 且三项均无自有属性时返回 `undefined`。
2831
+ * @throws `Error` SDK 版本非法、资料字段不齐、名称/图片路径非法,或封面不是 1–5 个互不重复的路径时抛出。
2832
+ * @remarks
2833
+ * 图片路径必须使用 `/` 分隔的非空相对路径,扩展名为 JPEG、PNG、GIF 或 WebP;拒绝 URL、点段、
2834
+ * 控制字符和构建/缓存等保留目录。此函数只校验声明,不读取文件,也不验证图片字节、尺寸或存在性。
2835
+ */
2819
2836
  function parseMiniappBasicInfo(value, sdkVersion = '0.8.2') {
2820
2837
  sdkVersion = sdkVersion.trim();
2821
2838
  if (!semverExports.valid(sdkVersion) || sdkVersion.startsWith('v') || sdkVersion.includes('+'))
@@ -2945,7 +2962,7 @@ async function ensureBasicInfoDirectory(rootPath, relative) {
2945
2962
  /** 构建时替换为当前发布包的实际版本。 */
2946
2963
  const HB_SDK_VERSION = typeof undefined === 'string'
2947
2964
  ? undefined
2948
- : '0.9.0-alpha.0';
2965
+ : '0.9.0-alpha.10';
2949
2966
 
2950
2967
  /**
2951
2968
  * iframe 与调试台页面的开发期 console 捕获转发。
@@ -3347,7 +3364,14 @@ function parseMiniappBindAppIds(value, options = {}) {
3347
3364
  return Object.freeze(appIds);
3348
3365
  }
3349
3366
 
3350
- /** 校验配置或产物中的类别,省略与显式非法值严格区分。 */
3367
+ /**
3368
+ * 校验项目配置或产物中的小程序类别。
3369
+ *
3370
+ * @param value - 待校验值,只接受 `tool`、`game`、`other` 或 `undefined`;不做 trim 或大小写转换。
3371
+ * @param sourceLabel - 错误消息中的字段来源,默认 `package.json#heybox.category`。
3372
+ * @returns 合法类别原值;输入 `undefined` 时返回 `undefined`,由发布流程另行检查是否必填。
3373
+ * @throws `Error` 输入为其他值(包括 null 或空字符串)时抛出带字段来源的错误。
3374
+ */
3351
3375
  function parseMiniappCategory(value, sourceLabel = 'package.json#heybox.category') {
3352
3376
  if (value === undefined)
3353
3377
  return undefined;
@@ -13336,6 +13360,7 @@ const devSnapshotStores = devSnapshotRegistry[devSnapshotStoreKey];
13336
13360
  * 不符合小程序 HTML 策略时,`transformIndexHtml` / 生产产物复检抛出。
13337
13361
  * @throws `Error` 生产构建无法读取或解析最近的 `package.json`,`version`、`heybox.platforms`、
13338
13362
  * `heybox.permissions`、`heybox.window`、`heybox.bindAppIds` 或 `heybox.companions` 声明非法时抛出。
13363
+ * @throws `Error` 展示资料缺失、名称/图片路径非法、图片无法解码或不符合大小/尺寸约束,或类别非法时抛出。
13339
13364
  * @throws `Error` 生产 `build.outDir` 缺少根 `index.html`、递归发现额外 HTML,或 Companion 权限、
13340
13365
  * 目标平台、来源目录、归档结构、入口二进制不符合约束时抛出;更早的 Rollup/Vite 错误会原样优先重抛。
13341
13366
  *
@@ -13346,6 +13371,10 @@ const devSnapshotStores = devSnapshotRegistry[devSnapshotStoreKey];
13346
13371
  *
13347
13372
  * - `version`:发布版本;trim 后必须是完整 SemVer,可含 prerelease,不允许 build metadata 或模板值
13348
13373
  * `0.0.0`;
13374
+ * - `heybox.name`、`heybox.icon`、`heybox.coverImages`:SDK `0.8.2` 起须完整提供的展示资料。
13375
+ * 图片源路径相对项目目录;icon 为 200×200,封面 1–5 张,每张不超过 10 MiB / 4000 万像素。
13376
+ * build 会复制图片到输出目录 `_hb/basic-info/`,并将 Manifest 路径改为生成路径,不改写源图片;
13377
+ * - `heybox.category`:`tool`、`game` 或 `other`;构建时允许缺省,发布预检要求提供;
13349
13378
  * - `heybox.platforms`:项目实际承诺适配的非空、无重复平台 allowlist;输出按平台词表规范排序。
13350
13379
  * 声明仍停留在旧模板移动端默认(`android`、`ios`、`ohos`)时,`serve` 与 `build` 都只输出
13351
13380
  * 一条非阻断提示,不影响构建结果;
@@ -89,12 +89,14 @@ Storage 面板只通过 `runtime.diagnostics.storage?.getSnapshot()` 读取 Runt
89
89
  | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
90
90
  | Browser Dev Host | 私有 WebSocket channel 优先,HTTP/SSE 保留为兼容路径。账号 identity 的 canonical 读取仍由 HTTP session status 完成;channel 只发 revision hint,收到 hint 后重新读取 HTTP 状态。 | WebSocket 握手、重连或消息失败不阻断 Browser Mock;回退 HTTP/SSE 并继续有界轮询。 |
91
91
  | Mobile Release | 当前稳定客户端继续把原生 `mini_url` launch 交给详情 H5/Native Host;二维码保持 HTTPS `open_inapp` 与 `heybox://` `openWindow`,但短链这一跳是普通 H5。跳转页打开完整 sandbox query(`mini_url`、身份、启动票和 LAN Dev Context)后延迟 `closeWindow`。真机 WebView 基址是 `http://127.0.0.1` 详情页且 HTML 来自线上缓存。 | 生成真机二维码前仍需 CLI 登录、项目绑定和有效 Dev Context;这些条件不阻断 Browser 调试台启动。 |
92
- | Mobile Debug/Ad-Hoc H5 | `dev_context_url` 是可选的 Dev Session 输入;Runtime 权限和本地 network proxy 仅在读取成功时采用。 | Dev Context 缺失、过期、不可达或校验失败时记录脱敏诊断,继续使用原生 Host 的账号、网络与远端权限。 |
92
+ | Mobile Debug/Ad-Hoc H5 | `dev_context_url` 是可选的 Dev Session 输入;读取成功后采用本地 network proxy,代理不参与 Runtime 权限判断。 | Dev Context 缺失、过期、不可达或校验失败时记录脱敏诊断,继续使用原生 Host 的账号、网络与远端权限。 |
93
93
 
94
94
  `DevSession` 同时携带本地声明、独立的 `local_dev_grant` 与 context revision,不会反向修改线上配置。真实 H5 必须先以启动票取得 canonical identity,再将可信线上基线与声明及严格解析的 grant 合成普通 Runtime 快照;没有有效票据或非法 grant 时不临时放权。临时授权仅允许 `network` / `companion`,不包含 `useOfficialDomain`,且每次启动由用户确认。
95
95
 
96
96
  Node 负责 CLI-owned stable context endpoint、短跳转 registry 和 Launch Reference 生命周期;H5 负责持续验证 CLI lease,不能用 iframe heartbeat 代替。连续失联约 30 秒、到期、session/revision 或 Companion 摘要变化时销毁旧 Runtime;重连重新确认和创建实例。票据字符串轮换不改变授权指纹。线上权限快照在 Runtime 内不可变,临时权限来源不传给 iframe。Android、iOS 与新 PC 原生 adapter 沿用既有 operation;真实 PC Companion 还必须有私有 local-dev lease capability,缺能力继续 fail closed。
97
97
 
98
+ 真机公开 `network.request` 使用 Dev Context 下的 `/network` 转发。代理生命周期仅由 CLI dev server 管理,不另设激活、续租、撤销、权限或授权指纹检查。代理不判断黑盒域名,不注入或剥离应用层凭据,只处理 HTTP 传输头、超时、取消和大小限制,并保留上游重定向响应。Runtime 私有请求、`network.download` 和正式版本继续使用原生 adapter。
99
+
98
100
  多网卡环境中,CLI 从可用私有 IPv4 网卡派生候选 `mini_url`,并优先展示与 HMR 默认地址匹配的候选。用户切换网卡后,`mini_url` 和 Dev Context URL 都投影到同一选中地址。`dev_context_url` 必须嵌套在 `heybox-mini-dev://sandbox` 的 query 中,不能误放到最外层 `openWindow` payload。
99
101
 
100
102
  ## Mobile 短跳转安全边界
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heybox/hb-sdk",
3
- "version": "0.9.0-alpha.0",
3
+ "version": "0.9.0-alpha.10",
4
4
  "sideEffects": [
5
5
  "./src/index.ts",
6
6
  "./src/core/singleton.ts",
@@ -65,7 +65,7 @@
65
65
  "undici": "^7.28.0",
66
66
  "ws": "^8.18.0",
67
67
  "sharp": "^0.34.5",
68
- "@heybox/hb-sdk-protocol": "0.9.0-alpha.0"
68
+ "@heybox/hb-sdk-protocol": "0.9.0-alpha.10"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "vite": ">=5"
@@ -116,13 +116,13 @@
116
116
  "vue-tsc": "^3.3.7",
117
117
  "vite": "^8.0.12",
118
118
  "vitest": "^3.2.4",
119
- "@heybox/hb-sdk-runtime": "~0.9.0-alpha.0",
120
119
  "@heybox-domain/heybox-theme": "~0.1.0",
121
120
  "@heybox-domain/heybox-vue3-ui": "~0.1.0",
122
- "@heybox/hb-api": "~1.28.9",
123
- "@heybox/runtime": "~0.2.0",
124
- "@heybox/runtime-policy": "~0.2.0",
125
- "@heybox/runtime-transport-fetch": "~0.2.0"
121
+ "@heybox/hb-api": "~1.28.10",
122
+ "@heybox/hb-sdk-runtime": "~0.9.0-alpha.10",
123
+ "@heybox/runtime": "~0.2.1",
124
+ "@heybox/runtime-policy": "~0.2.1",
125
+ "@heybox/runtime-transport-fetch": "~0.2.1"
126
126
  },
127
127
  "publishConfig": {
128
128
  "registry": "https://registry.npmjs.org/",
package/skill/skill.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "hb-sdk",
3
- "skillVersion": "0.9.0-alpha.0+skill.aa24d6656331",
3
+ "skillVersion": "0.9.0-alpha.10+skill.aa24d6656331",
4
4
  "sdk": {
5
5
  "package": "@heybox/hb-sdk",
6
- "version": "0.9.0-alpha.0",
7
- "compatibility": "0.9.0-alpha.0"
6
+ "version": "0.9.0-alpha.10",
7
+ "compatibility": "0.9.0-alpha.10"
8
8
  },
9
9
  "distribution": {
10
10
  "type": "npm",
11
11
  "package": "@heybox/hb-sdk",
12
- "version": "0.9.0-alpha.0",
12
+ "version": "0.9.0-alpha.10",
13
13
  "path": "skill"
14
14
  },
15
15
  "integrity": "sha256-aa24d6656331cbad8f6aae7735258a49d7f1a82f6e900415de53a1b93a30ddb8"
@@ -205,7 +205,7 @@ export declare function onHandshakeStateChange(handler: MiniProgramSDKHandshakeS
205
205
  * - `heybox_app_login_change`:`{ isHeyboxAppLoggedIn }`;
206
206
  * - `user_info_authorization_change`:
207
207
  * [UserInfoAuthorization](/reference/symbols/root/interfaces/UserInfoAuthorization),包含 `identity` 与
208
- * `profile` 两项授权状态;
208
+ * `profile` 两项授权状态,支持 Steam 账号能力时还可能包含 `steam_account`;
209
209
  * - `companion.session.output`:`{ sessionId, controllerGeneration, stream, sequence, data }`;
210
210
  * - `companion.session.exit`:`{ sessionId, exit }`;
211
211
  * - `companion.session.ownershipLost`:`{ sessionId, controllerGeneration }`。
@@ -1,4 +1,32 @@
1
- /** 只消费构建目录中的字节,不生成或回写 Manifest。返回 URL 的释放由页面负责。 */
1
+ /**
2
+ * 在浏览器中校验构建产物的展示资料图片,并创建预览 URL。
3
+ *
4
+ * @param manifest - 构建产物 Manifest,必须包含合法的 `sdkVersion`。
5
+ * @param files - 构建文件列表;`relativePath` 必须精确匹配 Manifest 中的图片路径。
6
+ * @returns 名称、图标 `icon_url` 和按原顺序排列的 `cover_image_urls`;允许缺失资料的历史产物返回 `undefined`。
7
+ * @throws `Error` 资料非法、图片缺失/为空/超过 10 MiB、格式与扩展名不符、超过 4000 万像素、
8
+ * icon 不是 200×200,或仍使用脚手架占位图片时拒绝;浏览器解码和摘要计算失败也会拒绝。
9
+ * @remarks
10
+ * 需要浏览器提供 `crypto.subtle`、`createImageBitmap` 和 object URL API;不生成或回写 Manifest。
11
+ * 失败时会释放本次已创建的 URL;成功后所有 URL 由调用方在预览结束或替换时释放。
12
+ * @example
13
+ * ```ts
14
+ * import { previewMiniappBasicInfo } from '@heybox/hb-sdk/miniapp-publish';
15
+ *
16
+ * const preview = await previewMiniappBasicInfo(manifest, files);
17
+ * if (preview) {
18
+ * try {
19
+ * const image = new Image();
20
+ * image.src = preview.icon_url;
21
+ * await image.decode();
22
+ * document.body.append(image);
23
+ * } finally {
24
+ * // 已加载的图像可继续显示;不再需要从这些 URL 加载时释放。
25
+ * [preview.icon_url, ...preview.cover_image_urls].forEach(URL.revokeObjectURL);
26
+ * }
27
+ * }
28
+ * ```
29
+ */
2
30
  export declare function previewMiniappBasicInfo(manifest: Record<string, unknown>, files: readonly {
3
31
  relativePath: string;
4
32
  file: Blob;
@@ -1,12 +1,33 @@
1
1
  export declare const BASIC_INFO_MAX_BYTES: number;
2
2
  export declare const BASIC_INFO_MAX_PIXELS = 40000000;
3
+ /** 小程序展示资料;项目声明和构建产物使用相同字段,图片路径的根目录不同。 */
3
4
  export interface MiniappBasicInfo {
5
+ /** NFKC 规范化并移除首尾 Unicode 空白后的名称,长度为 1–40 个 Unicode code point。 */
4
6
  name: string;
7
+ /** 图标的规范相对路径;项目声明相对项目目录,Manifest 相对构建目录。 */
5
8
  icon: string;
9
+ /** 1–5 个互不重复的封面相对路径,按展示顺序排列。 */
6
10
  coverImages: string[];
7
11
  }
8
- /** 按 NFKC 和 Unicode 空白规范化名称,并校验 1–40 个字符及禁用字符。 */
12
+ /**
13
+ * 规范化并校验小程序展示名称。
14
+ *
15
+ * @param raw - 原始名称,必须是字符串。
16
+ * @returns NFKC 规范化、去除首尾 Unicode White_Space 后的名称;不折叠规范化后的内部空白。
17
+ * @throws `Error` 输入不是字符串,或规范化后不是 1–40 个 Unicode code point、不含文字或数字,或包含控制字符、
18
+ * 格式字符、行/段分隔符以及 HTML 特殊字符 `<`、`>`、`&`、双引号或单引号时抛出。
19
+ */
9
20
  export declare function normalizeBasicInfoName(raw: unknown): string;
10
21
  export declare function validateBasicInfoPath(raw: unknown): string;
11
- /** 解析项目或构建资料;仅早于 0.8.2 且三项全部缺失时返回 undefined。 */
22
+ /**
23
+ * 校验项目声明或 Manifest 中的小程序展示资料。
24
+ *
25
+ * @param value - `package.json#heybox` 或 Manifest 对象,读取 `name`、`icon`、`coverImages`。
26
+ * @param sdkVersion - 产物 SDK 版本,默认 `0.8.2`;用于判断历史产物是否允许缺失全部资料。
27
+ * @returns 名称规范化后的新资料对象;仅版本早于 `0.8.2` 且三项均无自有属性时返回 `undefined`。
28
+ * @throws `Error` SDK 版本非法、资料字段不齐、名称/图片路径非法,或封面不是 1–5 个互不重复的路径时抛出。
29
+ * @remarks
30
+ * 图片路径必须使用 `/` 分隔的非空相对路径,扩展名为 JPEG、PNG、GIF 或 WebP;拒绝 URL、点段、
31
+ * 控制字符和构建/缓存等保留目录。此函数只校验声明,不读取文件,也不验证图片字节、尺寸或存在性。
32
+ */
12
33
  export declare function parseMiniappBasicInfo(value: Record<string, unknown>, sdkVersion?: string): MiniappBasicInfo | undefined;
@@ -1,4 +1,11 @@
1
- /** 小程序发布类别;新上传版本必须声明,历史产物读取允许缺省。 */
1
+ /** 小程序发布类别:`tool` 为工具、`game` 为游戏、`other` 为其他;新上传版本必须声明,历史读取可缺省。 */
2
2
  export type MiniappCategory = 'tool' | 'game' | 'other';
3
- /** 校验配置或产物中的类别,省略与显式非法值严格区分。 */
3
+ /**
4
+ * 校验项目配置或产物中的小程序类别。
5
+ *
6
+ * @param value - 待校验值,只接受 `tool`、`game`、`other` 或 `undefined`;不做 trim 或大小写转换。
7
+ * @param sourceLabel - 错误消息中的字段来源,默认 `package.json#heybox.category`。
8
+ * @returns 合法类别原值;输入 `undefined` 时返回 `undefined`,由发布流程另行检查是否必填。
9
+ * @throws `Error` 输入为其他值(包括 null 或空字符串)时抛出带字段来源的错误。
10
+ */
4
11
  export declare function parseMiniappCategory(value: unknown, sourceLabel?: string): MiniappCategory | undefined;