@heybox/hb-sdk 0.9.2-alpha.6 → 0.9.2-alpha.8
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/CHANGELOG.md +22 -0
- package/README.md +4 -2
- package/dist/cli-chunks/{build-ffQNXsFk.cjs → build-BinntZJf.cjs} +5 -5
- package/dist/cli-chunks/{context-DlFt5Q7p.cjs → context-BI3QMxw2.cjs} +2 -2
- package/dist/cli-chunks/{create-BtmA7deR.cjs → create-BK028Mlk.cjs} +1 -1
- package/dist/cli-chunks/deploy-lock-pKDDxTKm.cjs +148 -0
- package/dist/cli-chunks/{dev-CNDIlDmL.cjs → dev-DeNzUY6g.cjs} +75 -66
- package/dist/cli-chunks/{doctor-BkFUZH17.cjs → doctor-BOfbKnN2.cjs} +1 -1
- package/dist/cli-chunks/games-yqu20laX.cjs +140 -0
- package/dist/cli-chunks/{index-DrlSotEe.cjs → index-C7nrP0tt.cjs} +1 -1
- package/dist/cli-chunks/{index-CN_l895H.cjs → index-CY67PpQk.cjs} +35 -16
- package/dist/cli-chunks/{index.esm-mmJekGrr.cjs → index.esm-DQdwzMhB.cjs} +6 -6
- package/dist/cli-chunks/{login-qupR7tLT.cjs → login-PJdMmFoB.cjs} +1 -1
- package/dist/cli-chunks/{project-vite-CNubrzp5.cjs → project-vite-Dm128JTE.cjs} +1 -1
- package/dist/cli-chunks/{remote-CbZlAq6Z.cjs → remote-CZuy1lmn.cjs} +33 -146
- package/dist/cli-chunks/{runtime-gate-BcKHky95.cjs → runtime-gate-g3afiufR.cjs} +2 -2
- package/dist/cli-chunks/{runtime-permission-env-BQ7lPfhg.cjs → runtime-permission-env-CDx5qO-T.cjs} +2 -2
- package/dist/cli-chunks/{skill-KmRvlkMJ.cjs → skill-Bdy5Ehue.cjs} +2 -2
- package/dist/cli-chunks/{version-ai8lcNbJ.cjs → version-D40WHkF9.cjs} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/devtools/browser-dev-host/assets/{browser-dev-host-DIkT9EVT.js → browser-dev-host-BW7iWnpt.js} +1 -1
- package/dist/devtools/browser-dev-host/assets/{desktop-app-launch-CXLBQXPW.js → desktop-app-launch-lmlBUG16.js} +1 -1
- package/dist/devtools/browser-dev-host/assets/{index-Dn9OFySi.js → index-D7F2y1lF.js} +3 -3
- package/dist/devtools/browser-dev-host/index.html +2 -2
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/miniapp-publish.cjs.js +22 -0
- package/dist/miniapp-publish.esm.js +22 -1
- package/dist/templates/vanilla-vite-js/README.md.ejs +4 -0
- package/dist/vite.cjs.js +46 -3
- package/dist/vite.esm.js +46 -3
- package/docs/runtime-host-migration.md +1 -1
- package/package.json +6 -6
- package/skill/SKILL.md +9 -0
- package/skill/skill.json +5 -5
- package/types/miniapp-publish/index.d.ts +15 -2
- package/types/vite/index.d.ts +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
本文件随 `@heybox/hb-sdk` npm 包公开分发,只记录外部小程序开发者可观察到的变化。
|
|
4
4
|
|
|
5
|
+
## 0.9.2-alpha.8 - 2026-10-20
|
|
6
|
+
|
|
7
|
+
### 新增能力
|
|
8
|
+
|
|
9
|
+
- 新增 `hb-sdk remote games search "游戏名" --json`,查询平台游戏 appid、中英文名称和分页结果,无需先绑定小程序项目。
|
|
10
|
+
- CLI 游戏搜索增加请求频率保护,操作过于频繁时提示稍后重试。
|
|
11
|
+
|
|
12
|
+
### 行为调整
|
|
13
|
+
|
|
14
|
+
- 开发启动、构建和部署时,对简介缺失、工具类未关联游戏给出非阻断提醒;部署不重复输出内部构建的资料提示。
|
|
15
|
+
- Agent Skill 主动检查小程序分类、简介和游戏绑定,保留已有内容,通用工具可保持不关联游戏。
|
|
16
|
+
|
|
17
|
+
### 问题修复
|
|
18
|
+
|
|
19
|
+
- 修复 Vite 5/6 开发服务在输出资料或旧模板平台提醒时无法启动的问题。
|
|
20
|
+
|
|
21
|
+
## 0.9.2-alpha.7 - 2026-10-20
|
|
22
|
+
|
|
23
|
+
### 行为调整
|
|
24
|
+
|
|
25
|
+
- `hb-sdk dev` 启动前要求 CLI 已登录、项目已绑定小程序且远端配置校验通过;失败时提供修复指引并退出,不再自动进入匿名 Browser Mock。临时网络异常和短期限流仅重试一次,启动后的签票失败或临时断网仍保留浏览器调试服务。
|
|
26
|
+
|
|
5
27
|
## 0.9.2-alpha.6
|
|
6
28
|
|
|
7
29
|
### 新增能力
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ npm run dev
|
|
|
26
26
|
|
|
27
27
|
脚手架已包含 SDK、Vite 配置和常用开发命令。浏览器调试通过后,再从调试台的二维码入口使用手机小黑盒 APP 验收。
|
|
28
28
|
|
|
29
|
-
手机二维码的短链先打开普通中间页,再进入专用 dev-shell。最终 `openWindow` 协议会把 CLI 校验后的用户小程序字符串 ID(UUID)写入根字段 `user_miniprogram_id`;原生不会从 URL 查询参数补读,也不能用传统小程序数字 ID
|
|
29
|
+
手机二维码的短链先打开普通中间页,再进入专用 dev-shell。最终 `openWindow` 协议会把 CLI 校验后的用户小程序字符串 ID(UUID)写入根字段 `user_miniprogram_id`;原生不会从 URL 查询参数补读,也不能用传统小程序数字 ID 代替。原生未开放的横屏能力仍返回 `supported: false`。入口排查与验证记录见 [Android 396 入口审计](./docs/android-396-launch-identity.md)。
|
|
30
30
|
|
|
31
31
|
创建命令使用 `@latest`,实际安装版本以 npm 的 `latest` 为准。
|
|
32
32
|
|
|
@@ -124,6 +124,8 @@ async function revokeAuthorizationFromUserAction() {
|
|
|
124
124
|
|
|
125
125
|
小程序类别需在 `package.json#heybox.category` 声明为 `tool`、`game` 或 `other`,构建后写入 Manifest,CLI/Open 提审自动采用,发布后生效。开发者提审页不展示或提供手动选择类别;新上传版本(含已有小程序更新)必须声明,缺少类别的项目须补配置后重新构建上传,详见 [小程序类别](https://docs.xiaoheihe.cn/hb_sdk/guide/cli#小程序类别)。
|
|
126
126
|
|
|
127
|
+
使用 `hb-sdk remote games search "游戏名" --json` 查询平台游戏候选,无需先绑定项目;核对后将返回的字符串 `appid` 填入 `heybox.bindAppIds`,能否绑定以部署预检为准。简介缺失、工具类未关联游戏时,开发启动、构建和部署会给出非阻断提醒;具体流程见 [CLI 指南](https://docs.xiaoheihe.cn/hb_sdk/guide/cli)。
|
|
128
|
+
|
|
127
129
|
`bindAppIds` 只接受规范十进制字符串(形如 `/^[1-9]\d*$/`,拒绝前导零、空串与非数字),每项必须是正 int32(最大 `2147483647`),数组内不允许重复,最多 20 项,并按数值升序写入 Manifest。它不是权限,构建不联网;游戏真实性在远端预检和提审时校验。字段缺失或 `[]` 都表示清空绑定。PC 展示仍受 `platforms` 过滤。
|
|
128
130
|
|
|
129
131
|
再启用构建插件:
|
|
@@ -498,7 +500,7 @@ CLI 会复用已验证产物、跳过该 ZIP 的网络上传;Web 文件及发
|
|
|
498
500
|
|
|
499
501
|
右上角的桌面图标与二维码按钮使用相同样式。桌面图标只在该项目于 `package.json#heybox.platforms` 声明了桌面平台(`windows`、`macos` 或 `linux`)时展示,未声明桌面平台的项目不显示该入口。点击桌面图标后选择小黑盒正式版或 Debug 版,选择会立即请求客户端打开当前本地页面并在本地记忆,不需要二次确认。桌面端只接受无凭据的 `http://127.0.0.1:<port>`,拒绝 `localhost`、IPv6 和 LAN 地址,不提供地址选择或手工 URL;手机二维码继续独立选择局域网地址。入口在项目已绑定且本地调试启动票有效时可用,统一 URI 只携带 `mini_program_id` 和 `mini_url`,启动票继续由 detail 从同源 `launch.json` 发现并交给后端验证。浏览器无法确认客户端是否真正打开,因此调试台只记录“已请求打开”,不会自动切换正式版或 Debug 版。
|
|
500
502
|
|
|
501
|
-
`hb-sdk dev`
|
|
503
|
+
`hb-sdk dev` 启动前要求 CLI 已登录、项目已绑定小程序,并成功校验远端配置;未满足时直接退出,不启动服务或打开浏览器。网络或服务临时异常等待 1 秒后重试一次;限流仅在服务端给出的等待窗口不超过 30 秒时重试一次,仍失败则退出并保留绑定。启动后,真实手机/PC 入口须有有效启动票,签票失败不阻断 Browser Mock,运行中的临时网络故障也不关闭浏览器服务。CLI 自动从本地声明生成普通 `network` / `companion` 的临时批准缺口,不提供第二套权限开关。调试台顶部的“查看全部权限申请”在新标签页打开当前小程序的权限列表;尚未获批的 Network、Companion 单项提供“去申请”,直接打开对应申请表单。未获取到小程序 ID 时先选择小程序,再进入对应权限;已获批或审核中的权限不重复打开申请表单。真实 Host 每次打开会话确认临时权限,拒绝后仍可按线上批准基线打开;官方域名始终只认声明与线上批准的交集。手机真机 Dev Session 仅将目标 hostname 为 `localhost` 或 `127.0.0.*` 的公开 `network.request()` 交给开发机 HTTP 代理转发,因此这些地址指向开发机;其它域名、LAN 地址和其它 IP 使用设备自身网络;代理不管理独立租约,不判断黑盒域名或改写应用层凭据。正式版本和 Runtime 私有请求仍走 Host 网络。CLI 连续失联约 30 秒、期限或快照变化会销毁旧 Runtime,并清理临时 Companion 进程树;恢复后重新确认。手机验收统一从右上角二维码进入并选择可达的局域网网卡。调试会话、权限刷新与完整操作见 [CLI 指南](https://docs.xiaoheihe.cn/hb_sdk/guide/cli),实现与安全边界由 [Runtime Host 迁移](./docs/runtime-host-migration.md) 维护。
|
|
502
504
|
|
|
503
505
|
开发上下文按需读取并默认缓存 30 秒;重新打开真机会话时,过期缓存会刷新。权限刷新遇到临时故障或限流会按退避自动重试,恢复前暂停签发新启动票。真机按确认后的有效网络权限选择身份模式;身份上下文读取失败会提示重试,不会静默切换旧身份模式。
|
|
504
506
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var runtimeGate = require('./runtime-gate-
|
|
3
|
+
var runtimeGate = require('./runtime-gate-g3afiufR.cjs');
|
|
4
4
|
var fs$1 = require('node:fs');
|
|
5
5
|
var fs = require('node:fs/promises');
|
|
6
6
|
var path = require('node:path');
|
|
7
|
-
var runtimePermissionEnv = require('./runtime-permission-env-
|
|
8
|
-
var index = require('./index-
|
|
7
|
+
var runtimePermissionEnv = require('./runtime-permission-env-CDx5qO-T.cjs');
|
|
8
|
+
var index = require('./index-CY67PpQk.cjs');
|
|
9
9
|
require('node:crypto');
|
|
10
10
|
require('node:zlib');
|
|
11
|
-
var projectVite = require('./project-vite-
|
|
11
|
+
var projectVite = require('./project-vite-Dm128JTE.cjs');
|
|
12
12
|
require('node:module');
|
|
13
13
|
require('node:url');
|
|
14
14
|
require('./_commonjs-dynamic-modules-DUamuDzp.cjs');
|
|
@@ -16,7 +16,7 @@ require('fs');
|
|
|
16
16
|
require('path');
|
|
17
17
|
require('os');
|
|
18
18
|
require('inspector');
|
|
19
|
-
require('./version-
|
|
19
|
+
require('./version-D40WHkF9.cjs');
|
|
20
20
|
require('node:async_hooks');
|
|
21
21
|
require('readline');
|
|
22
22
|
require('tty');
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
var node_crypto = require('node:crypto');
|
|
4
4
|
var fs = require('node:fs/promises');
|
|
5
5
|
var path = require('node:path');
|
|
6
|
-
var runtimePermissionEnv = require('./runtime-permission-env-
|
|
6
|
+
var runtimePermissionEnv = require('./runtime-permission-env-CDx5qO-T.cjs');
|
|
7
7
|
var fs$1 = require('node:fs');
|
|
8
8
|
var sharp = require('sharp');
|
|
9
|
-
var index = require('./index-
|
|
9
|
+
var index = require('./index-CY67PpQk.cjs');
|
|
10
10
|
|
|
11
11
|
async function inspectBasicInfoImage(bytes, sourcePath, kind) {
|
|
12
12
|
const inspected = await inspectDecodedBasicInfoImage(bytes, kind);
|
|
@@ -5,7 +5,7 @@ var fs = require('node:fs/promises');
|
|
|
5
5
|
var path = require('node:path');
|
|
6
6
|
var require$$0 = require('fs');
|
|
7
7
|
var require$$1 = require('path');
|
|
8
|
-
var index = require('./index-
|
|
8
|
+
var index = require('./index-CY67PpQk.cjs');
|
|
9
9
|
require('node:module');
|
|
10
10
|
require('readline');
|
|
11
11
|
require('os');
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_crypto = require('node:crypto');
|
|
4
|
+
var fs = require('node:fs/promises');
|
|
5
|
+
var path = require('node:path');
|
|
6
|
+
var index = require('./index-CY67PpQk.cjs');
|
|
7
|
+
|
|
8
|
+
const DEPLOY_LOCKED_MESSAGE = '当前设备已有同版本产物正在上传,请等待完成后重试';
|
|
9
|
+
const DEPLOY_LOCK_DIRECTORY_NAME = 'deploy-locks';
|
|
10
|
+
const DEPLOY_LOCK_OWNER_FILE = 'owner.json';
|
|
11
|
+
const INCOMPLETE_LOCK_GRACE_MS = 30_000;
|
|
12
|
+
const defaultPaths = index.envPaths('hb-sdk', { suffix: '' });
|
|
13
|
+
class DeployLockConflictError extends Error {
|
|
14
|
+
}
|
|
15
|
+
async function withDeployLock(scope, operation, options = {}) {
|
|
16
|
+
let lock;
|
|
17
|
+
try {
|
|
18
|
+
lock = await acquireDeployLock(scope, options);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof DeployLockConflictError) {
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
// 本地文件锁只减少重复操作,文件系统异常不阻断服务端上传流程。
|
|
25
|
+
return operation();
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
return await operation();
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
await lock.release().catch(() => undefined);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function acquireDeployLock(scope, options = {}) {
|
|
35
|
+
const lockDirectory = getDeployLockDirectory(scope, options.cacheRoot);
|
|
36
|
+
const ownerFile = path.join(lockDirectory, DEPLOY_LOCK_OWNER_FILE);
|
|
37
|
+
const owner = {
|
|
38
|
+
version: 1,
|
|
39
|
+
pid: options.pid ?? process.pid,
|
|
40
|
+
token: options.token ?? node_crypto.randomBytes(16).toString('hex'),
|
|
41
|
+
};
|
|
42
|
+
await fs.mkdir(path.dirname(lockDirectory), { recursive: true, mode: 0o700 });
|
|
43
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
44
|
+
let created = false;
|
|
45
|
+
try {
|
|
46
|
+
await fs.mkdir(lockDirectory, { mode: 0o700 });
|
|
47
|
+
created = true;
|
|
48
|
+
await fs.writeFile(ownerFile, `${JSON.stringify(owner)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
49
|
+
return createDeployLock(lockDirectory, ownerFile, owner.token);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (created) {
|
|
53
|
+
await fs.rm(lockDirectory, { force: true, recursive: true });
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
if (!isNodeError(error) || error.code !== 'EEXIST') {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
if (!(await canReclaimDeployLock(lockDirectory, ownerFile, options))) {
|
|
60
|
+
throw new DeployLockConflictError(DEPLOY_LOCKED_MESSAGE);
|
|
61
|
+
}
|
|
62
|
+
await reclaimDeployLock(lockDirectory, owner.token);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
throw new DeployLockConflictError(DEPLOY_LOCKED_MESSAGE);
|
|
66
|
+
}
|
|
67
|
+
function getDeployLockDirectory(scope, cacheRoot = defaultPaths.cache) {
|
|
68
|
+
const scopeHash = node_crypto.createHash('sha256').update(`${scope.apiBaseUrl}\0${scope.miniProgramId}\0${scope.version}`).digest('hex');
|
|
69
|
+
return path.join(cacheRoot, DEPLOY_LOCK_DIRECTORY_NAME, scopeHash);
|
|
70
|
+
}
|
|
71
|
+
function createDeployLock(lockDirectory, ownerFile, token) {
|
|
72
|
+
let released = false;
|
|
73
|
+
return {
|
|
74
|
+
async release() {
|
|
75
|
+
if (released)
|
|
76
|
+
return;
|
|
77
|
+
released = true;
|
|
78
|
+
await removeOwnedLock(lockDirectory, ownerFile, token);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function canReclaimDeployLock(lockDirectory, ownerFile, options) {
|
|
83
|
+
const owner = await readDeployLockOwner(ownerFile);
|
|
84
|
+
if (owner) {
|
|
85
|
+
return !(options.isProcessRunning ?? isProcessRunning)(owner.pid);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const lockStat = await fs.stat(lockDirectory);
|
|
89
|
+
return (options.now ?? Date.now)() - lockStat.mtimeMs >= INCOMPLETE_LOCK_GRACE_MS;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return isNodeError(error) && error.code === 'ENOENT';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function removeOwnedLock(lockDirectory, ownerFile, token) {
|
|
96
|
+
const owner = await readDeployLockOwner(ownerFile);
|
|
97
|
+
if (owner?.token === token) {
|
|
98
|
+
await fs.rm(lockDirectory, { force: true, recursive: true });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function reclaimDeployLock(lockDirectory, token) {
|
|
102
|
+
const reclaimDirectory = `${lockDirectory}.reclaim-${node_crypto.createHash('sha256').update(token).digest('hex')}`;
|
|
103
|
+
try {
|
|
104
|
+
await fs.rename(lockDirectory, reclaimDirectory);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (isNodeError(error) && error.code === 'ENOENT')
|
|
108
|
+
return;
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
await fs.rm(reclaimDirectory, { force: true, recursive: true });
|
|
112
|
+
}
|
|
113
|
+
async function readDeployLockOwner(ownerFile) {
|
|
114
|
+
try {
|
|
115
|
+
const value = JSON.parse(await fs.readFile(ownerFile, 'utf8'));
|
|
116
|
+
return isDeployLockOwner(value) ? value : null;
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (isNodeError(error) && error.code === 'ENOENT')
|
|
120
|
+
return null;
|
|
121
|
+
if (error instanceof SyntaxError)
|
|
122
|
+
return null;
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function isDeployLockOwner(value) {
|
|
127
|
+
return (typeof value === 'object' &&
|
|
128
|
+
value !== null &&
|
|
129
|
+
value.version === 1 &&
|
|
130
|
+
Number.isInteger(value.pid) &&
|
|
131
|
+
typeof value.token === 'string');
|
|
132
|
+
}
|
|
133
|
+
function isProcessRunning(pid) {
|
|
134
|
+
try {
|
|
135
|
+
process.kill(pid, 0);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return !isNodeError(error) || error.code !== 'ESRCH';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function isNodeError(error) {
|
|
143
|
+
return error instanceof Error && 'code' in error;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
exports.DEPLOY_LOCKED_MESSAGE = DEPLOY_LOCKED_MESSAGE;
|
|
147
|
+
exports.acquireDeployLock = acquireDeployLock;
|
|
148
|
+
exports.withDeployLock = withDeployLock;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
4
|
-
var context = require('./context-
|
|
3
|
+
var index = require('./index-CY67PpQk.cjs');
|
|
4
|
+
var context = require('./context-BI3QMxw2.cjs');
|
|
5
5
|
var node_crypto = require('node:crypto');
|
|
6
6
|
var fs = require('node:fs');
|
|
7
|
-
var runtimePermissionEnv = require('./runtime-permission-env-
|
|
7
|
+
var runtimePermissionEnv = require('./runtime-permission-env-CDx5qO-T.cjs');
|
|
8
8
|
var os = require('node:os');
|
|
9
9
|
var path = require('node:path');
|
|
10
10
|
var net = require('node:net');
|
|
@@ -16,8 +16,8 @@ var fs$1 = require('node:fs/promises');
|
|
|
16
16
|
var require$$0$1 = require('crypto');
|
|
17
17
|
var require$$0 = require('buffer');
|
|
18
18
|
var browser = require('./browser-RAy8e8cV.cjs');
|
|
19
|
-
var projectVite = require('./project-vite-
|
|
20
|
-
var version = require('./version-
|
|
19
|
+
var projectVite = require('./project-vite-Dm128JTE.cjs');
|
|
20
|
+
var version = require('./version-D40WHkF9.cjs');
|
|
21
21
|
require('node:zlib');
|
|
22
22
|
|
|
23
23
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -1995,8 +1995,8 @@ const DEFAULT_CHANNEL_TRANSPORT = {
|
|
|
1995
1995
|
};
|
|
1996
1996
|
const IPV4_LOOPBACK_ADDRESSES = new net.BlockList();
|
|
1997
1997
|
IPV4_LOOPBACK_ADDRESSES.addSubnet('127.0.0.0', 8, 'ipv4');
|
|
1998
|
-
const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-
|
|
1999
|
-
const { parse: parseHtml } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-
|
|
1998
|
+
const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-DeNzUY6g.cjs', document.baseURI).href)))('ws');
|
|
1999
|
+
const { parse: parseHtml } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-DeNzUY6g.cjs', document.baseURI).href)))('parse5');
|
|
2000
2000
|
const BROWSER_DEV_HOST_ROOT_CANDIDATES = [
|
|
2001
2001
|
path.resolve(__dirname, 'devtools/browser-dev-host'),
|
|
2002
2002
|
path.resolve(__dirname, '../devtools/browser-dev-host'),
|
|
@@ -11100,7 +11100,7 @@ function assertNodeRuntimeCapabilities(ctx, settings) {
|
|
|
11100
11100
|
function createNodeRealtimeDriverRegistry() {
|
|
11101
11101
|
const registry = createRuntimeRealtimeDriverRegistry();
|
|
11102
11102
|
registry.registerLazy('node-websocket', async () => {
|
|
11103
|
-
const mod = await Promise.resolve().then(function () { return require('./index.esm-
|
|
11103
|
+
const mod = await Promise.resolve().then(function () { return require('./index.esm-DQdwzMhB.cjs'); });
|
|
11104
11104
|
return mod.createNodeWebSocketRuntimeDriver();
|
|
11105
11105
|
});
|
|
11106
11106
|
return registry;
|
|
@@ -15584,21 +15584,6 @@ async function runDevCommand(options, runtime = {}) {
|
|
|
15584
15584
|
const logger = runtime.logger ?? index.createCliLogger();
|
|
15585
15585
|
const fetchImpl = runtime.fetchImpl ?? fetch;
|
|
15586
15586
|
const openUrl = runtime.openExternalUrl ?? browser.openExternalUrl;
|
|
15587
|
-
const networkInterfaceSnapshot = (runtime.networkInterfaces ?? os.networkInterfaces)();
|
|
15588
|
-
const getPortImpl = runtime.getPort ?? getPorts;
|
|
15589
|
-
const requestedAppPort = options.port ?? DEFAULT_APP_PORT;
|
|
15590
|
-
const appPort = await selectAvailableVitePort({
|
|
15591
|
-
getPort: getPortImpl,
|
|
15592
|
-
isPortListening: runtime.isTcpPortListening ?? isTcpPortListening,
|
|
15593
|
-
startPort: requestedAppPort,
|
|
15594
|
-
});
|
|
15595
|
-
if (appPort !== requestedAppPort)
|
|
15596
|
-
logger.warn(`端口 ${requestedAppPort} 已被占用,已自动切换到 ${appPort}`);
|
|
15597
|
-
const resolvedOptions = {
|
|
15598
|
-
...options,
|
|
15599
|
-
hmrHost: createLanInterfaceCandidates(networkInterfaceSnapshot)[0]?.address,
|
|
15600
|
-
port: appPort,
|
|
15601
|
-
};
|
|
15602
15587
|
const projectRoot = projectVite.findProjectRoot(runtime.cwd ?? process.cwd());
|
|
15603
15588
|
const workspaceCardsDeclared = runtimePermissionEnv.readMiniappWorkspaceCardsFromPackageJson(projectRoot).declaration !== undefined;
|
|
15604
15589
|
const companionArtifactAccessToken = (runtime.randomBytes ?? node_crypto.randomBytes)(32).toString('base64url');
|
|
@@ -15608,7 +15593,8 @@ async function runDevCommand(options, runtime = {}) {
|
|
|
15608
15593
|
const miniProgramPlatforms = runtimePermissionEnv.readMiniappPlatformsFromPackageJson(projectRoot);
|
|
15609
15594
|
// A1:Dev Context 结果缓存。启动读取、设备会话读取和权限刷新共用同一份结果,
|
|
15610
15595
|
// 手机端重连不再 1:1 产生远端 `detail` 请求;限流时按网关建议时长延长压制。
|
|
15611
|
-
|
|
15596
|
+
// 启动等待期间尚无监听服务,定时器必须保持进程存活。
|
|
15597
|
+
const defaultSleep = (ms) => new Promise(resolve => { setTimeout(resolve, ms); });
|
|
15612
15598
|
const devContextCache = createDevContextCache({
|
|
15613
15599
|
load: () => loadDevLaunchContext({
|
|
15614
15600
|
env: runtime.env,
|
|
@@ -15632,9 +15618,9 @@ async function runDevCommand(options, runtime = {}) {
|
|
|
15632
15618
|
const key = `${projectRoot}\0${boundMiniProgramId ?? ''}`;
|
|
15633
15619
|
return devContextCache.read(key);
|
|
15634
15620
|
};
|
|
15635
|
-
let
|
|
15621
|
+
let startup = await readDevLaunchContext();
|
|
15636
15622
|
let lastRateLimitHint = '';
|
|
15637
|
-
//
|
|
15623
|
+
// 提示只在内容变化时输出一次,避免手机端反复重连刷屏。
|
|
15638
15624
|
const reportRateLimitOnce = (state) => {
|
|
15639
15625
|
const hint = index.formatCliRateLimitHint(state);
|
|
15640
15626
|
if (hint === lastRateLimitHint)
|
|
@@ -15642,29 +15628,40 @@ async function runDevCommand(options, runtime = {}) {
|
|
|
15642
15628
|
lastRateLimitHint = hint;
|
|
15643
15629
|
reportDevContextRateLimit(logger, state, runtime.env);
|
|
15644
15630
|
};
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
|
|
15648
|
-
//
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15652
|
-
if (
|
|
15653
|
-
|
|
15654
|
-
|
|
15655
|
-
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15631
|
+
const startupRateLimit = startup.context.rateLimit;
|
|
15632
|
+
if (startupRateLimit?.limited)
|
|
15633
|
+
reportRateLimitOnce(startupRateLimit);
|
|
15634
|
+
// 首次启动只对临时错误重试一次;限流必须遵守服务端窗口,不能用普通退避绕过。
|
|
15635
|
+
const retryDelay = startupRateLimit?.limited
|
|
15636
|
+
? startupRateLimit.retryAfterMs
|
|
15637
|
+
: startup.retryable ? DEFAULT_DEV_CONTEXT_BACKOFF_START_MS : undefined;
|
|
15638
|
+
if (startup.error && retryDelay !== undefined && retryDelay <= DEV_CONTEXT_STARTUP_RATE_LIMIT_WAIT_MAX_MS) {
|
|
15639
|
+
logger.warn(`${startupRateLimit?.limited ? '已被网关限流' : '远端配置暂不可用'},等待 ${Math.round(retryDelay / 1000)} 秒后重试一次…`);
|
|
15640
|
+
await (runtime.sleep ?? defaultSleep)(retryDelay);
|
|
15641
|
+
devContextCache.invalidate();
|
|
15642
|
+
startup = await readDevLaunchContext();
|
|
15643
|
+
}
|
|
15644
|
+
if (startup.error) {
|
|
15645
|
+
throw new index.CliError(`无法启动调试:${startup.error.message}`, startup.error.verboseMessage, { httpStatus: startup.error.httpStatus });
|
|
15646
|
+
}
|
|
15647
|
+
const { context: devLaunchContext, miniProgram } = startup;
|
|
15648
|
+
lastRateLimitHint = '';
|
|
15649
|
+
// 完成项目身份与配置校验后,才选择端口、创建服务和打开浏览器。
|
|
15650
|
+
const networkInterfaceSnapshot = (runtime.networkInterfaces ?? os.networkInterfaces)();
|
|
15651
|
+
const getPortImpl = runtime.getPort ?? getPorts;
|
|
15652
|
+
const requestedAppPort = options.port ?? DEFAULT_APP_PORT;
|
|
15653
|
+
const appPort = await selectAvailableVitePort({
|
|
15654
|
+
getPort: getPortImpl,
|
|
15655
|
+
isPortListening: runtime.isTcpPortListening ?? isTcpPortListening,
|
|
15656
|
+
startPort: requestedAppPort,
|
|
15657
|
+
});
|
|
15658
|
+
if (appPort !== requestedAppPort)
|
|
15659
|
+
logger.warn(`端口 ${requestedAppPort} 已被占用,已自动切换到 ${appPort}`);
|
|
15660
|
+
const resolvedOptions = {
|
|
15661
|
+
...options,
|
|
15662
|
+
hmrHost: createLanInterfaceCandidates(networkInterfaceSnapshot)[0]?.address,
|
|
15663
|
+
port: appPort,
|
|
15664
|
+
};
|
|
15668
15665
|
let currentDevContext = devLaunchContext;
|
|
15669
15666
|
// 候选输入不对真机公开;签票成功后才替换整份运行上下文。
|
|
15670
15667
|
let candidateDevContext = devLaunchContext;
|
|
@@ -15933,6 +15930,8 @@ async function runDevCommand(options, runtime = {}) {
|
|
|
15933
15930
|
if (refreshed.context.rateLimit?.limited) {
|
|
15934
15931
|
throw index.createCliRateLimitedErrorFromState(refreshed.context.rateLimit);
|
|
15935
15932
|
}
|
|
15933
|
+
if (refreshed.error)
|
|
15934
|
+
throw refreshed.error;
|
|
15936
15935
|
if (refreshed.context.miniProgramId !== devLaunchContext.miniProgramId)
|
|
15937
15936
|
throw new Error('项目绑定已变更,请重新启动调试');
|
|
15938
15937
|
if (refreshed.context.source !== 'remote')
|
|
@@ -16085,17 +16084,20 @@ function runDevStartupTask(logger, text, action, successText) {
|
|
|
16085
16084
|
return logger.task(text, () => action(), { successText });
|
|
16086
16085
|
}
|
|
16087
16086
|
async function loadDevLaunchContext(options) {
|
|
16088
|
-
//
|
|
16087
|
+
// 声明错误始终阻断;远端失败保留结构化原因,启动与运行阶段分别处理。
|
|
16089
16088
|
const localPermissions = runtimePermissionEnv.readMiniappPermissionsFromPackageJson(options.projectRoot, runtimePermissionEnv.resolveMiniappSdkVersion());
|
|
16090
16089
|
const platforms = runtimePermissionEnv.readMiniappPlatformsFromPackageJson(options.projectRoot);
|
|
16091
|
-
const
|
|
16090
|
+
const unavailable = (message, error = new index.CliError(message), retryable = false) => ({
|
|
16091
|
+
context: { source: 'anonymous', warning: message,
|
|
16092
16092
|
declaredPermissions: localPermissions.permissions ?? {}, platforms,
|
|
16093
|
-
runtimePermissions: runtimePermissionEnv.composeMiniappRuntimePermissions(localPermissions, undefined).runtimePermissions },
|
|
16094
|
-
|
|
16095
|
-
|
|
16093
|
+
runtimePermissions: runtimePermissionEnv.composeMiniappRuntimePermissions(localPermissions, undefined).runtimePermissions },
|
|
16094
|
+
miniProgram: null, error, retryable,
|
|
16095
|
+
});
|
|
16096
16096
|
const miniProgramId = await context.readBoundMiniProgramId(options.projectRoot);
|
|
16097
16097
|
if (!miniProgramId)
|
|
16098
|
-
return
|
|
16098
|
+
return unavailable('当前项目尚未绑定小程序。请先运行 hb-sdk remote create 或 hb-sdk remote bind <mini-program-id>,完成后重新运行 hb-sdk dev。');
|
|
16099
|
+
if (!(await index.readHeyboxAuthSession({ env: options.env })))
|
|
16100
|
+
return unavailable('尚未登录 CLI。请先运行 hb-sdk login,完成后重新运行 hb-sdk dev。');
|
|
16099
16101
|
let migratingProfile = false;
|
|
16100
16102
|
try {
|
|
16101
16103
|
const { detail, miniProgramId: verifiedMiniProgramId } = await runDevStartupTask(options.logger, '正在读取远端小程序权限', () => loadRemoteDevContextWithTimeout({
|
|
@@ -16113,7 +16115,7 @@ async function loadDevLaunchContext(options) {
|
|
|
16113
16115
|
if (migration.changed)
|
|
16114
16116
|
options.logger.info('已迁移当前正式发布名称与图片,继续启动开发环境');
|
|
16115
16117
|
if (!runtimePermissionEnv.parseMiniProgramRuntimePermissions(detail.runtime_permissions).valid)
|
|
16116
|
-
return
|
|
16118
|
+
return unavailable('线上权限快照无效,请稍后重试;持续失败时请联系平台支持。');
|
|
16117
16119
|
const effectivePermissions = runtimePermissionEnv.composeMiniappRuntimePermissions(localPermissions, detail.runtime_permissions, detail.party_type).runtimePermissions;
|
|
16118
16120
|
return {
|
|
16119
16121
|
context: {
|
|
@@ -16132,18 +16134,25 @@ async function loadDevLaunchContext(options) {
|
|
|
16132
16134
|
throw new Error(`版本资料配置失败:${index.readRedactedErrorMessage(error)}。请配置 heybox.name/icon/coverImages 后重试。`, { cause: error });
|
|
16133
16135
|
if (error instanceof context.MiniProgramProjectBindingError && error.code.startsWith('PACKAGE_JSON_'))
|
|
16134
16136
|
throw error;
|
|
16135
|
-
// A3:限流要作为结构化状态继续透出;不能和其它错误一样只报「未连接线上上下文」。
|
|
16136
16137
|
const rateLimitState = index.readCliRateLimitState(error);
|
|
16137
16138
|
if (rateLimitState) {
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
16146
|
-
|
|
16139
|
+
const failure = unavailable(index.formatCliRateLimitHint(rateLimitState));
|
|
16140
|
+
failure.context.rateLimit = rateLimitState;
|
|
16141
|
+
return failure;
|
|
16142
|
+
}
|
|
16143
|
+
const status = error instanceof index.CliError ? error.httpStatus : undefined;
|
|
16144
|
+
const reason = status === 401
|
|
16145
|
+
? 'CLI 登录态已失效,请运行 hb-sdk login 后重试。'
|
|
16146
|
+
: status === 403 || status === 404
|
|
16147
|
+
? '无法访问已绑定的小程序,请检查当前账号的管理权限和小程序是否存在,必要时运行 hb-sdk remote bind <mini-program-id> 重新绑定。'
|
|
16148
|
+
: error instanceof context.MiniProgramProjectBindingError
|
|
16149
|
+
? `${index.readRedactedErrorMessage(error)}。请运行 hb-sdk remote create 或 hb-sdk remote bind <mini-program-id> 后重试。`
|
|
16150
|
+
: `读取远端小程序配置失败:${index.readRedactedErrorMessage(error)}。请检查网络或稍后重试,当前项目绑定已保留。`;
|
|
16151
|
+
const retryable = error instanceof TypeError
|
|
16152
|
+
|| (error instanceof Error && error.message === 'dev context timeout')
|
|
16153
|
+
|| status === 408
|
|
16154
|
+
|| (status !== undefined && status >= 500);
|
|
16155
|
+
return unavailable(reason, new index.CliError(reason, undefined, { httpStatus: status }), retryable);
|
|
16147
16156
|
}
|
|
16148
16157
|
}
|
|
16149
16158
|
/**
|