@h-ai/deploy 0.1.0-alpha.56 → 0.1.0-alpha.57

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 ADDED
@@ -0,0 +1,243 @@
1
+ # @h-ai/deploy
2
+
3
+ [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
4
+
5
+ [Framework home](../../README.en.md) · Related modules: [@h-ai/core](../core/README.en.md)
6
+
7
+ An automated deployment module with two targets: deploy SvelteKit apps to Vercel with cloud infrastructure provisioning, or containerize and deploy to any Linux host over SSH (docker-ssh).
8
+
9
+ ## Deployment targets
10
+
11
+ | Provider | Target | Description |
12
+ | ------------ | --------------- | ------------------------------------------------------------- |
13
+ | `vercel` | Vercel platform | SvelteKit + adapter-vercel with cloud provisioners |
14
+ | `docker-ssh` | Any Linux host | SvelteKit + adapter-node, containerized and deployed over SSH |
15
+
16
+ ## Cloud services (provisioners)
17
+
18
+ | Service type | Provisioner | Description |
19
+ | ------------ | ------------- | ------------------------------- |
20
+ | Database | Neon | PostgreSQL Serverless |
21
+ | Cache | Upstash | Redis TCP + TLS |
22
+ | Storage | Cloudflare R2 | S3-compatible object storage |
23
+ | Email | Resend | SMTP (existing verified domain) |
24
+ | SMS | Alibaba Cloud | Alibaba Cloud SMS |
25
+
26
+ ## Quick start
27
+
28
+ ```typescript
29
+ import { deploy } from '@h-ai/deploy'
30
+
31
+ // 可选:从 ~/.hai/credentials.yml 注入 HAI_DEPLOY_* 环境变量
32
+ deploy.credentials.load()
33
+
34
+ // 初始化
35
+ await deploy.init({
36
+ provider: { type: 'vercel', token: 'vel_xxx' },
37
+ services: {
38
+ db: { provisioner: 'neon', apiKey: 'neon_xxx' },
39
+ cache: { provisioner: 'upstash', email: 'a@b.com', apiKey: 'up_xxx' },
40
+ },
41
+ })
42
+
43
+ // 扫描应用依赖
44
+ const scan = await deploy.scan('./apps/my-app')
45
+
46
+ // 开通基础设施
47
+ const provisions = await deploy.provisionAll('my-app')
48
+
49
+ // 完整部署
50
+ const result = await deploy.deployApp('./apps/my-app')
51
+
52
+ await deploy.close()
53
+ ```
54
+
55
+ ## Configuration
56
+
57
+ Keep Git-safe configuration in `config/_deploy.yml` and secrets in `~/.hai/credentials.yml`:
58
+
59
+ ```yaml
60
+ # config/_deploy.yml
61
+ provider:
62
+ type: vercel
63
+ token: ${HAI_DEPLOY_VERCEL_TOKEN}
64
+
65
+ services:
66
+ db:
67
+ provisioner: neon
68
+ apiKey: ${HAI_DEPLOY_NEON_API_KEY}
69
+ cache:
70
+ provisioner: upstash
71
+ email: ${HAI_DEPLOY_UPSTASH_EMAIL}
72
+ apiKey: ${HAI_DEPLOY_UPSTASH_API_KEY}
73
+ ```
74
+
75
+ These variables are explicit special mappings managed by `deploy.credentials`. If convention-based variables
76
+ such as `HAI_DEPLOY_PROVIDER_TOKEN` are also set, the convention-based variables take precedence.
77
+
78
+ Use `deploy.credentials.*` to manage credential files explicitly in scripts or the CLI:
79
+
80
+ ```typescript
81
+ deploy.credentials.load()
82
+ deploy.credentials.save('HAI_DEPLOY_VERCEL_TOKEN', 'vel_xxx')
83
+ deploy.credentials.saveAll({
84
+ HAI_DEPLOY_NEON_API_KEY: 'neon_xxx',
85
+ })
86
+ ```
87
+
88
+ > `deploy.scan()` and `deploy.credentials.*()` use the local filesystem and do not require `deploy.init()`.
89
+
90
+ ## docker-ssh deployment
91
+
92
+ Containerize the application and deploy over SSH to any Linux host; no cloud account is required.
93
+
94
+ ### Prerequisites
95
+
96
+ - **Local**: install docker or podman (`auto` prefers podman).
97
+ - **Remote host**: SSH access, docker/podman and compose installed, and a login user permitted to run containers.
98
+ - **Application**: SvelteKit must use `@sveltejs/adapter-node` (covered by the supplied `Dockerfile`); otherwise `ADAPTER_MISSING` is returned.
99
+
100
+ ### Steps
101
+
102
+ 1. Store the SSH private key path in the credential file, outside the repository. Edit `~/.hai/credentials.yml` or use the API:
103
+
104
+ ```typescript
105
+ deploy.credentials.save('HAI_DEPLOY_SSH_KEY', '~/.ssh/hai_deploy')
106
+ ```
107
+
108
+ 2. Declare the target host in `config/_deploy.yml`:
109
+
110
+ ```yaml
111
+ provider:
112
+ type: docker-ssh
113
+ ssh:
114
+ host: 10.0.0.20 # 主机 IP 或 ~/.ssh/config 别名
115
+ port: 22
116
+ username: deploy
117
+ identityFile: ${HAI_DEPLOY_SSH_KEY} # 私钥文件路径,省略则用 ssh-agent
118
+ remote:
119
+ baseDir: /opt/hai/apps # 远程部署根目录
120
+ runtime: auto # 远程运行时;auto 优先 podman,其次 docker
121
+ expose:
122
+ type: port
123
+ containerPort: 3000 # 容器内端口(adapter-node 默认 3000)
124
+ hostPort: 18080 # 宿主机端口 → 访问地址 http://10.0.0.20:18080
125
+
126
+ container:
127
+ runtime: auto # 本地构建运行时(可选)
128
+
129
+ services: {} # 启用的服务会自动生成 compose sidecar,见下
130
+ ```
131
+
132
+ 3. Deploy and verify with the CLI or API (equivalent behavior):
133
+
134
+ ```bash
135
+ hai deploy # 读取 config/_deploy.yml,输出访问地址
136
+ ```
137
+
138
+ ```typescript
139
+ import { deploy } from '@h-ai/deploy'
140
+
141
+ deploy.credentials.load() // 注入 HAI_DEPLOY_* 环境变量
142
+ await deploy.init(dockerSshConfig)
143
+ const result = await deploy.deployApp('./apps/my-app')
144
+ if (result.success) {
145
+ result.data.url // http://<host>:<hostPort>
146
+ result.data.healthCheck // 'passed'(HTTP 探测成功)
147
+ }
148
+ await deploy.close()
149
+ ```
150
+
151
+ ### How it works
152
+
153
+ For docker-ssh, `deployApp()` runs these steps:
154
+
155
+ 1. **Scan**: read `package.json` and `config/*.yml` to identify `@sveltejs/adapter-node`, required services, and backend types.
156
+ 2. **Local build**: use the project's `Dockerfile` to build `hai-<app>:<deploymentId>` (podman adds `--format docker --jobs=1`).
157
+ 3. **Export**: save the image as tar with `docker/podman save`.
158
+ 4. **Preflight**: verify SSH connectivity and remote `docker/podman version` / `compose version`.
159
+ 5. **Transfer/load**: upload tar with `scp`, load remotely, and retag under `localhost/` to avoid accidental registry pulls.
160
+ 6. **Runtime files**: generate `compose.yml` (app + sidecars) and `.env.runtime` (including `HAI_*` overrides and credentials), upload to `<baseDir>/<app>/`, and set `.env.runtime` permissions to `600`.
161
+ 7. **Start**: `compose up -d` with fixed project name `hai-<app>` for idempotent redeployment.
162
+ 8. **Health check**: poll `http://<host>:<hostPort>/`; only HTTP 200 yields `ready`.
163
+
164
+ > Images, `compose.yml`, and `.env.runtime` are stored in the application's `.hai/deploy/`, excluded by the template `.gitignore`.
165
+
166
+ ### Feature-based compose sidecars
167
+
168
+ `deploy.scan()` identifies services and their **actual backend types** (`type` in `_db.yml` / `_vecdb.yml`, etc.), generates matching sidecars, and injects `HAI_*` overrides:
169
+
170
+ | Detected service | Backend (`type`) | Added sidecar | Injected variables |
171
+ | ---------------- | ---------------- | ------------------------------- | ------------------ |
172
+ | `db` | `postgresql` | `postgres:16-alpine` | `HAI_DB` |
173
+ | `db` | `mysql` | `mysql:8.4` | `HAI_DB` |
174
+ | `db` | `sqlite` | None (mount `/app/data` volume) | — |
175
+ | `cache` | `redis` | `redis:7-alpine` | `HAI_CACHE` |
176
+ | `storage` | `s3` | `minio` + bucket initialization | `HAI_STORAGE` |
177
+ | `vecdb` | `qdrant` | `qdrant/qdrant` | `HAI_VECDB` |
178
+ | `vecdb` | `pgvector` | `pgvector/pgvector` | `HAI_VECDB` |
179
+ | `vecdb` | `chroma` | `chromadb/chroma` | `HAI_VECDB` |
180
+ | `vecdb` | `lancedb` | None (mount `/app/data` volume) | — |
181
+
182
+ - Memory `cache` and external email/SMS `reach` APIs do not generate sidecars.
183
+ - Existing cloud provisioners take precedence (for example Neon providing `HAI_DB`); no duplicate sidecar is created.
184
+ - Sidecar secrets such as passwords go only in remote `.env.runtime` (`600`), never `compose.yml`.
185
+
186
+ > Security: `identityFile` is a private key **path**, not key content. `strictHostKeyChecking: true` (default)
187
+ > uses accept-new: trust first use and reject changed keys. You may connect once manually with `ssh` for an unknown host.
188
+
189
+ ## Error handling
190
+
191
+ ```typescript
192
+ import { HaiDeployError } from '@h-ai/deploy'
193
+
194
+ const result = await deploy.deployApp('./apps/my-app')
195
+ if (!result.success) {
196
+ switch (result.error.code) {
197
+ case HaiDeployError.AUTH_FAILED.code:
198
+ // Vercel Token 无效
199
+ break
200
+ case HaiDeployError.BUILD_FAILED.code:
201
+ // 构建失败
202
+ break
203
+ }
204
+ }
205
+ ```
206
+
207
+ Common error codes:
208
+
209
+ | Error code | code | Description |
210
+ | --------------------------------- | ---------------- | ------------------------------------- |
211
+ | `HaiDeployError.DEPLOY_FAILED` | `hai:deploy:001` | Deployment failed |
212
+ | `HaiDeployError.BUILD_FAILED` | `hai:deploy:003` | Build failed |
213
+ | `HaiDeployError.AUTH_FAILED` | `hai:deploy:006` | Authentication failed |
214
+ | `HaiDeployError.PROVISION_FAILED` | `hai:deploy:007` | Provisioning failed |
215
+ | `HaiDeployError.NOT_INITIALIZED` | `hai:deploy:010` | Not initialized |
216
+ | `HaiDeployError.ENV_VAR_FAILED` | `hai:deploy:011` | Environment variable operation failed |
217
+
218
+ docker-ssh-specific error codes:
219
+
220
+ | Error code | code | Description |
221
+ | -------------------------------------------- | ---------------- | --------------------------- |
222
+ | `HaiDeployError.CONTAINER_RUNTIME_NOT_FOUND` | `hai:deploy:015` | Container runtime not found |
223
+ | `HaiDeployError.CONTAINER_BUILD_FAILED` | `hai:deploy:016` | Image build failed |
224
+ | `HaiDeployError.REMOTE_CONNECT_FAILED` | `hai:deploy:017` | Remote connection failed |
225
+ | `HaiDeployError.REMOTE_COMMAND_FAILED` | `hai:deploy:018` | Remote command failed |
226
+ | `HaiDeployError.IMAGE_TRANSFER_FAILED` | `hai:deploy:019` | Image transfer failed |
227
+ | `HaiDeployError.HEALTH_CHECK_FAILED` | `hai:deploy:020` | Health check failed |
228
+
229
+ ## Tests
230
+
231
+ ```bash
232
+ pnpm --filter @h-ai/deploy test
233
+ ```
234
+
235
+ ## License
236
+
237
+ Apache-2.0
238
+
239
+ Provisioned configuration: Neon emits HAI_DB (PostgreSQL JSON), Upstash HAI_CACHE (Redis rediss URL JSON), and R2 HAI_STORAGE (flat S3 JSON). Email/SMS emit HAI_REACH_PROVIDERS; deployApp merges both channels while preserving YAML message templates, replacing the original providers array. Core supports whole-object/array overrides, with parents preceding leaves and schema validation retained. Build subprocesses and target runtimes share provisioned values. R2 needs existing S3 accessKeyId/secretAccessKey, Resend a verified-domain from address, and Alibaba Cloud approved signName/templates. Applications need matching `_db.yml` / `_cache.yml` / `_storage.yml` / `_reach.yml` loaded at startup; network clients require Node.
240
+
241
+ Configuration references: [Upstash TLS](https://upstash.com/docs/redis/features/security), [Resend SMTP](https://resend.com/docs/send-with-smtp). Deterministic acceptance generates real applications and validates Core and module schemas. It does not create cloud resources or send email/SMS, so it does not establish cloud read/write acceptance.
242
+
243
+ Deployment recovery: `ProvisionResult.resourceStatus` marks created/reused. `getDeployRecovery(result.error)` reads projectName, stage, platformProjectId, and resource lists; unknown means an uncertain request result that must first be checked in the provider console. Preserve returned IDs for failed resources. Recovery excludes envVars, raw exceptions, and credentials; the CLI shows resources and advice. Same-name retries reuse resources. Reused resources are never deleted automatically; clean up newly created resources only after manually confirming they are unused.
package/README.ja.md ADDED
@@ -0,0 +1,243 @@
1
+ # @h-ai/deploy
2
+
3
+ [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
4
+
5
+ [フレームワークのホーム](../../README.ja.md) · 関連モジュール:[@h-ai/core](../core/README.ja.md)
6
+
7
+ 自動デプロイモジュールです。SvelteKit アプリをクラウド基盤の作成とともに Vercel へ展開する方式と、コンテナー化して任意の Linux ホストへ SSH で展開する方式(docker-ssh)に対応します。
8
+
9
+ ## 対応デプロイ方式
10
+
11
+ | Provider | 展開先 | 説明 |
12
+ | ------------ | ------------------- | ------------------------------------------------------- |
13
+ | `vercel` | Vercel | SvelteKit + adapter-vercel、クラウド Provisioner と連携 |
14
+ | `docker-ssh` | 任意の Linux ホスト | SvelteKit + adapter-node、コンテナー化して SSH で展開 |
15
+
16
+ ## 対応クラウドサービス(Provisioner)
17
+
18
+ | サービス種別 | Provisioner | 説明 |
19
+ | ------------ | ------------- | ------------------------------ |
20
+ | データベース | Neon | PostgreSQL Serverless |
21
+ | キャッシュ | Upstash | Redis TCP + TLS |
22
+ | ストレージ | Cloudflare R2 | S3 互換オブジェクトストレージ |
23
+ | メール | Resend | SMTP(検証済みドメインが必要) |
24
+ | SMS | Alibaba Cloud | Alibaba Cloud SMS |
25
+
26
+ ## クイックスタート
27
+
28
+ ```typescript
29
+ import { deploy } from '@h-ai/deploy'
30
+
31
+ // 可选:从 ~/.hai/credentials.yml 注入 HAI_DEPLOY_* 环境变量
32
+ deploy.credentials.load()
33
+
34
+ // 初始化
35
+ await deploy.init({
36
+ provider: { type: 'vercel', token: 'vel_xxx' },
37
+ services: {
38
+ db: { provisioner: 'neon', apiKey: 'neon_xxx' },
39
+ cache: { provisioner: 'upstash', email: 'a@b.com', apiKey: 'up_xxx' },
40
+ },
41
+ })
42
+
43
+ // 扫描应用依赖
44
+ const scan = await deploy.scan('./apps/my-app')
45
+
46
+ // 开通基础设施
47
+ const provisions = await deploy.provisionAll('my-app')
48
+
49
+ // 完整部署
50
+ const result = await deploy.deployApp('./apps/my-app')
51
+
52
+ await deploy.close()
53
+ ```
54
+
55
+ ## 設定
56
+
57
+ Git に保存できる設定は `config/_deploy.yml`、秘密情報は `~/.hai/credentials.yml` で管理します:
58
+
59
+ ```yaml
60
+ # config/_deploy.yml
61
+ provider:
62
+ type: vercel
63
+ token: ${HAI_DEPLOY_VERCEL_TOKEN}
64
+
65
+ services:
66
+ db:
67
+ provisioner: neon
68
+ apiKey: ${HAI_DEPLOY_NEON_API_KEY}
69
+ cache:
70
+ provisioner: upstash
71
+ email: ${HAI_DEPLOY_UPSTASH_EMAIL}
72
+ apiKey: ${HAI_DEPLOY_UPSTASH_API_KEY}
73
+ ```
74
+
75
+ ここでの変数は `deploy.credentials` が管理する明示的な特殊マッピングです。YAML パスから生成する
76
+ `HAI_DEPLOY_PROVIDER_TOKEN` なども指定した場合、規約に沿う変数が優先されます。
77
+
78
+ スクリプト・CLI で認証情報ファイルを明示的に管理するには `deploy.credentials.*` を使います:
79
+
80
+ ```typescript
81
+ deploy.credentials.load()
82
+ deploy.credentials.save('HAI_DEPLOY_VERCEL_TOKEN', 'vel_xxx')
83
+ deploy.credentials.saveAll({
84
+ HAI_DEPLOY_NEON_API_KEY: 'neon_xxx',
85
+ })
86
+ ```
87
+
88
+ > `deploy.scan()` と `deploy.credentials.*()` はローカルファイルシステムの機能で、`deploy.init()` に依存しません。
89
+
90
+ ## docker-ssh デプロイ
91
+
92
+ アプリをコンテナー化して SSH で任意の Linux ホストへ展開します。クラウドアカウントは不要です。
93
+
94
+ ### 前提条件
95
+
96
+ - **ローカル**:docker または podman をインストール(`auto` は podman を優先)。
97
+ - **リモート**:SSH 接続可能、docker/podman と compose が導入済み、ログインユーザーがコンテナーを実行可能。
98
+ - **アプリ**:SvelteKit に `@sveltejs/adapter-node` を使用(付属 `Dockerfile` は対応済み)。不足時は `ADAPTER_MISSING`。
99
+
100
+ ### 使用手順
101
+
102
+ 1. SSH 秘密鍵のパスをリポジトリー外の認証情報ファイルに保存します。`~/.hai/credentials.yml` を編集するか API を使います:
103
+
104
+ ```typescript
105
+ deploy.credentials.save('HAI_DEPLOY_SSH_KEY', '~/.ssh/hai_deploy')
106
+ ```
107
+
108
+ 2. `config/_deploy.yml` に対象ホストを定義します:
109
+
110
+ ```yaml
111
+ provider:
112
+ type: docker-ssh
113
+ ssh:
114
+ host: 10.0.0.20 # 主机 IP 或 ~/.ssh/config 别名
115
+ port: 22
116
+ username: deploy
117
+ identityFile: ${HAI_DEPLOY_SSH_KEY} # 私钥文件路径,省略则用 ssh-agent
118
+ remote:
119
+ baseDir: /opt/hai/apps # 远程部署根目录
120
+ runtime: auto # 远程运行时;auto 优先 podman,其次 docker
121
+ expose:
122
+ type: port
123
+ containerPort: 3000 # 容器内端口(adapter-node 默认 3000)
124
+ hostPort: 18080 # 宿主机端口 → 访问地址 http://10.0.0.20:18080
125
+
126
+ container:
127
+ runtime: auto # 本地构建运行时(可选)
128
+
129
+ services: {} # 启用的服务会自动生成 compose sidecar,见下
130
+ ```
131
+
132
+ 3. CLI または API で展開・検証します(動作は同じ):
133
+
134
+ ```bash
135
+ hai deploy # 读取 config/_deploy.yml,输出访问地址
136
+ ```
137
+
138
+ ```typescript
139
+ import { deploy } from '@h-ai/deploy'
140
+
141
+ deploy.credentials.load() // 注入 HAI_DEPLOY_* 环境变量
142
+ await deploy.init(dockerSshConfig)
143
+ const result = await deploy.deployApp('./apps/my-app')
144
+ if (result.success) {
145
+ result.data.url // http://<host>:<hostPort>
146
+ result.data.healthCheck // 'passed'(HTTP 探测成功)
147
+ }
148
+ await deploy.close()
149
+ ```
150
+
151
+ ### 処理の流れ
152
+
153
+ docker-ssh の `deployApp()` は次の順で処理します:
154
+
155
+ 1. **走査**:`package.json` と `config/*.yml` から `@sveltejs/adapter-node`、必要なサービス、バックエンド種別を判定。
156
+ 2. **ローカルビルド**:プロジェクトの `Dockerfile` で `hai-<app>:<deploymentId>` を作成(podman は `--format docker --jobs=1` を追加)。
157
+ 3. **出力**:`docker/podman save` で tar に保存。
158
+ 4. **事前確認**:SSH 接続とリモートの `docker/podman version` / `compose version` を確認。
159
+ 5. **転送・読み込み**:`scp` で tar を転送し、リモートで `load` 後、誤った registry 取得を防ぐため `localhost/` タグを付与。
160
+ 6. **実行定義**:走査結果から `compose.yml`(app + sidecar)と `.env.runtime`(`HAI_*` 上書き・認証情報)を生成し、`<baseDir>/<app>/` に転送。`.env.runtime` は `600` に設定。
161
+ 7. **起動**:固定プロジェクト名 `hai-<app>` で `compose up -d`。再展開は冪等。
162
+ 8. **ヘルスチェック**:`http://<host>:<hostPort>/` を監視し、200 応答でのみ `ready` と判定。
163
+
164
+ > イメージ、`compose.yml`、`.env.runtime` はアプリの `.hai/deploy/` に保存し、テンプレートの `.gitignore` で除外済みです。
165
+
166
+ ### 機能に応じた compose sidecar
167
+
168
+ `deploy.scan()` は必要なサービスと**実際のバックエンド種別**(`_db.yml` / `_vecdb.yml` などの `type`)を読み、対応する sidecar と `HAI_*` 上書き変数を生成します:
169
+
170
+ | 検出サービス | バックエンド(`type`) | 追加 sidecar | 注入する変数 |
171
+ | ------------ | ---------------------- | ---------------------------------------- | ------------- |
172
+ | `db` | `postgresql` | `postgres:16-alpine` | `HAI_DB` |
173
+ | `db` | `mysql` | `mysql:8.4` | `HAI_DB` |
174
+ | `db` | `sqlite` | なし(`/app/data` ボリュームをマウント) | — |
175
+ | `cache` | `redis` | `redis:7-alpine` | `HAI_CACHE` |
176
+ | `storage` | `s3` | `minio` + バケット初期化 | `HAI_STORAGE` |
177
+ | `vecdb` | `qdrant` | `qdrant/qdrant` | `HAI_VECDB` |
178
+ | `vecdb` | `pgvector` | `pgvector/pgvector` | `HAI_VECDB` |
179
+ | `vecdb` | `chroma` | `chromadb/chroma` | `HAI_VECDB` |
180
+ | `vecdb` | `lancedb` | なし(`/app/data` ボリュームをマウント) | — |
181
+
182
+ - `memory` の `cache` と外部 API の `reach`(メール・SMS)は sidecar を生成しません。
183
+ - 同じサービスにクラウド Provisioner がある場合(Neon の `HAI_DB` など)、クラウドを優先し sidecar を重複作成しません。
184
+ - sidecar のパスワードなどはリモートの `.env.runtime`(`600`)のみに保存し、`compose.yml` には含めません。
185
+
186
+ > セキュリティ:`identityFile` は秘密鍵の**パス**で、内容ではありません。`strictHostKeyChecking: true`(既定)は
187
+ > accept-new を使い、初回は信頼し、鍵変更は拒否します。未知のホストには先に手動で `ssh` 接続できます。
188
+
189
+ ## エラー処理
190
+
191
+ ```typescript
192
+ import { HaiDeployError } from '@h-ai/deploy'
193
+
194
+ const result = await deploy.deployApp('./apps/my-app')
195
+ if (!result.success) {
196
+ switch (result.error.code) {
197
+ case HaiDeployError.AUTH_FAILED.code:
198
+ // Vercel Token 无效
199
+ break
200
+ case HaiDeployError.BUILD_FAILED.code:
201
+ // 构建失败
202
+ break
203
+ }
204
+ }
205
+ ```
206
+
207
+ 主なエラーコード:
208
+
209
+ | エラーコード | code | 説明 |
210
+ | --------------------------------- | ---------------- | -------------------- |
211
+ | `HaiDeployError.DEPLOY_FAILED` | `hai:deploy:001` | デプロイに失敗 |
212
+ | `HaiDeployError.BUILD_FAILED` | `hai:deploy:003` | ビルドに失敗 |
213
+ | `HaiDeployError.AUTH_FAILED` | `hai:deploy:006` | 認証に失敗 |
214
+ | `HaiDeployError.PROVISION_FAILED` | `hai:deploy:007` | リソースの作成に失敗 |
215
+ | `HaiDeployError.NOT_INITIALIZED` | `hai:deploy:010` | 未初期化 |
216
+ | `HaiDeployError.ENV_VAR_FAILED` | `hai:deploy:011` | 環境変数の処理に失敗 |
217
+
218
+ docker-ssh 専用エラーコード:
219
+
220
+ | エラーコード | code | 説明 |
221
+ | -------------------------------------------- | ---------------- | ---------------------------------- |
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
+ ## テスト
230
+
231
+ ```bash
232
+ pnpm --filter @h-ai/deploy test
233
+ ```
234
+
235
+ ## License
236
+
237
+ Apache-2.0
238
+
239
+ クラウド設定の利用:Neon は HAI_DB(PostgreSQL JSON)、Upstash は HAI_CACHE(Redis rediss URL JSON)、R2 は HAI_STORAGE(フラットな S3 JSON)を出力します。メール・SMS は HAI_REACH_PROVIDERS を出力し、deployApp が両チャネルと YAML のメッセージテンプレートを統合して元の providers 配列を置換します。Core はオブジェクト・配列全体の上書きをサポートし、親ノードを末端より優先して Schema 検証を維持します。ビルド子プロセスと対象環境は同じ値を使います。R2 は既存の S3 accessKeyId/secretAccessKey、Resend は検証済みドメインの from、Alibaba Cloud は承認済み signName・テンプレートが必要です。アプリは対応する `_db.yml` / `_cache.yml` / `_storage.yml` / `_reach.yml` を起動時に読み込み、ネットワーククライアントには Node が必要です。
240
+
241
+ 設定の参照:[Upstash TLS](https://upstash.com/docs/redis/features/security)、[Resend SMTP](https://resend.com/docs/send-with-smtp)。決定的な検証では実際のアプリを生成して Core・各モジュールの Schema を確認します。クラウドリソースの作成やメール・SMS 送信は行わず、クラウドの読み書き検証済みとは言えません。
242
+
243
+ デプロイ失敗からの復旧:`ProvisionResult.resourceStatus` は created/reused を示します。`getDeployRecovery(result.error)` で projectName、stage、platformProjectId、リソース一覧を取得し、unknown は結果不明なので先にサービス側の管理画面で確認します。失敗リソースの ID が返った場合は保持します。復旧情報に envVars・元の例外・接続認証情報は含まれず、CLI が一覧と提案を表示します。同名の再試行は既存リソースを再利用し、自動削除しません。新規作成分も未使用を人が確認した後にのみ削除します。
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @h-ai/deploy
2
2
 
3
+ [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
4
+
5
+ [框架首页](../../README.md) · 相关模块:[@h-ai/core](../core/README.md)
6
+
3
7
  自动化部署模块,支持两种部署方式:一键将 SvelteKit 应用部署到 Vercel(并自动开通云基础设施),或将应用容器化后通过 SSH 部署到任意 Linux 主机(docker-ssh)。
4
8
 
5
9
  ## 支持的部署方式
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/deploy",
3
3
  "type": "module",
4
- "version": "0.1.0-alpha.56",
4
+ "version": "0.1.0-alpha.57",
5
5
  "description": "Hai Framework deployment automation module.",
6
6
  "license": "Apache-2.0",
7
7
  "exports": {
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "yaml": "^2.7.0",
27
27
  "zod": "^4.4.3",
28
- "@h-ai/core": "0.1.0-alpha.56"
28
+ "@h-ai/core": "0.1.0-alpha.57"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^25.9.1",