@h-ai/deploy 1.0.0-beta.2 → 1.0.0-beta.20
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 +130 -34
- package/README.ja.md +129 -31
- package/README.md +143 -44
- package/dist/deploy-runtime-env.mjs +230 -0
- package/dist/index.d.ts +347 -102
- package/dist/index.js +9596 -1091
- package/dist/index.js.map +1 -1
- package/package.json +10 -9
package/README.en.md
CHANGED
|
@@ -2,17 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
[简体中文](README.md) | [English](README.en.md) | [日本語](README.ja.md)
|
|
4
4
|
|
|
5
|
-
## Introduction
|
|
6
|
-
|
|
7
5
|
Deploy existing images or Vercel prebuilt output, including complete offline bundles, selected service updates, SSH automation and platform upload scripts. The SDK consumes artifacts; CLI --build explicitly orchestrates build then deployment.
|
|
8
6
|
|
|
9
|
-
##
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
Run in an application created by the CLI with a configured deploy script. Inspect the read-only plan, verify the environment, destination and selected services, then build and deploy:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pnpm run deploy --env prod --plan
|
|
13
|
+
pnpm run deploy --env prod --build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The command returns a deployment URL or an offline delivery directory. On failure, check the safe message and local/remote execution states. Keep production credentials in `.env.prod.local` and prepare data backups and recovery before deployment. The sections below explain build, configuration and delivery boundaries.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
10
19
|
|
|
11
20
|
- Build, package, upload over SSH, start services and check access from one CLI command.
|
|
12
21
|
- Include application and self-hosted middleware images, or update selected services.
|
|
13
22
|
- Deliver offline tar bundles with Windows/Linux/macOS operator scripts, step results and recovery on failure.
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
### Operations and results
|
|
25
|
+
|
|
26
|
+
Use the complete initialization flow in this section first. The host validates and authorizes example business values; check success before reading data from asynchronous domain results. Here void means completion without data, null means absent; synchronous factories/tools return the listed type directly.
|
|
27
|
+
|
|
28
|
+
#### deploy
|
|
29
|
+
|
|
30
|
+
Deployment: scan project/options yields a scan; provisionAll project/services yields provisioned resources; deployApp project/options yields URL/bundle/recovery receipts, checking success first.
|
|
31
|
+
|
|
32
|
+
| Entry | Input parameters | Successful result | Call example |
|
|
33
|
+
| --------------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------ |
|
|
34
|
+
| `deploy.scan` | appDir, options | `ScanResult` | `await deploy.scan('./apps/orders', { environment: 'prod' })` |
|
|
35
|
+
| `deploy.provisionAll` | projectName, services | `ProvisionResult[]` | `await deploy.provisionAll('orders', ['db', 'cache'])` |
|
|
36
|
+
| `deploy.deployApp` | appDir, options | `DeployResult` | `await deploy.deployApp('./apps/orders', { environment: 'prod', bundleOnly: true })` |
|
|
37
|
+
|
|
38
|
+
#### deploy.credentials
|
|
39
|
+
|
|
40
|
+
Local private credentials need no init: getPath returns path, load a HaiResult of loaded variable names; save/saveAll take key/value or mapping and yield void HaiResult without returning secrets for display.
|
|
41
|
+
|
|
42
|
+
| Entry | Input parameters | Successful result | Call example |
|
|
43
|
+
| ---------------------------- | ---------------- | ----------------- | --------------------------------------------------------------------- |
|
|
44
|
+
| `deploy.credentials.getPath` | No arguments | `string` | `deploy.credentials.getPath()` |
|
|
45
|
+
| `deploy.credentials.load` | No arguments | `string[]` | `deploy.credentials.load()` |
|
|
46
|
+
| `deploy.credentials.save` | key, value | `void` | `deploy.credentials.save('HAI_DEPLOY_PROVIDER_TOKEN', providerToken)` |
|
|
47
|
+
| `deploy.credentials.saveAll` | entries | `void` | `deploy.credentials.saveAll(privateCredentialEntries)` |
|
|
16
48
|
|
|
17
49
|
### Prepare build artifacts
|
|
18
50
|
|
|
@@ -22,14 +54,28 @@ Delivery roles are `serv` for a separate API backend, `web` for a static or SSR
|
|
|
22
54
|
|
|
23
55
|
```sh
|
|
24
56
|
pnpm build
|
|
25
|
-
pnpm build --target
|
|
26
|
-
pnpm build --target
|
|
57
|
+
pnpm build --target image
|
|
58
|
+
pnpm build --target image --images web
|
|
27
59
|
pnpm build --target desktop --platform windows --arch x64
|
|
28
60
|
```
|
|
29
61
|
|
|
62
|
+
Automation can select the exact build using `artifactDir` from `hai build --target image --json`. `readDeploymentArtifact` verifies archive paths and SHA-256 checksums, and returns source commit, dirty state and image platforms when present. Older manifests may omit those fields.
|
|
63
|
+
|
|
30
64
|
#### Build options
|
|
31
65
|
|
|
32
|
-
`--target` selects compile (default),
|
|
66
|
+
`--target` selects compile (default), image, app or desktop. `--images serv|web|serv,web` selects images. `--runtime auto|podman|docker` selects the local engine; auto prefers reachable Podman. `--network` overrides build networking, `--no-http-proxy` disables this build proxy (same as --proxy-mode none). SQLite 13 includes native binaries in its npm package and uses the configured npm registry. Native `--platform` and `--arch` require the matching host SDK and Rust toolchain. Builds do not load deployment environments or runtime secrets.
|
|
67
|
+
|
|
68
|
+
#### Download sources and proxies
|
|
69
|
+
|
|
70
|
+
Image builds open an in-memory database to verify that the bundled native binary loads on the target platform.
|
|
71
|
+
|
|
72
|
+
`--image-source official|cn|custom` covers application base images and missing middleware images during packaging. `--npm-source` requires `--build` and controls Corepack/pnpm. The China preset uses 1ms for Docker Hub/GHCR and npmmirror for npm. First interactive choices are saved in `hai.json.build.sources`; flags override one invocation. Set `--proxy-mode inherit|system|custom|none`, `--proxy-url`, and `--proxy-bypass`; `--no-http-proxy` means none. Docker/remote Podman image pulls require engine-side proxy settings; build containers check connectivity separately. See [sources and proxies](../../docs/usage/configuration/delivery.md#下载源和代理) for custom sources and supported platforms.
|
|
73
|
+
|
|
74
|
+
SDK `DeployAppOptions.imageSource` accepts `{ type: 'cn' }` or `{ type: 'custom', registries: { 'docker.io': 'mirror.example.com/docker.io', 'ghcr.io': 'mirror.example.com/ghcr.io' } }`; `proxy` accepts `{ mode: 'inherit' }` or `{ mode: 'custom', url: 'http://127.0.0.1:10808', bypass: 'localhost' }`. Defaults use official sources and inherited process proxies. `resolveImageReference()` / `resolveDownloadProxy()` need no init and do not change engine settings. Middleware archives preserve canonical references for offline server imports.
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
pnpm run deploy --env prod --build --bundle-only --image-source cn --npm-source cn
|
|
78
|
+
```
|
|
33
79
|
|
|
34
80
|
#### Describe packaging in hai.json
|
|
35
81
|
|
|
@@ -67,7 +113,7 @@ pnpm build --target desktop --platform windows --arch x64
|
|
|
67
113
|
|
|
68
114
|
Each image has its own Dockerfile. Web runtime assets live in images/web/. Dockerfiles retain internal build/runtime stages; configuration does not select stages. Omit absent images and add desktop directories only for native projects.
|
|
69
115
|
|
|
70
|
-
Set `transport.maxPlaintextBytes` for both request and response JSON plaintext, measured in UTF-8 bytes: default 1 MiB, integer range 1 KiB–64 MiB. Clients learn the server limit during key exchange. `resolveTransportBodyLimits()` derives encrypted/proxy bytes as twice the plaintext limit plus 32 KiB. Handshake, public-key, header and replay constraints remain independent. Oversized streams are cancelled and readers released: requests return 413; oversized responses return an encrypted 500 capacity error, recognized as `TransportBodyTooLargeError` / `hai:crypto:070`. Full and serv-only incremental deployments derive the proxy limit from resolved `_serv.yml`. Capacity changes recreate the proxy using its installed Web image and restore the prior configuration on health failure. SvelteKit deployments also derive adapter-node `BODY_SIZE_LIMIT` from `_kit.yml`. [Transport capacity
|
|
116
|
+
Set `transport.maxPlaintextBytes` for both request and response JSON plaintext, measured in UTF-8 bytes: default 1 MiB, integer range 1 KiB–64 MiB. Clients learn the server limit during key exchange. `resolveTransportBodyLimits()` derives encrypted/proxy bytes as twice the plaintext limit plus 32 KiB. Handshake, public-key, header and replay constraints remain independent. Oversized streams are cancelled and readers released: requests return 413; oversized responses return an encrypted 500 capacity error, recognized as `TransportBodyTooLargeError` / `hai:crypto:070`. Full and serv-only incremental deployments derive the proxy limit from resolved `_serv.yml`. Capacity changes recreate the proxy using its installed Web image and restore the prior configuration on health failure. SvelteKit deployments also derive adapter-node `BODY_SIZE_LIMIT` from `_kit.yml`. [Transport capacity](../crypto/TRANSPORT-CAPACITY.md).
|
|
71
117
|
|
|
72
118
|
Bodyless authenticated envelopes use X-Hai-Transport. Generated proxies set large_client_header_buffers 4 32k and proxy_buffer_size 32k to admit these headers; custom proxies must preserve and admit them.
|
|
73
119
|
|
|
@@ -85,13 +131,11 @@ The SDK generates matching Nginx paths, runtime configuration URLs, SSR health c
|
|
|
85
131
|
|
|
86
132
|
#### Prepare the environment and destination
|
|
87
133
|
|
|
88
|
-
The default deployment name comes from `package.json.name` at the project root (the nearest `hai.json` or lockfile directory), rejecting missing or invalid names, with an explicit environment appended. A fullstack `hai-delivery` project scanned at `packages/hai-delivery-serv` with `--env test` generates `/opt/hai/apps/hai-delivery-test` and `bundle-hai-delivery-test-<deploymentId>-<version>.tar`. Remote directories, bundles, the Compose project, API/Web/middleware containers, data volumes, server credential state and incremental baselines share this name. Actual project names ending in `-serv` are preserved.
|
|
89
|
-
|
|
90
|
-
Artifact formats 4 and 5 record primaryService (serv/web); hasWeb describes the complete browser topology. Format 5 also records a non-root webBasePath. Only serv + web generates a same-origin API proxy. Rebuild artifacts using formats 1–3. Back up the existing deployment and verify project identity, volumes and managed credentials before establishing a new full deployment baseline. Tools do not migrate data across projects. Full deployments still remove obsolete service containers under the same Compose project; editing deploy-target.json.directory alone does not migrate resources.
|
|
134
|
+
The default deployment name comes from `package.json.name` at the project root (the nearest `hai.json` or lockfile directory), rejecting missing or invalid names, with an explicit environment appended. A fullstack `hai-delivery` project scanned at `packages/hai-delivery-serv` with `--env test` generates `/opt/hai/apps/hai-delivery-test` and `bundle-hai-delivery-test-<deploymentId>-<version>.tar.gz`. Remote directories, bundles, the Compose project, API/Web/middleware containers, data volumes, server credential state and incremental baselines share this name. Actual project names ending in `-serv` are preserved.
|
|
91
135
|
|
|
92
|
-
For
|
|
136
|
+
For a gateway that only exposes `/somepath/`, build with `PUBLIC_BASE_PATH=/somepath` and explicitly place Serv `http.apiPrefix`, health/readiness, docs and storage `publicEndpoint` under that prefix. The SDK generates proxy paths and browser API configuration from those effective settings. Preserve the prefix at the edge; handle internal probes and root ACME challenges separately. [Complete configuration and checks](../../docs/usage/configuration/delivery.md#所有对外业务路径必须带同一目录).
|
|
93
137
|
|
|
94
|
-
|
|
138
|
+
Artifact formats 4 and 5 record primaryService (serv/web); hasWeb describes the complete browser topology. Format 5 also records a non-root webBasePath. Only serv + web generates a same-origin API proxy. Rebuild artifacts using formats 1–3. Back up the existing deployment and verify project identity, volumes and managed credentials before establishing a new full deployment baseline. Tools do not migrate data across projects. Full deployments still remove obsolete service containers under the same Compose project; editing deploy-target.json.directory alone does not migrate resources.
|
|
95
139
|
|
|
96
140
|
Prepare `.env.<environment>` and the project root `hai.json`, with image/native configuration in `build` and application deployment in `deploy`. Fullstack scripts still point to packages/<project>-serv, and API workspaces to apps/<project>-serv, only to scan runtime dependencies and module YAML. Frontend and backend share the project configuration.
|
|
97
141
|
|
|
@@ -99,14 +143,11 @@ Prepare `.env.<environment>` and the project root `hai.json`, with image/native
|
|
|
99
143
|
|
|
100
144
|
The deployment SDK uses these priorities, highest first:
|
|
101
145
|
|
|
102
|
-
|
|
103
|
-
- Other modules: process > `.env.<environment>.local` > legacy `.env.local` > `.env.<environment>` > `.env`, preserving existing private credentials.
|
|
104
|
-
|
|
105
|
-
New connection settings and middleware secrets go to the Git-ignored `.env.<environment>.local`; public backends and addresses stay in `.env.<environment>`. Legacy `.env.local` remains a shared fallback and is never migrated or deleted automatically. Explicit deployment targets for the selected environment take precedence. Only the deployment SDK loads the environment-specific private file; ordinary Core application loading is unchanged. Builds do not load deployment environments or secrets.
|
|
146
|
+
All `HAI_*` settings use process > `.env.<mode>.local` > `.env.local` > `.env.<mode>` > `.env` > YAML. Within one source, fields override base JSON. Replacing a whole node from a higher source clears lower-source fields. Node/Vite and deployment share Core resolution.
|
|
106
147
|
|
|
107
|
-
|
|
148
|
+
Public settings live in `.env` and `.env.<mode>`; SSH settings and credentials go to Git-ignored `.env.<mode>.local`. `.env.local` contains shared machine-private settings. Builds do not read deployment secrets.
|
|
108
149
|
|
|
109
|
-
|
|
150
|
+
All custom HTTP API headers are treated as private values regardless of header names. Saving an existing environment also moves indented, `export` and multiline quoted entries out of the same-mode public file, so their previous values are not left behind.
|
|
110
151
|
|
|
111
152
|
For direct deployment, the wizard asks for missing server, SSH user, authentication and port settings using readable labels. Complete valid settings are reused, including with `--yes`. SSH accepts `auth: key` (private key/agent) or `auth: password`. Without `auth`, only a nonempty `password` selects password authentication; otherwise key/agent remains in use. Explicit `key` ignores a leftover password. Password input is hidden and preserves surrounding spaces and leading zeros. Effective passwords must not contain CR/LF/NUL and must fit within 1023 UTF-8 bytes. Private keys are referenced by path; their contents are never read or copied.
|
|
112
153
|
|
|
@@ -114,7 +155,11 @@ SSH settings are saved in `.env.<environment>.local`. `--bundle-only` offers to
|
|
|
114
155
|
|
|
115
156
|
#### Configure only the middleware the application needs
|
|
116
157
|
|
|
117
|
-
Runtime lockfile dependencies and configuration determine middleware. Choose defaults, custom connections or keep settings. With complete target-environment settings, `--yes` preserves values without asking again or provisioning cloud resources again; interactive mode still lets you select the scope. --skip-middleware skips configuration/provisioning. SQLite, memory cache and local storage need no external images. Complete bundles automatically include self-hosted middleware images. External services still require reachable destinations; cloud provisioning is not an offline operation.
|
|
158
|
+
Runtime lockfile dependencies of the target application and configuration determine middleware; commented configuration does not enable modules. LDAP is included only when effective `iam.login.ldap=true`, so disabled LDAP produces no prompt. Choose defaults, custom connections or keep settings. With complete target-environment settings, `--yes` preserves values without asking again or provisioning cloud resources again; interactive mode still lets you select the scope. --skip-middleware skips configuration/provisioning. SQLite, memory cache and local storage need no external images. Complete bundles automatically include self-hosted middleware images. External services still require reachable destinations; cloud provisioning is not an offline operation.
|
|
159
|
+
|
|
160
|
+
Default and custom modes preserve effective settings for the same backend, including pool, operation log, public storage URLs/prefixes, Redis retry and vector search options absent from the form. Managed services replace connection selectors and credentials; old URLs, TLS/cluster modes and credentials cannot override the new service. SMTP senders and LDAP attribute mappings remain. Switching backends clears incompatible fields. Missing fields already saved in parent JSON need recovery from the original configuration or backup: restore `publicEndpoint` in the highest-priority `HAI_STORAGE`, then rebuild and deploy the bundle. Editing YAML or leaf variables hidden by that parent JSON cannot repair an old bundle. Generators prefer field variables and retain JSON arrays. Handwritten JSON remains a base and appears before its module fields; fields in the same source win. Dynamic maps, JSON text and explicit empty objects preserve their meaning. Expanding a whole-object replacement retains its highest `{}` reset marker so old YAML fields cannot reappear. Container paths stay in delivery output without changing source settings.
|
|
161
|
+
|
|
162
|
+
In `hai deploy`, choose a URL or individual fields for custom PostgreSQL, MySQL, Redis and pgvector connections. For external S3, enter the server API address in `endpoint` and the bucket name in `bucket`. See [connecting existing middleware](../../docs/usage/configuration/delivery.md#连接已有数据库缓存和对象存储) for examples. An empty production Reach list requires a complete provider list, and the wizard configures existing provider indices.
|
|
118
163
|
|
|
119
164
|
#### Direct private object storage access
|
|
120
165
|
|
|
@@ -148,17 +193,19 @@ S3 `createBucket` defaults to `false`. Self-hosted S3 deployments set `HAI_STORA
|
|
|
148
193
|
pnpm run deploy --env prod --build --bundle-only
|
|
149
194
|
```
|
|
150
195
|
|
|
151
|
-
Each delivery creates one `.hai/deploy/<environment>/bundle-<project>-<deploymentId>-<version>/` directory containing only the tar, deploy.sh, deploy.ps1, deploy-target.json, read-target.awk, deploy-local.sh and README.txt. Compose, runtime environments, web.conf and manifest.json remain inside the tar; the external README also records the deployment ID. Copy that directory as a unit. Explicit `--output release-prod.tar` produces `release-prod-<version>/release-prod-<version>.tar` relative to the command directory, with all companion files alongside it. The tar includes selected application/middleware images, configurations, private environment files, checksums,
|
|
196
|
+
Each delivery creates one `.hai/deploy/<environment>/bundle-<project>-<deploymentId>-<version>/` directory containing only the tar, deploy.sh, deploy.ps1, deploy-target.json, read-target.awk, deploy-local.sh and README.txt. Compose, runtime environments, web.conf and manifest.json remain inside the tar; the external README also records the deployment ID. Copy that directory as a unit. Explicit `--output release-prod.tar` produces `release-prod-<version>/release-prod-<version>.tar` relative to the command directory, with all companion files alongside it. The tar includes selected application/middleware images, configurations, private environment files, checksums, `APPLY.txt`, and `apply.sh`. Before running either upload script, open `deploy-target.json` in the operation directory and use its per-field descriptions to edit and check the server, SSH user and port, private key and known-hosts files, remote directory and other settings. Run deploy.ps1 on Windows or deploy.sh on Linux/macOS; both scripts read this JSON to upload over SSH and execute the same server workflow. Running deploy.sh locally requires sh, awk, ssh and scp. Use `sh deploy.sh HOST [PORT] [USER]` to override the connection address, or pass `-IdentityFile` to deploy.ps1 to override its private key. Both scripts support HAI_DEPLOY_IDENTITY_FILE and HAI_DEPLOY_KNOWN_HOSTS_FILE to override key and known-hosts paths. After moving to another computer or operating system, update these paths to files on that computer.
|
|
152
197
|
|
|
153
198
|
Offline upload supports key and password authentication. `deploy-target.json` stores only the authentication choice and `passwordEnv` name (default `HAI_DEPLOY_PROVIDER_SSH_PASSWORD`), never the password value. Supply the password in the operator machine environment; it reaches only the current SSH/SCP child processes, not application environments, the tar or manifest. Windows can also read the persisted user environment. Windows needs PowerShell 5+ and OpenSSH; Linux/macOS uses sh, awk, ssh and scp. Neither uploader needs Node/pnpm. Target edits apply only to that delivery directory and never write back to the project; new deliveries use the saved project environment.
|
|
154
199
|
|
|
155
200
|
Uploaders reuse the operator environment password first. If unset or empty, `deploy.sh` / `deploy.ps1` immediately request hidden input and continue the current deployment. Input is never saved to files; noninteractive calls fail clearly without waiting. POSIX prompting requires a terminal and `stty`. Invalid input and cancellation are reported clearly. Progress shows received/total bytes and percentage, reaching 100% only after success; PowerShell forwards redacted SSH output continuously. Incremental deployment restores stopped or Compose-down services from the installed baseline and local images before checking dependencies and updating selected services; failed recovery does not advance current.
|
|
156
201
|
|
|
157
|
-
|
|
202
|
+
Set per-container hostname-to-IP mappings in `hai.json` under `deploy.container.compose.services.serv.extra_hosts` or `web.extra_hosts`. The archive carries the mappings. A partial deployment updates the selected services, and recovery restores their last successful mappings. [Configuration example](../../docs/usage/configuration/delivery.md#为容器设置主机名映射)
|
|
203
|
+
|
|
204
|
+
On isolated Linux servers, copy the delivery directory and run `sh deploy-local.sh`, optionally passing the deployment root. The script verifies and extracts the adjacent tar and invokes the bundled apply.sh automatically. If you copy only the archive, extract it, read `APPLY.txt`, and run `sh ./apply.sh` from that directory. Every failed step exits nonzero. Image loading, service startup and HTTP checks are distinct steps. result-<deploymentId>.json records the result; current changes only after successful checks. Reapplying the same deployment ID stops clearly; a newly generated bundle for the same application version is allowed. Failed updates attempt to restore selected containers and configuration while preserving data volumes and diagnostics. Data already written by the application is not rolled back.
|
|
158
205
|
|
|
159
206
|
The bundle `manifest.json` records `partial` and `selectedServices`, and the apply script embeds the same choice. A complete build without `--services` is a full deployment; explicit service selection or a partial build is incremental. Incremental packages require a matching successful `current` baseline and cannot perform a first installation.
|
|
160
207
|
|
|
161
|
-
The server holds a nonblocking kernel lock with util-linux `flock` on `.deploy.lock` in the deployment root, throughout deployment and recovery. Normal foreground deployment and synchronous failure recovery explicitly unlock after finalization and terminal-result publication, so background services do not block later deployments. Keep this file permanently: never delete, replace or steal it based on elapsed time, and use a filesystem that supports `flock`. On HUP/INT/TERM or a killed parent shell, active child commands retain the inherited lock until every holder exits or the server restarts.
|
|
208
|
+
The server holds a nonblocking kernel lock with util-linux `flock` on `.deploy.lock` in the deployment root, throughout deployment and recovery. Normal foreground deployment and synchronous failure recovery explicitly unlock after finalization and terminal-result publication, so background services do not block later deployments. Keep this file permanently: never delete, replace or steal it based on elapsed time, and use a filesystem that supports `flock`. On HUP/INT/TERM or a killed parent shell, active child commands retain the inherited lock until every holder exits or the server restarts. Forced termination or power loss skips recovery traps. Without a result file, execution is unknown: inspect containers, images and the successful `current` baseline before recovering with a new bundle. An unlocked file does not prove success or rolled-back effects.
|
|
162
209
|
|
|
163
210
|
#### Failure recovery and reverting a successful release
|
|
164
211
|
|
|
@@ -188,12 +235,29 @@ After the server passes local health checks and commits `current`, the SDK separ
|
|
|
188
235
|
|
|
189
236
|
Complete bundles include self-hosted middleware archives and matching architecture; server startup never pulls images. Linux needs Docker/Podman, Docker Compose v2 or podman-compose 1.6.0+ (supports --pull never), sh, tar, sha256sum, awk, curl, util-linux flock and filesystem/container permissions. Protect private bundle contents. Keep volume identities stable across versions. Verify actual offline startup, login, refresh, restart and persistence. HTTPS, certificates, DNS and external services need separate preparation.
|
|
190
237
|
|
|
238
|
+
### Build and packaging improvements
|
|
239
|
+
|
|
240
|
+
Image builds run at most two images concurrently by default; use `--concurrency 1` to reduce resource use. Dependency installation precedes source copies, and each side copies only its required source. Runtime images omit application declaration files, source maps and README files. Packaging validates and reuses middleware archives by image content ID and hashes application archives while copying. Delivery defaults to `.tar.gz`; explicit `--output release.tar` keeps an uncompressed archive. The delivery directory contains `README.txt`, and the archive contains the manual deployment guide `APPLY.txt`. Successful deployment removes its incoming upload/extraction, retains recovery configuration in releases, and keeps images in the container engine.
|
|
241
|
+
|
|
242
|
+
### Optional HTTPS certificates
|
|
243
|
+
|
|
244
|
+
`pnpm run deploy` offers no HTTPS, existing PEM certificate/key paths, or Let’s Encrypt for every container template. Relative paths resolve from the project root. Certificates are checked for domain, validity and key matching, then copied into private releases. A pinned official Certbot image handles issuance and renewal checks every 12 hours, with automatic Nginx reload. It requires terms acceptance, a real email, public DNS, port 80 and CA connectivity. Isolated servers use existing certificates. Certificate state stays on the server; keys stay out of application images. `--yes` reuses saved settings.
|
|
245
|
+
|
|
246
|
+
Supply regular PEM files of at most 1 MiB each; final-component symbolic links and hard links are rejected, and parent directories must remain trusted. Securely copy Certbot `live/` symlink targets to regular files in a controlled directory, or use the framework `letsencrypt` mode.
|
|
247
|
+
|
|
248
|
+
Configure `hai.json.deploy.provider.expose.https` or private environment overrides. Defaults are HTTPS 443 and HTTP redirection; omission retains HTTP. Enabling/disabling HTTPS or changing mode, domain, ports or supplied certificates requires a full deployment. See the [HTTPS guide](../../docs/usage/configuration/delivery.md#可选https证书). Plans use `root` for the project and `serviceDir` for the service source/configuration directory, exposing only public certificate metadata.
|
|
249
|
+
|
|
191
250
|
### SDK
|
|
192
251
|
|
|
193
252
|
```ts
|
|
194
253
|
import { deploy } from '@h-ai/deploy'
|
|
195
254
|
|
|
196
|
-
const initialized = await deploy.init({
|
|
255
|
+
const initialized = await deploy.init({
|
|
256
|
+
provider: {
|
|
257
|
+
type: 'docker-ssh',
|
|
258
|
+
expose: { hostPort: 18080 }
|
|
259
|
+
}
|
|
260
|
+
})
|
|
197
261
|
if (!initialized.success)
|
|
198
262
|
throw new Error(initialized.error.message)
|
|
199
263
|
try {
|
|
@@ -215,6 +279,8 @@ finally {
|
|
|
215
279
|
|
|
216
280
|
`selectedServices: ['web']` selects a partial update. `onProgress` receives actual packaging/server stages. `deploy.scan` and `deploy.credentials.*` are available before init. Check HaiResult.success before using data. Vercel uploads existing .vercel/output through the prebuilt API and requires internet; it does not provide offline or Compose partial deployment.
|
|
217
281
|
|
|
282
|
+
Vercel API requests and file uploads use the official endpoint, reject redirects and share a 30-second deadline per request, including complete JSON response reads. There is no new configuration option. A timeout does not prove that the platform rejected a deployment; check its actual status before deciding whether to publish again.
|
|
283
|
+
|
|
218
284
|
Command execution redacts correctly decoded UTF-8 logical streams, including known secrets split across stdout/stderr chunks. Successful captures, errors and output callbacks use the same boundary. Internal command callers must enumerate sensitive literals in `secrets`, including separately encoded or transformed forms. Each stream captures only its last 1 Mi characters by default; `maxCaptureChars` accepts 1 through 16 Mi characters. Check `stdoutTruncated` / `stderrTruncated` before parsing structured output. Async `onOutput` callbacks receive all safe stdout in order with pipe backpressure; deployment progress parses only the first 512 characters of each line. Total secret length is limited to 1 Mi UTF-16 units; invalid redaction fails closed. A timeout reports failure; remote process termination still requires confirmation.
|
|
219
285
|
|
|
220
286
|
Command deadlines include helper startup and output handling. Timeouts, input/output errors and callback failures terminate managed processes. POSIX uses a separate process group. Windows uses an embedded PowerShell/.NET Job Object: create suspended, assign successfully, then resume, with no breakaway. Helper, compilation or assignment failure never falls back to an unmanaged process. System PowerShell and Add-Type are required on Windows; execution is hidden without user profiles, preserving arguments, environment and UTF-8 pipes. POSIX commands must keep descendants in the inherited group; detached system daemons and remote services are outside local termination confirmation.
|
|
@@ -225,7 +291,25 @@ SSH interruptions initially report `remoteExecution: 'unknown'`. The docker-ssh
|
|
|
225
291
|
|
|
226
292
|
### Runtime environment files and repeated deployments
|
|
227
293
|
|
|
228
|
-
|
|
294
|
+
SvelteKit SSR uses a separate `gateway` for HTTP and HTTPS, without publishing the backend port. The gateway overwrites standard forwarding headers, and Compose fixes the adapter's protocol, Host and client address trust settings; the application runtime file cannot override them. The adapter does not read runtime `ORIGIN`; applications leave build-time `paths.origin` unset by default. Changes to the SSR ingress topology require a full bundle.
|
|
295
|
+
|
|
296
|
+
For upstream TLS termination, list the load balancer's actual IPs/CIDRs in `trustedEdgeProxies`. The separate gateway accepts a single `http` or `https` protocol only from those actual peers; other sources and combined values use its own connection scheme. External `Forwarded` and forwarded host/port values are overwritten.
|
|
297
|
+
|
|
298
|
+
Environment flags, initial account passwords and the transport key ring are also read directly by startup code. They remain available even when a similarly named configuration parent exists.
|
|
299
|
+
|
|
300
|
+
Generators prefer field variables and retain JSON arrays. Handwritten JSON remains a base and appears before its module fields; fields in the same source win. Dynamic maps, JSON text and explicit empty objects preserve their meaning. Expanding a whole-object replacement retains its highest `{}` reset marker so old YAML fields cannot reappear. Container paths stay in delivery output without changing source settings.
|
|
301
|
+
|
|
302
|
+
The deployment archive contains `apply.sh`, `APPLY.txt`, `manifest.json`, `config/`, `images/`, and `.hai/` at the top level. `config/.env.runtime` is the single application environment file. `manifest.json.metadata` holds nonsecret layout, dependencies, health paths, image lists and managed bindings. `.hai/compose.json` is a complete snapshot; partial updates replace selected service definitions and retain other services without historical Compose chains. `.hai/` also contains native environment, the loader, Nginx/TLS, policy and checksums. Secrets stay out of the manifest; helper scripts are embedded in `apply.sh`. Failure recovery restores application configuration before services while protecting credentials, backend ledgers and volumes. Bundle format 2 has no old-layout compatibility or migration. Runtime preparation reuses the already imported Node application image in a temporary container with networking disabled. It downloads no extra image and requires no host Node or jq.
|
|
303
|
+
|
|
304
|
+
Node backends (Serv / SvelteKit SSR) read `<deployment-root>/config/.env.runtime` on every start. This single application file includes managed connections. Edit a field such as `HAI_STORAGE_PUBLICENDPOINT`, then restart the backend; fields override parent JSON within the same source. The configuration directory is mounted read-only at `/run/hai/config`, so atomic file replacement is visible on restart. Private proxy identity and Node startup options remain deployment settings. Static Web, native middleware environment, ports/mounts, and Nginx routes or limits require deployment. Web/middleware-only updates retain the file; partial backend updates preserve managed connections, while full updates use the new package with existing managed credentials. Back up edits and copy permanent settings into the source environment.
|
|
305
|
+
|
|
306
|
+
The outer `README.txt` and the archive’s `APPLY.txt` include the file index, environment precedence, names of variables in this bundle, and troubleshooting steps. The unpacked `config/.env.runtime` is release input, the deployment root holds the active file, and `releases/<ID>/` holds the release record. After rotating an external PostgreSQL password, update the project environment and deploy the backend. Packaging rejects conflicting URL and separate passwords. Use a full deployment to switch between external and bundled middleware.
|
|
307
|
+
|
|
308
|
+
Container packaging sets the listener to `0.0.0.0` and the port declared by the artifact, falling back to deployment settings when absent. It generates `HOST`, `PORT`, and the matching Serv fields. Loopback addresses and development ports in local `.env` files remain local settings. Update the artifact and deployment layout together when changing container ports.
|
|
309
|
+
|
|
310
|
+
Nginx dynamically tracks DNS changes for application and storage containers. The shared `.hai/proxy-start.sh` runs as an image entrypoint hook, preserves the image startup command, and reads resolvers from the container's `/etc/resolv.conf` and also watches certificate changes for HTTPS. Docker and Podman need no fixed DNS address. After editing runtime configuration and restarting the backend, the proxy reconnects automatically even if its IP changes.
|
|
311
|
+
|
|
312
|
+
Image-native `POSTGRES_*`, `MYSQL_*`, `RUSTFS_*`, `MINIO_*`, and `LDAP_*` keep the names required by their images, only in private `.hai/middleware-runtime.env` loaded by middleware. All application connections are merged into `config/.env.runtime`.
|
|
229
313
|
|
|
230
314
|
Whole `HAI_*` configuration supplied by sidecars or provisioners clears superseded leaf variables: Redis overrides no longer leave `HAI_CACHE_TYPE=memory`. Global `~/.hai/credentials.yml` fills missing settings only, respecting existing environment/process keys and parent objects. Deployment starts selected middleware and waits for PostgreSQL/MySQL/Redis/S3 health before serv/Web; incremental deployment and recovery use the same order and preserve unselected containers.
|
|
231
315
|
|
|
@@ -233,39 +317,51 @@ On Podman, deployment actively runs each configured container healthcheck and re
|
|
|
233
317
|
|
|
234
318
|
Only the first startup batch removes orphan containers; later serv/Web startup preserves the middleware that is already ready.
|
|
235
319
|
|
|
236
|
-
|
|
320
|
+
Project creation generates independent initial passwords and transport key rings in `.env.dev.local`, `.env.test.local`, and `.env.prod.local`. These files are Git-ignored. Distribute environment secrets through protected files or a Secret Manager after cloning. Nodes in one environment share a valid ring and registry; never generate a ring at startup. Missing or invalid `HAI_CRYPTO_TRANSPORT_SERVERKEYRING` fails before upload. CLI and offline instructions identify password variables and sources without showing values. Initial passwords create missing accounts and do not reset existing accounts.
|
|
237
321
|
|
|
238
|
-
Each delivery still generates
|
|
322
|
+
Each delivery still generates `config/.env.runtime` inside the archive for Compose. This is generated output, not the saved configuration source. The default `NODE_ENV` follows the target: `test` → `test`, `dev/development` → `development`, and `prod/production` or other modes → `production`. Explicit `NODE_ENV` values in environment configuration override this default; build optimization does not select the runtime environment. Rebuild the bundle to update old deliveries.
|
|
239
323
|
|
|
240
324
|
Project-root `hai.json.deploy` stores deployment structure, `.env.<environment>` stores public settings, and `.env.<environment>.local` stores SSH settings and middleware secrets. Environment files default to the project/workspace root; override with `--env-dir`. After configuration, `pnpm run deploy --env test --build --bundle-only --yes` reuses complete settings without prompts; add `--skip-middleware` to retain middleware configuration. Interactive bundle-only mode offers to save or update SSH settings at the final configuration step; editing a delivery's `deploy-target.json` does not update the project.
|
|
241
325
|
|
|
242
326
|
The server persists managed middleware passwords in `<remoteDir>/managed-secrets.env` (mode 0600); back it up with data volumes. Each package supplies random first-use candidates without a build-machine cache. The online SDK, deploy.sh, deploy.ps1 and deploy-local.sh resolve server values under the deployment lock and update both application connections and native middleware variables. The delivery tar stays immutable; only private server runtime files receive resolved values. Missing state with an existing corresponding volume stops deployment before services change: restore the server credential backup. Deployment never silently rotates passwords or deletes data. Legacy credentials can be explicitly verified and imported using the procedure below.
|
|
243
327
|
|
|
244
|
-
|
|
328
|
+
### Read-only deployment plan
|
|
245
329
|
|
|
246
|
-
`createDeploymentPlan(appDir, config, options)` initializes no provider, generates no credentials/output and connects to no target. It shares real scanning, environment resolution, resource naming and artifact checksums, reporting versions, build ID, selected/retained services, source files/key names, baseline requirements and recovery paths without values or SSH credentials. Unread remote current is not-inspected; execution still strictly requires a successful baseline for partial updates. Compose recovery does not undo database changes/migrations. CLI: `hai deploy --env prod --plan`.
|
|
330
|
+
`createDeploymentPlan(appDir, config, options)` initializes no provider, generates no credentials/output and connects to no target. It shares real scanning, environment resolution, resource naming and artifact checksums, reporting project `root`, service source/configuration `serviceDir`, versions, build ID, selected/retained services, source files/key names, baseline requirements and recovery paths without values or SSH credentials. Unread remote current is not-inspected; execution still strictly requires a successful baseline for partial updates. Compose recovery does not undo database changes/migrations. CLI: `hai deploy --env prod --plan`.
|
|
247
331
|
|
|
248
332
|
Use `--plan --inspect-remote` (SDK inspectRemote:true) to read current and the successful release directory over SSH. It reports verified/missing/unavailable and the actual recovery release ID without target writes.
|
|
249
333
|
|
|
250
334
|
Resources use the complete execution topology. `containers` lists selected explicit container names; Compose-named LDAP/SMTP services appear in `composeManagedServices`. The SSR/API storage gateway appears in the actual selected or retained scope. `logicalVolumes` declares the complete Compose topology, including retained services and data volumes still mounted by the app; it does not mean those volumes will be created or replaced. Engine names are scoped by the Compose project. Unselected middleware has action keep, and cloud provisioning follows the actual selection without exposing credentials.
|
|
251
335
|
|
|
252
|
-
|
|
336
|
+
### Capacity and credential import
|
|
253
337
|
|
|
254
338
|
Explicit plaintext limits are preserved. Packaging rejects feedback requirements above an explicit limit with a configuration conflict. Omitted/auto values derive capacity; the Web proxy and Kit BODY_SIZE_LIMIT use the same encrypted budget. Plan target.runtime reports remote provider.remote.runtime separately from local packaging options.runtime; auto is not a detected runtime.
|
|
255
339
|
|
|
256
340
|
Use `importDeploymentSecrets({ directory, inputFile, runtime })` or run `hai deploy-secrets <directory> --import <private.json>` on the server for read-only verification. Only explicit `--apply` / dryRun:false imports state. The tool verifies projects, containers, volumes and live credentials; it never infers passwords from old bundles, rotates credentials or rebuilds services. V2 state supports special characters and is atomically written with mode 0600 under the deployment flock. Ordinary offline deployment still requires no server Node; this one-time import tool needs supported Node and installed CLI/deploy. See the [import and recovery procedure](docs/credential-import.en.md).
|
|
257
341
|
|
|
258
|
-
|
|
342
|
+
### Request policy files and trusted proxies
|
|
259
343
|
|
|
260
|
-
Serv `http.access` and SvelteKit `access` can reference separate yml/yaml files. Deployment reads effective application configuration, including environment overrides such as `HAI_SERV`, `HAI_SERV_HTTP_ACCESS` and `HAI_KIT_ACCESS`, validates the file and includes a normalized snapshot in the bundle. Runtime configuration points to `/run/hai/request-access.yml` with a read-only Compose mount. The project retains its original file reference. The snapshot participates in SHA-256 verification; missing or invalid files fail before upload.
|
|
344
|
+
Serv `http.access` and SvelteKit `access` can reference separate yml/yaml files. Deployment reads effective application configuration, including environment overrides such as `HAI_SERV`, `HAI_SERV_HTTP_ACCESS` and `HAI_KIT_ACCESS`, validates the file and includes a normalized snapshot in the bundle. Runtime configuration points to `/run/hai/request-access.yml` with a read-only Compose mount. The project retains its original file reference. The snapshot participates in SHA-256 verification; missing or invalid files fail before upload. The upload archive and its policy snapshot are integrity-checked inputs; replacing the SDK-managed snapshot requires a new bundle and deployment. The deployed Node backend reads its mounted `.env.runtime` on restart as described above. Inline rule changes do not rewrite the policy snapshot or Nginx configuration.
|
|
261
345
|
|
|
262
346
|
Full deployments and backend increments carry their own snapshot; frontend-only increments retain the backend mount. Failed deployment recovery uses the previous successful release's Compose and policy file. Non-root containers can read the policy inside a private release directory. Image and policy rollback does not undo database migrations or completed business effects.
|
|
263
347
|
|
|
264
|
-
For operator-managed rules that reload on restart, manage a read-only file outside the bundle and use a Compose override to replace the same `/run/hai/request-access.yml` mount. SDK rollback does not restore this external file. Recreate the container once to apply the mount; later file changes require a restart.
|
|
348
|
+
For operator-managed rules that reload on restart, manage a read-only file outside the bundle and use a Compose override to replace the same `/run/hai/request-access.yml` mount. SDK rollback does not restore this external file. Recreate the container once to apply the mount; later file changes require a restart. A custom container that only injects variables through Compose `env_file` still needs recreation after file changes, usually without rebuilding the image. SDK Node backends instead read the mounted `.env.runtime` on restart. See [mounted policy setup and verification](../../docs/usage/configuration/request-access.md#44-运维独立管理文件修改后重启生效).
|
|
265
349
|
|
|
266
350
|
Managed Compose sets `HAI_DEPLOY_PRIVATE_PROXY=1` only when a Web/gateway proxy fronts a backend without public ports. Serv/Kit default `trustedProxies: auto` uses container networks there and ignores forwarded headers on other hosts. Generated Nginx overwrites client-supplied forwarding headers with the actual peer. For an upstream load balancer, explicitly set Docker SSH Provider `trustedEdgeProxies` to its IPs/CIDRs; omitting it trusts no upstream, and `[]` explicitly selects the same behavior. Source addresses lost before Nginx cannot be reconstructed, including some rootless forwarding environments. See the [request access handbook](../../docs/usage/configuration/request-access.md) for examples and verification.
|
|
267
351
|
|
|
268
|
-
##
|
|
352
|
+
## Configuration
|
|
353
|
+
|
|
354
|
+
Lifecycle: init takes backend/business configuration; use the module only after success. Await close before releasing borrowed dependencies. Follow the quick-start example and public signatures for exact return values.
|
|
355
|
+
|
|
356
|
+
The host loads and validates configuration before passing it to this module. Keep secrets in private server environment files. Select the backend, capacity, deadlines and logging for the actual use case; reinitialize and check the result after changes.
|
|
357
|
+
|
|
358
|
+
[Per-option purpose, use cases and examples](../../docs/usage/configuration/delivery.md).
|
|
359
|
+
|
|
360
|
+
## Error Handling
|
|
361
|
+
|
|
362
|
+
Check result.success for domain operations. Handle failures with the module error definitions and safe messages; retain codes, correlation IDs and sanitized causes in server logs. Synchronous tools, factories, stream iteration and lifecycle calls follow their own signatures. A completed Promise alone is not business success. See each feature for recovery limits.
|
|
363
|
+
|
|
364
|
+
## Development
|
|
269
365
|
|
|
270
366
|
```sh
|
|
271
367
|
pnpm --filter @h-ai/deploy typecheck
|