@h-ai/cli 0.1.0-alpha.65 → 0.1.0-alpha.66
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.en.md +13 -7
- package/README.ja.md +13 -7
- package/README.md +14 -8
- package/dist/{chunk-IPG3QNYK.js → chunk-FWN5B54L.js} +36 -4
- package/dist/chunk-FWN5B54L.js.map +1 -0
- package/dist/{chunk-47V5OT22.js → chunk-QYX6V7H2.js} +17 -43
- package/dist/chunk-QYX6V7H2.js.map +1 -0
- package/dist/cli-config-templates-3XSFIXBP.js +5 -0
- package/dist/{cli-config-templates-SJ2MBIR7.js.map → cli-config-templates-3XSFIXBP.js.map} +1 -1
- package/dist/{cli-skill-templates-A5VIR5J6.js → cli-skill-templates-TSYEQTCY.js} +3 -3
- package/dist/{cli-skill-templates-A5VIR5J6.js.map → cli-skill-templates-TSYEQTCY.js.map} +1 -1
- package/dist/index.js +273 -208
- package/dist/index.js.map +1 -1
- package/dist/{src-6PPBKQ6Q.js → src-RDQ2EIBT.js} +506 -488
- package/dist/src-RDQ2EIBT.js.map +1 -0
- package/package.json +8 -8
- package/templates/apps/api/.dockerignore.hbs +4 -5
- package/templates/apps/api/.gitignore.hbs +2 -1
- package/templates/apps/api/Dockerfile.hbs +2 -15
- package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +2 -2
- package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +0 -1
- package/templates/apps/api/hai.build.json.hbs +1 -0
- package/templates/apps/api/package.json.hbs +5 -8
- package/templates/apps/fullstack/.dockerignore.hbs +4 -5
- package/templates/apps/fullstack/.gitignore.hbs +2 -1
- package/templates/apps/fullstack/Dockerfile.hbs +3 -15
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +0 -3
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +3 -6
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +2 -3
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +73 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +2 -6
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +2 -2
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +1 -0
- package/templates/apps/fullstack/hai.build.json.hbs +7 -0
- package/templates/apps/fullstack/package.json.hbs +5 -12
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +2 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +0 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +1 -1
- package/templates/apps/mobile-app/index.html.hbs +1 -0
- package/templates/apps/mobile-app/public/runtime-config.js +1 -0
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +2 -1
- package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +3 -2
- package/templates/base/.dockerignore.hbs +4 -5
- package/templates/base/.gitignore.hbs +2 -1
- package/templates/base/Dockerfile.hbs +5 -22
- package/templates/base/docker/nginx.conf.hbs +6 -0
- package/templates/base/hai.build.json.hbs +1 -0
- package/templates/base/package.json.hbs +13 -17
- package/templates/base/svelte.config.js.hbs +2 -0
- package/templates/base/vite.config.ts.hbs +6 -2
- package/templates/shared/.gitattributes +5 -0
- package/templates/shared/container-runtime-config.sh +30 -0
- package/templates/shared/run-e2e.mjs +65 -0
- package/templates/shared/vite-runtime-config.ts +54 -0
- package/templates/skills/hai-app-create/development.md +3 -1
- package/templates/skills/hai-app-create/reference.md +2 -2
- package/templates/skills/hai-build/SKILL.md +16 -1
- package/templates/skills/hai-deploy/SKILL.md +52 -260
- package/templates/skills/hai-deploy/middleware.md +8 -14
- package/templates/skills/hai-ui/reference.md +2 -0
- package/dist/chunk-47V5OT22.js.map +0 -1
- package/dist/chunk-IPG3QNYK.js.map +0 -1
- package/dist/cli-config-templates-SJ2MBIR7.js +0 -5
- package/dist/src-6PPBKQ6Q.js.map +0 -1
|
@@ -1,292 +1,84 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hai-deploy
|
|
3
|
-
description: "
|
|
3
|
+
description: "部署已有构建产物:配置环境与中间件,生成 Compose tar 并通过 SSH 或手工搬运发布;也支持 Vercel。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# hai-deploy
|
|
7
7
|
|
|
8
8
|
## 能力契约
|
|
9
9
|
|
|
10
|
-
`hai deploy` 在模块/配置缺失或凭证、扫描、初始化、部署、关闭失败时返回非零退出码。自动化流程必须以退出码判断成功,不要只判断命令是否完成或是否输出日志。
|
|
11
|
-
|
|
12
10
|
| 项目 | 契约 |
|
|
13
11
|
| --- | --- |
|
|
14
|
-
| 能力 |
|
|
15
|
-
| 适用场景 |
|
|
16
|
-
| 输入 |
|
|
17
|
-
| 输出 |
|
|
18
|
-
| 限制 |
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
部署前按 [环境与中间件向导](middleware.md) 先选择环境并检查对应文件,再逐项选择默认配置、自定义连接或保持不变。用户确认配置已完备时,可选择直接部署或传 `--skip-middleware` 跳过全部中间件处理。SSH 地址、端口、密钥路径及平台 Token 首次填写后仅保存 `.env.local`,后续自动复用。该文档列出模块依赖、后端、连接字段、云开通边界和启动验证要求。
|
|
43
|
-
|
|
44
|
-
### 1. 配置
|
|
45
|
-
|
|
46
|
-
```yaml
|
|
47
|
-
# config/_deploy.yml
|
|
48
|
-
provider:
|
|
49
|
-
type: vercel
|
|
50
|
-
token: ${HAI_DEPLOY_PROVIDER_TOKEN}
|
|
51
|
-
|
|
52
|
-
services:
|
|
53
|
-
db:
|
|
54
|
-
provisioner: neon
|
|
55
|
-
apiKey: ${HAI_DEPLOY_SERVICES_DB_APIKEY}
|
|
56
|
-
cache:
|
|
57
|
-
provisioner: upstash
|
|
58
|
-
email: ${HAI_DEPLOY_SERVICES_CACHE_EMAIL}
|
|
59
|
-
apiKey: ${HAI_DEPLOY_SERVICES_CACHE_APIKEY}
|
|
60
|
-
storage:
|
|
61
|
-
provisioner: cloudflare-r2
|
|
62
|
-
accountId: ${HAI_DEPLOY_SERVICES_STORAGE_ACCOUNTID}
|
|
63
|
-
apiToken: ${HAI_DEPLOY_SERVICES_STORAGE_APITOKEN}
|
|
64
|
-
accessKeyId: ${HAI_DEPLOY_SERVICES_STORAGE_ACCESSKEYID}
|
|
65
|
-
secretAccessKey: ${HAI_DEPLOY_SERVICES_STORAGE_SECRETACCESSKEY}
|
|
66
|
-
email:
|
|
67
|
-
provisioner: resend
|
|
68
|
-
apiKey: ${HAI_DEPLOY_SERVICES_EMAIL_APIKEY}
|
|
69
|
-
from: ${HAI_DEPLOY_SERVICES_EMAIL_FROM}
|
|
70
|
-
sms:
|
|
71
|
-
provisioner: aliyun
|
|
72
|
-
accessKeyId: ${HAI_DEPLOY_SERVICES_SMS_ACCESSKEYID}
|
|
73
|
-
accessKeySecret: ${HAI_DEPLOY_SERVICES_SMS_ACCESSKEYSECRET}
|
|
74
|
-
signName: ${HAI_DEPLOY_SERVICES_SMS_SIGNNAME}
|
|
12
|
+
| 能力 | 消费已有镜像或平台产物,配置环境、中间件并部署 |
|
|
13
|
+
| 适用场景 | SSH 自动部署、离线手工交付、Vercel 发布和部署故障排查 |
|
|
14
|
+
| 输入 | 完整构建产物、pnpm-lock.yaml、目标环境文件、部署配置和私有凭据引用 |
|
|
15
|
+
| 输出 | Compose tar 与手工说明,或已检查的在线部署结果 |
|
|
16
|
+
| 限制 | deploy 不编译/构建,不提供 skip-build 兼容路径;收费开通/发布/删除须在用户授权范围内。packaged 不代表 ready。 |
|
|
17
|
+
|
|
18
|
+
## 操作流程
|
|
19
|
+
|
|
20
|
+
1. 读取当前 package.json、`hai.build.json`、构建清单和 `_deploy.yml`;构建入口见 [hai-build](../hai-build/SKILL.md)。先显式运行 `pnpm build --target docker`,缺产物不得在 deploy 中隐式补构建。
|
|
21
|
+
2. 选择环境,检查 `.env.<mode>`;缺失则让用户创建后再继续。六类环境文件和变量优先级见 [中间件与环境](middleware.md)。
|
|
22
|
+
3. 逐项展示 lockfile 运行依赖要求的中间件、当前后端与默认用途,提供默认/自定义/完整配置时保持不变。用户表示配置齐全或传 `--skip-middleware` 时跳过全部处理,不重写连接或开通资源。
|
|
23
|
+
4. 检查已有镜像清单和 SHA-256,再生成对应环境的 Compose tar。含 app/web 时一起发布,公开 Web 同源代理 API;私有 env 仅挂载 API。
|
|
24
|
+
版本以清单 appVersion 为准,不从当前源码猜测;Compose 使用 docker-compose-<版本>.yml,tar 自动补版本后缀,启动与手工 ps/logs 都显式 -f 指定。保留稳定的项目/卷身份,跨版本跳过中间件时复用上次 Compose。CLI 仅使用 --skip-middleware,SDK 仅使用 skipMiddleware。
|
|
25
|
+
5. 在线模式上传一个 tar,远程解包、导入、compose up,再检查 API/Web;手工模式 `--bundle-only` 不要求 SSH 配置、不连接远端,输出准确的复制/解包/启动步骤及所需镜像标签。
|
|
26
|
+
6. 失败返回非零退出码;SDK 返回 HaiResult,先检查 success。保留已创建资源的恢复信息,不擅自删除。测试资源在 finally/teardown 清理。
|
|
27
|
+
|
|
28
|
+
## CLI
|
|
29
|
+
|
|
30
|
+
使用 `pnpm run deploy` 明确执行项目脚本,避免与 pnpm 自身的 deploy 命令混淆。
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pnpm build --target docker
|
|
34
|
+
pnpm run deploy --env test
|
|
35
|
+
pnpm run deploy --env prod --skip-middleware
|
|
36
|
+
pnpm run deploy --env prod --artifact-dir .hai/build/docker/<buildId>
|
|
37
|
+
pnpm run deploy --env prod --bundle-only --output release-prod.tar
|
|
38
|
+
# fullstack 的 deploy 脚本等价于
|
|
39
|
+
pnpm exec hai deploy packages/my-app-serv --env prod --env-dir .
|
|
75
40
|
```
|
|
76
41
|
|
|
77
|
-
|
|
78
|
-
`HAI_DEPLOY_PROVIDER_TOKEN` 等约定变量,约定变量仍拥有最高优先级。
|
|
79
|
-
|
|
80
|
-
#### docker-ssh 配置
|
|
81
|
-
|
|
82
|
-
将上面的 `provider` 替换为 docker-ssh(远程主机需 SSH + docker/podman + compose):
|
|
42
|
+
API workspace 的服务目录为 apps/my-app-service。单包使用当前目录。Node/pnpm 版本以项目 engines/packageManager 为准,Windows 用 pnpm.cmd。
|
|
83
43
|
|
|
84
44
|
```yaml
|
|
85
|
-
# config/_deploy.yml
|
|
45
|
+
# 服务包 config/_deploy.yml
|
|
86
46
|
provider:
|
|
87
47
|
type: docker-ssh
|
|
88
|
-
ssh:
|
|
89
|
-
host: ${HAI_DEPLOY_PROVIDER_SSH_HOST}
|
|
90
|
-
port: 22
|
|
91
|
-
username: deploy
|
|
92
|
-
identityFile: ${HAI_DEPLOY_PROVIDER_SSH_IDENTITYFILE} # 私钥文件路径,省略则用 ssh-agent
|
|
93
|
-
remote:
|
|
94
|
-
baseDir: /opt/hai/apps
|
|
95
|
-
runtime: auto # auto 优先 podman,其次 docker
|
|
96
48
|
expose:
|
|
97
|
-
|
|
98
|
-
containerPort: 3000
|
|
99
|
-
hostPort: 18080 # 访问地址 http://<host>:18080
|
|
100
|
-
|
|
49
|
+
hostPort: 18080
|
|
101
50
|
container:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
services:
|
|
105
|
-
# 启用的服务会被加入远程 compose sidecar(postgres/redis/rustfs 或 minio)
|
|
106
|
-
# 若配置了云 Provisioner(如 neon),则优先用云资源,不再自建 sidecar
|
|
107
|
-
db:
|
|
108
|
-
provisioner: neon
|
|
109
|
-
apiKey: ${HAI_DEPLOY_SERVICES_DB_APIKEY}
|
|
51
|
+
s3Engine: rustfs # rustfs | minio
|
|
110
52
|
```
|
|
111
53
|
|
|
112
|
-
|
|
54
|
+
SSH/平台参数可在向导输入后存入 `.env.local` 的 `HAI_DEPLOY_PROVIDER` 整体 JSON;私钥只存路径,不记录内容。仅打包可省 SSH;在线部署需要 ssh/scp、主机信任和运行权限。完整字段、可选云 Provisioner 及中间件配置见 [middleware.md](middleware.md)。
|
|
113
55
|
|
|
114
|
-
|
|
115
|
-
- compose 按 `deploy.scan()` 识别的服务**及其后端类型**生成匹配 sidecar 并注入 `HAI_*` 覆盖变量:
|
|
116
|
-
- `db`:`postgresql`→postgres、`mysql`→mysql、`sqlite`→数据卷(无 sidecar)→ `HAI_DB`
|
|
117
|
-
- `cache`:`redis`→redis → `HAI_CACHE`;`storage`:`s3`→RustFS/MinIO(container.s3Engine) → `HAI_STORAGE`
|
|
118
|
-
- `vecdb`:`qdrant`/`pgvector`/`chroma`→对应 sidecar、`lancedb`→数据卷 → `HAI_VECDB`
|
|
119
|
-
- 若同一服务已配置云 Provisioner(如 neon 提供 `HAI_DB`),优先用云资源,不再自建 sidecar
|
|
120
|
-
- sidecar 密码写被忽略的本机私有配置及远程 `.env.runtime`(权限 600),不入公共环境文件或 `compose.yml`
|
|
121
|
-
- `identityFile` 是私钥**路径**(非私钥内容);禁止把私钥内容写进 `_deploy.yml`
|
|
56
|
+
## SDK
|
|
122
57
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
58
|
+
```ts
|
|
126
59
|
import { deploy } from '@h-ai/deploy'
|
|
127
60
|
|
|
128
|
-
deploy.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// 使用后关闭
|
|
138
|
-
await deploy.close()
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### 3. 扫描应用
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
const scanResult = await deploy.scan('./apps/my-app', { environment: 'test' })
|
|
145
|
-
if (scanResult.success) {
|
|
146
|
-
const { appName, isSvelteKit, requiredServices } = scanResult.data
|
|
61
|
+
const initialized = await deploy.init({ provider: { type: 'docker-ssh', expose: { hostPort: 18080 } } })
|
|
62
|
+
if (!initialized.success) throw new Error(initialized.error.message)
|
|
63
|
+
try {
|
|
64
|
+
const result = await deploy.deployApp('./packages/my-app-serv', {
|
|
65
|
+
environment: 'prod', envDir: '.', bundleOnly: true,
|
|
66
|
+
artifactDir: './.hai/build/docker/<buildId>', skipMiddleware: true,
|
|
67
|
+
})
|
|
68
|
+
if (!result.success) throw new Error(result.error.message)
|
|
69
|
+
// bundlePath/instructions;只有在线部署才有健康检查和可访问 URL。
|
|
147
70
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
### 4. 开通基础设施
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
const provResults = await deploy.provisionAll('my-project')
|
|
154
|
-
if (provResults.success) {
|
|
155
|
-
for (const prov of provResults.data) {
|
|
156
|
-
// prov.envVars 包含需要注入的环境变量
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### 5. 完整部署
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
const result = await deploy.deployApp('./apps/my-app', {
|
|
165
|
-
projectName: 'my-project',
|
|
166
|
-
skipProvision: false,
|
|
167
|
-
skipBuild: false,
|
|
168
|
-
})
|
|
169
|
-
if (result.success) {
|
|
170
|
-
// result.data.url — 部署地址
|
|
171
|
-
// result.data.deploymentId — 部署 ID
|
|
172
|
-
// result.data.envVarsSet — 已设置的环境变量列表
|
|
71
|
+
finally {
|
|
72
|
+
await deploy.close()
|
|
173
73
|
}
|
|
174
74
|
```
|
|
175
75
|
|
|
176
|
-
|
|
76
|
+
`deploy.scan`、`deploy.credentials.getPath/load/save/saveAll` 不依赖 init。Vercel 使用 prebuilt 协议只上传 Build Output API v3 的 .vercel/output,不运行 build 命令;云认证和开通需要外网。
|
|
177
77
|
|
|
178
|
-
|
|
179
|
-
| ---------------------- | -------------------------------------------------------------------------- | ------------ |
|
|
180
|
-
| `deploy.credentials.load` | `() => HaiResult<string[]>` | 加载凭证到 `process.env` |
|
|
181
|
-
| `deploy.credentials.save` | `(key: string, value: string) => HaiResult<void>` | 保存单个凭证 |
|
|
182
|
-
| `deploy.credentials.saveAll` | `(entries: Record<string, string>) => HaiResult<void>` | 批量保存凭证 |
|
|
183
|
-
| `deploy.credentials.getPath` | `() => string` | 获取凭证文件路径 |
|
|
184
|
-
| `deploy.init` | `(config: DeployConfigInput) => Promise<HaiResult<void>>` | 初始化模块 |
|
|
185
|
-
| `deploy.close` | `() => Promise<void>` | 关闭模块 |
|
|
186
|
-
| `deploy.scan` | `(appDir: string, options?: DeployScanOptions) => Promise<HaiResult<ScanResult>>` | 按环境扫描(不依赖 init) |
|
|
187
|
-
| `deploy.provisionAll` | `(projectName: string, services?: ServiceType[]) => Promise<HaiResult<ProvisionResult[]>>` | 开通指定或全部已配置服务 |
|
|
188
|
-
| `deploy.deployApp` | `(appDir: string, options?) => Promise<HaiResult<DeployResult>>` | 完整部署 |
|
|
189
|
-
| `deploy.config` | `DeployConfig \| null` | 当前配置 |
|
|
190
|
-
| `deploy.isInitialized` | `boolean` | 初始化状态 |
|
|
78
|
+
## 离线交付与验证
|
|
191
79
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
所有凭证操作都通过 `deploy.credentials.*` 访问,模块入口不再单独导出自由函数。
|
|
195
|
-
|
|
196
|
-
> `deploy.credentials.*()` 与 `deploy.scan()` 都不依赖 `deploy.init()`,可用于 CLI 在读取 `_deploy.yml` 之前准备环境。
|
|
197
|
-
|
|
198
|
-
## 配置消费与失败恢复
|
|
199
|
-
|
|
200
|
-
云资源配置消费:Neon 输出 HAI_DB(PostgreSQL JSON),Upstash 输出 HAI_CACHE(Redis rediss URL JSON),R2 输出 HAI_STORAGE(扁平 S3 JSON)。邮件/短信输出 HAI_REACH_PROVIDERS 数组,deployApp 合并两个渠道并保留 YAML 中的消息模板;此覆盖替换原 providers 数组。Core 支持整体对象/数组覆盖,父节点优先于叶子变量,仍执行 Schema 校验;构建子进程与目标运行环境使用相同开通结果。R2 必须提供已有 S3 accessKeyId/secretAccessKey;Resend 必须提供已验证域名的 from;阿里云必须提供已审核 signName/模板。应用须已有相应 _db/_cache/_storage/_reach.yml 并在启动时加载,网络客户端需要 Node 运行时。
|
|
201
|
-
|
|
202
|
-
部署失败恢复:`ProvisionResult.resourceStatus` 标记 created/reused;`getDeployRecovery(result.error)` 读取 projectName、stage、platformProjectId 和资源清单,unknown 表示请求结果不确定,必须先在服务商控制台核对。失败资源已返回 ID 时保留该 ID。恢复结果不含 envVars、原始异常或连接凭证,CLI 会展示清单和建议。同名重试复用现有资源;不自动删除复用资源,新建资源仅在人工确认未被使用后清理。
|
|
203
|
-
|
|
204
|
-
## 错误码 — `HaiDeployError`
|
|
205
|
-
|
|
206
|
-
| 错误码 | code | 说明 |
|
|
207
|
-
| --------------------------------------- | ------------------ | ------------------------ |
|
|
208
|
-
| `HaiDeployError.DEPLOY_FAILED` | `hai:deploy:001` | 部署失败(通用) |
|
|
209
|
-
| `HaiDeployError.PROJECT_CREATE_FAILED` | `hai:deploy:002` | 平台项目创建失败 |
|
|
210
|
-
| `HaiDeployError.BUILD_FAILED` | `hai:deploy:003` | 应用构建失败 |
|
|
211
|
-
| `HaiDeployError.UPLOAD_FAILED` | `hai:deploy:004` | 构建产物上传失败 |
|
|
212
|
-
| `HaiDeployError.AUTH_REQUIRED` | `hai:deploy:005` | 未认证 |
|
|
213
|
-
| `HaiDeployError.AUTH_FAILED` | `hai:deploy:006` | 认证失败 |
|
|
214
|
-
| `HaiDeployError.PROVISION_FAILED` | `hai:deploy:007` | 基础设施开通失败 |
|
|
215
|
-
| `HaiDeployError.ADAPTER_MISSING` | `hai:deploy:008` | SvelteKit adapter 未安装 |
|
|
216
|
-
| `HaiDeployError.SCAN_FAILED` | `hai:deploy:009` | 应用扫描失败 |
|
|
217
|
-
| `HaiDeployError.NOT_INITIALIZED` | `hai:deploy:010` | 模块未初始化 |
|
|
218
|
-
| `HaiDeployError.ENV_VAR_FAILED` | `hai:deploy:011` | 环境变量设置失败 |
|
|
219
|
-
| `HaiDeployError.UNSUPPORTED_TYPE` | `hai:deploy:012` | 不支持的类型 |
|
|
220
|
-
| `HaiDeployError.CONFIG_ERROR` | `hai:deploy:013` | 配置错误 |
|
|
221
|
-
| `HaiDeployError.CREDENTIAL_ERROR` | `hai:deploy:014` | 凭证读写失败 |
|
|
222
|
-
| `HaiDeployError.CONTAINER_RUNTIME_NOT_FOUND` | `hai:deploy:015` | 未找到容器运行时 |
|
|
223
|
-
| `HaiDeployError.CONTAINER_BUILD_FAILED` | `hai:deploy:016` | 镜像构建失败 |
|
|
224
|
-
| `HaiDeployError.REMOTE_CONNECT_FAILED` | `hai:deploy:017` | 远程连接失败 |
|
|
225
|
-
| `HaiDeployError.REMOTE_COMMAND_FAILED` | `hai:deploy:018` | 远程命令失败 |
|
|
226
|
-
| `HaiDeployError.IMAGE_TRANSFER_FAILED` | `hai:deploy:019` | 镜像传输失败 |
|
|
227
|
-
| `HaiDeployError.HEALTH_CHECK_FAILED` | `hai:deploy:020` | 健康检查未通过 |
|
|
228
|
-
|
|
229
|
-
## CLI 命令
|
|
230
|
-
|
|
231
|
-
通过 CLI 部署前,先按 [CLI 安装与命令](../hai-app-create/development.md#cli-安装与命令) 全局安装 `@h-ai/cli`,确认 `hai --version` 可运行后再执行下列命令。在 Node.js 脚本中直接使用 `@h-ai/deploy` API 时无需安装 CLI。
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
# 部署当前目录
|
|
235
|
-
hai deploy
|
|
236
|
-
|
|
237
|
-
# 部署指定应用
|
|
238
|
-
hai deploy ./apps/admin-console --env test
|
|
239
|
-
|
|
240
|
-
# 跳过基础设施开通
|
|
241
|
-
hai deploy --env prod --skip-provision
|
|
242
|
-
|
|
243
|
-
# 仅 Vercel:跳过应用构建;docker-ssh 仍会构建镜像
|
|
244
|
-
hai deploy --env prod --skip-build
|
|
245
|
-
|
|
246
|
-
# 自定义项目名
|
|
247
|
-
hai deploy --project-name my-custom-name
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
> 部署方式由 `config/_deploy.yml` 的 `provider.type` 决定(vercel / docker-ssh),
|
|
251
|
-
> CLI 命令相同。docker-ssh 成功后输出的访问地址为 `http://<host>:<hostPort>`。
|
|
252
|
-
|
|
253
|
-
fullstack 需明确部署服务包;`hai deploy packages/my-app-serv --env prod` 不会发布 Web。根 Dockerfile 的 `runtime` / `web` target 分别构建 API / Web;Web 单独转移、运行,设置浏览器可访问的 `PUBLIC_API_BASE` 和 API 的 CORS。模板 `pnpm run deploy` 是打包脚本,不等于 CLI 发布。
|
|
254
|
-
|
|
255
|
-
离线部署先按 [离线准备与验收](middleware.md#离线准备与验收) 检查材料。docker-ssh 在本地构建并导出镜像 tar,再分别上传镜像、Compose、运行环境和启动脚本,不在远程构建源码。当前无直接指定预构建镜像的参数;不得声称 `--skip-build` 能离线发布容器,也不得将联网部署测试作为断网证明。
|
|
256
|
-
|
|
257
|
-
## 常见模式
|
|
258
|
-
|
|
259
|
-
### 仅部署(跳过基础设施)
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
await deploy.deployApp('./apps/my-app', { skipProvision: true })
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### 仅开通基础设施
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
await deploy.init(config)
|
|
269
|
-
const result = await deploy.provisionAll('my-project')
|
|
270
|
-
// 手动使用 result.data 中的环境变量
|
|
271
|
-
await deploy.close()
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### 自定义部署流程
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
import { deploy } from '@h-ai/deploy'
|
|
278
|
-
|
|
279
|
-
// Provider 通过 init 配置自动创建,不需要手动导入
|
|
280
|
-
await deploy.init({
|
|
281
|
-
provider: { type: 'vercel', token: 'vel_xxx' },
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
// 使用 deploy API 部署
|
|
285
|
-
const result = await deploy.deployApp('./apps/my-app')
|
|
286
|
-
```
|
|
80
|
+
部署器不需要本地容器引擎;提前从构建机复制完整 `.hai/build/docker/<buildId>`。Linux 准备 Docker/Podman、compose、sh、tar、sha256sum、所需中间件镜像的准确标签及数据目录权限。手工包含私有配置,权限受限,不提交 Git。启动脚本校验文件、加载 app/web、检查镜像存在并导出环境标识;缺镜像时停止,不联网拉取。
|
|
287
81
|
|
|
288
|
-
|
|
82
|
+
完全离线构建另需基础镜像、Linux 依赖缓存、pnpm 和匹配 ABI/libc 的 SQLite 预编译包;Windows node_modules 不能替代。生产 HTTPS、CORS、证书和 DNS 另行配置。实际断网后验收登录、刷新、重启与持久化,不能将联网测试当作离线证明。
|
|
289
83
|
|
|
290
|
-
|
|
291
|
-
- **hai-reldb** — 数据库(Neon PostgreSQL)
|
|
292
|
-
- **hai-cache** — 缓存(Upstash Redis)
|
|
84
|
+
改动后执行 typecheck、lint、build、test,模板执行 scaffold gates,部署流程执行 test:deploy-gates;真实 Tauri 安装包按系统单独验证。所有测试临时工程、镜像、容器、辅助进程、截图、日志和报告必须在 finally/teardown 自动清理,失败/取消同样清理。不得把验收产物提交 Git,也不得清理用户既有资源。
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
2. **使用自定义配置**:逐项输入所选后端的连接字段,展示变量名、字段用途与约束,校验必填项、端口、布尔和 URL;凭据用密码输入。保存配置后跳过该服务的开通与 sidecar。
|
|
30
30
|
3. **保持不变**:仅在目标 `.env.<mode>` 显式声明当前后端及完整连接配置时出现;私有凭据可来自 `.env.local`/进程。选择后不修改该项、不认证其 Provisioner、不创建或移除已有中间件容器,继续下一项。只有 `.env` 或其他环境有配置不满足此条件。
|
|
31
31
|
|
|
32
|
-
逐项配置前提供“环境配置已完备,直接部署”。选择后跳过全部中间件提示、变量改写、云资源与 sidecar
|
|
32
|
+
逐项配置前提供“环境配置已完备,直接部署”。选择后跳过全部中间件提示、变量改写、云资源与 sidecar 创建,保留已有服务;仍校验已有构建产物并执行部署及健康检查。命令行使用唯一的 `--skip-middleware`,SDK 使用 `skipMiddleware`。不要因为缺少某项中间件的目标文件声明而阻止用户主动跳过。
|
|
33
33
|
|
|
34
34
|
`--yes` 用于已授权的自动化:目标环境已有完整配置时保持不变,否则使用当前后端默认配置;不支持的云后端或缺少必需凭据直接失败。自动化直接部署用 `hai deploy packages/my-app-serv --env prod --yes --skip-middleware`。跳过不作为配置完整性或连接成功的证明。
|
|
35
35
|
|
|
@@ -71,24 +71,18 @@ S3 是协议,不是某个容器产品。默认配置时另选 RustFS/MinIO,
|
|
|
71
71
|
|
|
72
72
|
## 离线准备与验收
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
构建与部署分开:先在构建机运行 `pnpm build --target docker`,将完整 `.hai/build/docker/<buildId>` 复制到部署电脑。deploy 只读取这些已校验的镜像 tar,不需要本地 Docker/Podman、基础镜像、pnpm store 或 SQLite 下载。Node/pnpm 版本以工程 engines/packageManager 为准。
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
`pnpm run deploy --env prod --bundle-only --output release-prod.tar` 按清单 appVersion 自动生成 release-prod-1.2.3.tar(示例版本 1.2.3),包含 app/web、docker-compose-1.2.3.yml、manifest.json、私有 env、校验和、README 与 start-prod.sh,不连接 SSH。搬到 Linux 后,创建权限 700 的目录,`tar -xf release-prod-1.2.3.tar -C release`,`cd release && sh start-prod.sh`。脚本自动指定带版本的 Compose;手工状态检查使用 `docker compose -f docker-compose-1.2.3.yml --env-file .env.runtime ps`。启动脚本可用 HAI_DEPLOY_PROVIDER_REMOTE_RUNTIME=docker/podman 选择运行时,镜像缺少时停止,不尝试联网。
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Linux 需要 compose、sh、tar、sha256sum 和容器/目录/持久化磁盘权限;中间件镜像另行 docker load,名称、tag 和架构须与包内清单一致。自定义连接要求现有服务可从应用容器访问,并备好账号、数据库、S3 桶与密钥。云 Provider/Provisioner 需要网络,不能用于完全离线。
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
fullstack 的 Web 不在服务包 `hai deploy` 中发布,需单独加载/运行 Web 镜像并设置 PUBLIC_API_BASE、API CORS。生产禁止通配 CORS,refresh Cookie 启用 Secure;须准备 HTTPS 入口、内网证书/信任与 DNS/hosts,SDK 不自动配置 TLS/反向代理。离线验收须包含断外网构建/上传/启动、API 健康、真实 Web 登录、页面与会话刷新、重启和持久化;分别报告 API 部署、Web 发布和断网证据,不能互相替代。
|
|
80
|
+
如连构建也需离线,构建机另准备 Linux 容器引擎、Node/Nginx 基础镜像、pnpm/Corepack、完整 Linux 依赖缓存和匹配 SQLite 驱动/Node ABI/架构/libc 的预编译包。可用构建参数 `--sqlite-prebuild-mirror <可信HTTP(S)地址>` 指定二进制根目录;失败应修复缓存/网络,不能让 deploy 下载编译环境。构建无需选择环境;Podman 代理不可达时用 `pnpm build --target docker --no-http-proxy`,不修改系统代理。
|
|
83
81
|
|
|
84
82
|
## 启动与验证
|
|
85
83
|
|
|
86
|
-
fullstack
|
|
87
|
-
|
|
88
|
-
Podman 构建默认继承运行时代理。代理地址在容器内不可达时,在 `_deploy.yml` 配置 `container.httpProxy: false`(已声明该节点时也可使用 `HAI_DEPLOY_CONTAINER_HTTPPROXY=false`),不要修改用户的系统代理。`loadDeploymentEnvironment`、`loadDeploymentConfig`、`saveDeploymentEnvironment` 可用于脚本显式读取、解析和保存同一份部署配置,均返回 HaiResult。
|
|
89
|
-
|
|
90
|
-
构建上下文必须排除 `.env.local`、`.env.*.local`、`.env.runtime` 和 `.hai/deploy`(含镜像归档与凭据);公共环境文件仍可进入上下文。兜底 Dockerfile 使用伴随忽略文件,Podman 通过 `--ignorefile` 显式指定,避免使用 workspace 根规则后把上次部署的归档或运行配置重新打进构建层。
|
|
84
|
+
fullstack 的 hai.build.json 含 app/web 时,两镜像共用构建 ID,部署生成一个 Compose 和同源代理。API 前缀来自当前服务配置,缺省 CORS 填公开入口,明确 Origin 保留;Web 不挂载 .env.runtime。线上成功要求 API/Web 健康,手工模式返回 packaged 并提示用户自行验收。生产登录刷新还需 HTTPS、正确 CORS、受信证书与 DNS/hosts,模块不配置 TLS。
|
|
91
85
|
|
|
92
|
-
|
|
86
|
+
容器运行期 NODE_ENV=production;HAI_DEPLOY_ENVIRONMENT 保存文件模式,HAI_CORE_ENV 映射 development/test/production/staging。资源名附环境后缀,卷按环境隔离;私有 env 权限 600。构建上下文排除 .env.local、环境覆盖、.env.runtime、.hai/build、.hai/deploy 和 data,不把运行期凭据写入镜像。
|
|
93
87
|
|
|
94
|
-
|
|
88
|
+
修改后运行 deploy/CLI typecheck、lint、build、test、scaffold gates 和 test:deploy-gates。测试应分别证明构建/环境选择、SSH 上传及手工包启动、Web 登录/刷新;断网能力另做实际断网验收。测试的临时工程、容器、镜像、日志、截图、报告与辅助进程必须 finally/teardown 自动清理,失败也清理;不得删除用户已有资源。原生客户端及付费云资源单独验收并报告边界。
|
|
@@ -606,6 +606,8 @@ AuthPanel 直接接收 IAM 白名单配置和 actions,内置登录(密码/LD
|
|
|
606
606
|
|
|
607
607
|
AuthPanel 在 SSR 阶段禁用原生表单控件,客户端挂载并绑定事件后自动开放输入,避免接管时丢失早到的输入。应用无需额外的就绪适配;E2E 等待控件可编辑,并覆盖客户端脚本延迟加载的场景。
|
|
608
608
|
|
|
609
|
+
认证链接指向当前完整 URL 时,AuthPanel 只切换场景并阻止重复导航,返回登录后可立即输入。路径、查询串或 hash 不同时交给应用路由处理;Ctrl/Cmd 等修改键点击保留浏览器行为。不要为切换场景额外调用 goto 或 location.reload。
|
|
610
|
+
|
|
609
611
|
|
|
610
612
|
协议在 Modal 内显示并保留表单输入;使用 URL 时,协议页面须允许 iframe 嵌入,组件禁用其脚本,另提供新窗口查看入口。登录/注册表单使用 `header/extraFields/footer` snippet,AuthPanel 透传 `loginHeader/loginFields/loginFooter` 和 `registerHeader/registerFields/registerFooter`,底部保留内置导航。自定义字段由应用绑定状态和提交,不会隐式写入 IAM 用户模型。
|
|
611
613
|
|