@h-ai/deploy 1.0.0-beta.16 → 1.0.0-beta.18
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 +4 -0
- package/README.ja.md +4 -0
- package/README.md +4 -0
- package/dist/deploy-runtime-env.mjs +13 -2
- package/dist/index.d.ts +6 -1
- package/dist/index.js +85 -14
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.en.md
CHANGED
|
@@ -27,6 +27,8 @@ pnpm build --target image --images web
|
|
|
27
27
|
pnpm build --target desktop --platform windows --arch x64
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
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.
|
|
31
|
+
|
|
30
32
|
#### Build options
|
|
31
33
|
|
|
32
34
|
`--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), and `--sqlite-prebuild-mirror` selects a trusted HTTP(S) binary mirror. Native `--platform` and `--arch` require the matching host SDK and Rust toolchain. Builds do not load deployment environments or runtime secrets.
|
|
@@ -260,6 +262,8 @@ The deployment archive contains `apply.sh`, `APPLY.txt`, `manifest.json`, `confi
|
|
|
260
262
|
|
|
261
263
|
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.
|
|
262
264
|
|
|
265
|
+
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.
|
|
266
|
+
|
|
263
267
|
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.
|
|
264
268
|
|
|
265
269
|
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.
|
package/README.ja.md
CHANGED
|
@@ -27,6 +27,8 @@ pnpm build --target image --images web
|
|
|
27
27
|
pnpm build --target desktop --platform windows --arch x64
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
自動化では `hai build --target image --json` の `artifactDir` で今回の成果物を指定できます。`readDeploymentArtifact` はアーカイブのパスと SHA-256 を検証し、マニフェストに含まれるソースコミット、変更状態、イメージのプラットフォームを返します。過去のマニフェストではこれらの項目を省略できます。
|
|
31
|
+
|
|
30
32
|
#### build のオプション
|
|
31
33
|
|
|
32
34
|
`--target` は compile(既定)、image、app、desktop を選択します。`--images serv|web|serv,web` は対象イメージを、`--runtime auto|podman|docker` はローカルエンジンを選択します。auto は接続可能な Podman を優先します。`--network` は構築ネットワーク、`--no-http-proxy` は 今回のビルドのプロキシ無効(none と同じ)、`--sqlite-prebuild-mirror` は信頼できる HTTP(S) バイナリ配布元です。ネイティブ配布物には対象 OS の SDK と Rust ツールチェーンが必要です。構築時にデプロイ環境や秘密情報を読み込みません。
|
|
@@ -258,6 +260,8 @@ SSH 中断は最初に `remoteExecution: 'unknown'` とし、docker-ssh SDK は
|
|
|
258
260
|
|
|
259
261
|
Node バックエンド(Serv / SvelteKit SSR)は起動ごとに `<配備ディレクトリー>/config/.env.runtime` を読みます。管理接続も同じアプリ設定に統合します。`HAI_STORAGE_PUBLICENDPOINT` などを編集して再起動すると反映され、同じソースでは個別フィールドが親 JSON を上書きします。設定ディレクトリーを `/run/hai/config` に読み取り専用でマウントするため、ファイルのアトミック置換も次の起動で反映されます。非公開プロキシ識別と Node 起動引数は配備設定です。静的 Web、ネイティブ環境、ポート、マウント、Nginx の変更は再配備します。Web/ミドルウェアのみの更新は設定を維持し、バックエンドの部分更新は管理接続を維持、全量更新は新しい設定と既存の管理資格情報を使います。編集前にバックアップし、恒久的な値は元の環境にも反映してください。
|
|
260
262
|
|
|
263
|
+
外側の `README.txt` とアーカイブ内の `APPLY.txt` には、ファイル索引、環境設定の優先順位、今回の変数名、調査手順が含まれます。展開した `config/.env.runtime` は配備入力、配備ルートの同名ファイルは現在の実行設定、`releases/<ID>/` 内は配備記録です。外部 PostgreSQL のパスワード変更後はプロジェクトの環境設定を更新し、バックエンドを配備します。URL と個別項目のパスワードが競合する場合はパッケージ作成時に失敗します。外部と同梱の切り替えには全量配備が必要です。
|
|
264
|
+
|
|
261
265
|
コンテナーのパッケージ化では、待受アドレスを `0.0.0.0`、ポートを成果物の宣言値(未指定なら配置設定)として、`HOST`、`PORT` と Serv の対応フィールドを生成します。ローカル `.env` のループバックアドレスと開発ポートはローカル実行に使います。コンテナーポートの変更時は成果物と配置構成を更新して再配備してください。
|
|
262
266
|
|
|
263
267
|
Nginx はアプリとストレージのコンテナーの DNS 変更に動的に追従します。共通の `.hai/proxy-start.sh` はイメージの元の起動コマンドを維持する入口フックとして動作し、コンテナー内の `/etc/resolv.conf` からリゾルバーを読み、HTTPS では証明書更新も監視します。Docker と Podman の DNS アドレスを固定する必要はありません。実行時設定を編集してバックエンドを再起動した後、IP が変わってもプロキシは自動的に再接続します。
|
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ pnpm build --target image --images web
|
|
|
27
27
|
pnpm build --target desktop --platform windows --arch x64
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
自动化可使用 `hai build --target image --json` 的 `artifactDir` 指定本次构建。`readDeploymentArtifact` 校验归档路径及 SHA-256,并返回清单中的来源提交、工作区状态和镜像平台;历史清单可以省略这些字段。
|
|
31
|
+
|
|
30
32
|
源码编译、镜像构建、桌面打包分别对应 compile/image/desktop。构建不选择部署环境、不注入运行期密钥。原生安装包在对应操作系统准备 SDK 与 Rust 工具链后构建。
|
|
31
33
|
|
|
32
34
|
#### build 的可选参数
|
|
@@ -278,6 +280,8 @@ SSH 中断始终先记 `remoteExecution: 'unknown'`。docker-ssh SDK 用新连
|
|
|
278
280
|
|
|
279
281
|
Node 后端(Serv / SvelteKit SSR)每次启动读取服务器 `<部署目录>/config/.env.runtime`。应用配置与托管连接在此合并,修改 `HAI_STORAGE_PUBLICENDPOINT` 等细项后重启对应后端即可;同一来源的细项覆盖父 JSON。配置目录只读挂载到 `/run/hai/config`,编辑器原子替换文件也会被下一次启动读取。私有代理标记和 Node 启动参数由部署装配管理;静态 Web、中间件原生环境、端口/挂载、Nginx 路由与限额变更仍需部署。仅更新 Web/中间件保留当前应用配置;后端局部更新保留服务器托管连接,其余值来自新包,全量更新采用新包并按已有凭据状态定稿。手工修改先备份,长期配置同步回源环境。
|
|
280
282
|
|
|
283
|
+
每个部署包的外层 `README.txt` 和归档内 `APPLY.txt` 都包含文件索引、环境优先级、当前包的变量名和排障步骤。解包目录的 `config/.env.runtime` 是发布输入,部署根下的是当前运行配置,`releases/<ID>/` 下的是历史记录。外部 PostgreSQL 改密后更新项目源环境并发布后端。部署校验拒绝 URL 与分字段密码冲突,增量切换外部与随包中间件需要改用全量发布。
|
|
284
|
+
|
|
281
285
|
容器打包时,监听地址采用 `0.0.0.0`,端口采用制品声明值(未声明时采用部署配置),并生成 `HOST`、`PORT` 和 Serv 的对应细项。本机 `.env` 中的回环地址与开发端口继续用于本地运行。修改容器端口时更新制品与部署布局后重新部署。
|
|
282
286
|
|
|
283
287
|
Nginx 通过动态上游跟随应用和存储容器的 DNS 地址变化。共用的 `.hai/proxy-start.sh` 作为镜像入口钩子执行,保留镜像原有启动命令,并从容器 `/etc/resolv.conf` 读取解析器,HTTPS 时同时监视证书更新;Docker 与 Podman 均无需固定 DNS 地址。修改运行配置后重启后端,即使容器 IP 变化,代理也会自动恢复连接。
|
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
7
7
|
import { parseEnv } from 'node:util'
|
|
8
8
|
|
|
9
9
|
const maximumBytes = 1024 * 1024
|
|
10
|
+
const refreshCookieSecure = 'HAI_SERV_REFRESH_COOKIE_SECURE'
|
|
10
11
|
|
|
11
12
|
/** 拒绝特殊文件、链接、超限与不可读文件,不输出秘密。 */
|
|
12
13
|
function readText(name) {
|
|
@@ -46,7 +47,7 @@ function readEnvironment(name) {
|
|
|
46
47
|
const text = readText(name)
|
|
47
48
|
const values = parseEnv(text)
|
|
48
49
|
const names = new Set()
|
|
49
|
-
for (const match of text.matchAll(/^(?:export\
|
|
50
|
+
for (const match of text.matchAll(/^[ \t]*(?:export[ \t]+)?([A-Z_]\w*)[ \t]*=[ \t]*('[^']*'|"(?:[^"\\]|\\.)*"|`[^`]*`|[^\r\n]*)/gim)) {
|
|
50
51
|
if (names.has(match[1]))
|
|
51
52
|
throw new Error('Duplicate environment variable')
|
|
52
53
|
names.add(match[1])
|
|
@@ -62,6 +63,13 @@ function readEnvironment(name) {
|
|
|
62
63
|
catch { throw new Error('Runtime environment file could not be parsed') }
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
/** 校验最终生效的独立进程开关,允许空值使用 Serv 默认策略。 */
|
|
67
|
+
function validateRefreshCookie(values) {
|
|
68
|
+
const value = values[refreshCookieSecure]
|
|
69
|
+
if (value && value !== 'true' && value !== 'false')
|
|
70
|
+
throw new Error(`Runtime environment file: ${refreshCookieSecure} must be true, false or empty`)
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
/** 清单只保存非敏感元数据,不把环境值放入错误消息。 */
|
|
66
74
|
function readManifest(name) {
|
|
67
75
|
if (name === '-')
|
|
@@ -159,6 +167,7 @@ function prepare(directory, previousManifest, previousEnvironment, credentialSta
|
|
|
159
167
|
if (state.PROJECT && project && state.PROJECT !== project.trim())
|
|
160
168
|
throw new Error('Managed middleware credential project mismatch')
|
|
161
169
|
applyManagedPasswords(next, bindings, state)
|
|
170
|
+
validateRefreshCookie(next)
|
|
162
171
|
incoming.metadata['managed-app-keys'] = `${keys.join('\n')}${keys.length ? '\n' : ''}`
|
|
163
172
|
incoming.metadata['managed-bindings'] = `${bindings}${bindings ? '\n' : ''}`
|
|
164
173
|
if (project)
|
|
@@ -183,10 +192,12 @@ else {
|
|
|
183
192
|
const inherited = Object.fromEntries(Object.entries(process.env).filter(([name, value]) => name.startsWith('HAI_') && value !== undefined))
|
|
184
193
|
for (const name of Object.keys(inherited).sort((left, right) => left.length - right.length)) {
|
|
185
194
|
for (const previous of Object.keys(values)) {
|
|
186
|
-
|
|
195
|
+
// 与 Core 来源合并保持一致:独立开关只允许同名变量覆盖。
|
|
196
|
+
if (previous !== refreshCookieSecure && previous.startsWith(`${name}_`))
|
|
187
197
|
delete values[previous]
|
|
188
198
|
}
|
|
189
199
|
values[name] = inherited[name]
|
|
190
200
|
}
|
|
201
|
+
validateRefreshCookie(values)
|
|
191
202
|
Object.assign(process.env, values)
|
|
192
203
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ declare const DeploymentArtifactSchema: z.ZodObject<{
|
|
|
24
24
|
}>;
|
|
25
25
|
appVersion: z.ZodString;
|
|
26
26
|
buildId: z.ZodString;
|
|
27
|
+
source: z.ZodOptional<z.ZodObject<{
|
|
28
|
+
commit: z.ZodString;
|
|
29
|
+
dirty: z.ZodNullable<z.ZodBoolean>;
|
|
30
|
+
}, z.core.$strip>>;
|
|
27
31
|
partial: z.ZodDefault<z.ZodBoolean>;
|
|
28
32
|
hasWeb: z.ZodDefault<z.ZodBoolean>;
|
|
29
33
|
webBasePath: z.ZodOptional<z.ZodString>;
|
|
@@ -37,6 +41,7 @@ declare const DeploymentArtifactSchema: z.ZodObject<{
|
|
|
37
41
|
file: z.ZodString;
|
|
38
42
|
imageRef: z.ZodString;
|
|
39
43
|
sha256: z.ZodString;
|
|
44
|
+
platform: z.ZodOptional<z.ZodString>;
|
|
40
45
|
containerPort: z.ZodOptional<z.ZodNumber>;
|
|
41
46
|
}, z.core.$strip>>;
|
|
42
47
|
}, z.core.$strip>;
|
|
@@ -1072,7 +1077,7 @@ declare const deploy: DeployFunctions;
|
|
|
1072
1077
|
* const message = deployM('deploy_sshRequired')
|
|
1073
1078
|
* ```
|
|
1074
1079
|
*/
|
|
1075
|
-
declare const deployM: (key: "deploy_composeHostAddressInvalid" | "deploy_composeHostnameInvalid" | "deploy_composeHostnameConflict" | "deploy_composeProviderRequired" | "deploy_composeServiceUnavailable" | "deploy_notInitialized" | "deploy_initFailed" | "deploy_unsupportedProviderType" | "deploy_unsupportedProvisionerType" | "deploy_configTokenRequired" | "deploy_authRequired" | "deploy_authFailed" | "deploy_projectCreateFailed" | "deploy_uploadFailed" | "deploy_deployFailed" | "deploy_provisionFailed" | "deploy_adapterMissing" | "deploy_scanFailed" | "deploy_envVarFailed" | "deploy_credentialError" | "deploy_credentialInvalidKey" | "deploy_credentialSaved" | "deploy_credentialLoaded" | "deploy_configError" | "deploy_credentialMissing" | "deploy_apiError" | "deploy_fileUploadFailed" | "deploy_provisionNoResult" | "deploy_recoveryFailure" | "deploy_recoverySuggestion" | "deploy_commandTimeout" | "deploy_commandFailed" | "deploy_remoteConnectFailed" | "deploy_remoteRuntimeMissing" | "deploy_imageTransferFailed" | "deploy_healthCheckFailed" | "deploy_invalidEnvironment" | "deploy_environmentMissing" | "deploy_environmentReadFailed" | "deploy_environmentWriteFailed" | "deploy_multipleApplications" | "deploy_purposeSqlite" | "deploy_purposeDatabase" | "deploy_purposeMemory" | "deploy_purposeLocal" | "deploy_purposeCache" | "deploy_purposeStorage" | "deploy_purposeVector" | "deploy_purposeDisabled" | "deploy_purposeLdap" | "deploy_purposeConsole" | "deploy_purposeEmail" | "deploy_purposeSms" | "deploy_webProxyInvalid" | "deploy_webBaseConflict" | "deploy_storageProxyInvalid" | "deploy_storagePublicEndpointInvalid" | "deploy_storageBackendRequired" | "deploy_artifactInvalid" | "deploy_sshRequired" | "deploy_sshPasswordInvalid" | "deploy_sshAskpassFailed" | "deploy_sshAskpassCleanupFailed" | "deploy_targetAuth" | "deploy_targetPasswordEnv" | "deploy_bundleInstructions" | "deploy_bundleApplyGuide" | "deploy_bundleMetadata" | "deploy_targetHost" | "deploy_targetPort" | "deploy_targetUsername" | "deploy_targetIdentityFile" | "deploy_targetKnownHostsFile" | "deploy_targetStrictHostKeyChecking" | "deploy_targetConnectTimeoutSeconds" | "deploy_targetDirectory" | "deploy_targetBundle" | "deploy_bundleOnlyContainer" | "deploy_selectedContainerOnly" | "deploy_selectionInvalid" | "deploy_imageVersionRequired" | "deploy_bundleRuntimeRequired" | "deploy_bundleFailed" | "deploy_configFileInvalid" | "deploy_configFileUnreadable" | "deploy_bundleNameInvalid" | "deploy_localStopped" | "deploy_localUnknown" | "deploy_localNotStarted" | "deploy_commandOutputFailed" | "deploy_commandInputFailed" | "deploy_commandTreeActive" | "deploy_commandExecutionFailed" | "deploy_remoteUnknown" | "deploy_remoteFinished" | "deploy_bundleDirectoryExists" | "deploy_bundleFull" | "deploy_bundlePartial" | "deploy_bundleSelection" | "deploy_transportBodyLimitInvalid" | "deploy_transportKeyRingInvalid" | "deploy_uploadPasswordPrompt" | "deploy_uploadPasswordUnavailable" | "deploy_uploadPasswordCancelled" | "deploy_uploadPasswordInvalid" | "deploy_managedSecretsInvalid" | "deploy_secretImportFailed" | "deploy_projectNameRequired" | "deploy_projectNameOverrideRemoved" | "deploy_requestAccessInvalid" | "deploy_httpsPortsInvalid" | "deploy_httpsCertificateInvalid" | "deploy_bundleRuntime" | "deploy_bundleHttpOnly" | "deploy_bundleHttps" | "deploy_bundleAcme" | "deploy_bundleAccounts" | "deploy_bundleDirectories" | "deploy_downloadInvalid" | "deploy_imageSourceMissing" | "deploy_proxySystemUnsupported" | "deploy_middlewareFieldInvalid" | "deploy_middlewareFieldError" | "deploy_middlewareRequired" | "deploy_middlewareInteger" | "deploy_middlewareBoolean" | "deploy_middlewareUrl" | "deploy_middlewareS3Endpoint" | "deploy_middlewareTlsSyntax" | "deploy_middlewareMysqlTls" | "deploy_middlewarePostgresTls" | "deploy_middlewareHeaders" | "deploy_middlewareMethod" | "deploy_configResolutionFailed" | "deploy_reachEmptyProviderOverride" | "deploy_s3Engine", options?: _h_ai_core.MessageOptions) => string;
|
|
1080
|
+
declare const deployM: (key: "deploy_composeHostAddressInvalid" | "deploy_composeHostnameInvalid" | "deploy_composeHostnameConflict" | "deploy_composeProviderRequired" | "deploy_composeServiceUnavailable" | "deploy_notInitialized" | "deploy_initFailed" | "deploy_unsupportedProviderType" | "deploy_unsupportedProvisionerType" | "deploy_configTokenRequired" | "deploy_authRequired" | "deploy_authFailed" | "deploy_projectCreateFailed" | "deploy_uploadFailed" | "deploy_deployFailed" | "deploy_provisionFailed" | "deploy_adapterMissing" | "deploy_scanFailed" | "deploy_envVarFailed" | "deploy_credentialError" | "deploy_credentialInvalidKey" | "deploy_credentialSaved" | "deploy_credentialLoaded" | "deploy_configError" | "deploy_credentialMissing" | "deploy_apiError" | "deploy_fileUploadFailed" | "deploy_provisionNoResult" | "deploy_recoveryFailure" | "deploy_recoverySuggestion" | "deploy_commandTimeout" | "deploy_commandFailed" | "deploy_remoteConnectFailed" | "deploy_remoteRuntimeMissing" | "deploy_imageTransferFailed" | "deploy_healthCheckFailed" | "deploy_invalidEnvironment" | "deploy_environmentMissing" | "deploy_environmentReadFailed" | "deploy_environmentWriteFailed" | "deploy_multipleApplications" | "deploy_purposeSqlite" | "deploy_purposeDatabase" | "deploy_purposeMemory" | "deploy_purposeLocal" | "deploy_purposeCache" | "deploy_purposeStorage" | "deploy_purposeVector" | "deploy_purposeDisabled" | "deploy_purposeLdap" | "deploy_purposeConsole" | "deploy_purposeEmail" | "deploy_purposeSms" | "deploy_webProxyInvalid" | "deploy_webBaseConflict" | "deploy_storageProxyInvalid" | "deploy_storagePublicEndpointInvalid" | "deploy_storageBackendRequired" | "deploy_artifactInvalid" | "deploy_sshRequired" | "deploy_sshPasswordInvalid" | "deploy_sshAskpassFailed" | "deploy_sshAskpassCleanupFailed" | "deploy_targetAuth" | "deploy_targetPasswordEnv" | "deploy_bundleInstructions" | "deploy_bundleApplyGuide" | "deploy_bundleMetadata" | "deploy_targetHost" | "deploy_targetPort" | "deploy_targetUsername" | "deploy_targetIdentityFile" | "deploy_targetKnownHostsFile" | "deploy_targetStrictHostKeyChecking" | "deploy_targetConnectTimeoutSeconds" | "deploy_targetDirectory" | "deploy_targetBundle" | "deploy_bundleOnlyContainer" | "deploy_selectedContainerOnly" | "deploy_selectionInvalid" | "deploy_imageVersionRequired" | "deploy_bundleRuntimeRequired" | "deploy_bundleFailed" | "deploy_configFileInvalid" | "deploy_configFileUnreadable" | "deploy_bundleNameInvalid" | "deploy_localStopped" | "deploy_localUnknown" | "deploy_localNotStarted" | "deploy_commandOutputFailed" | "deploy_commandInputFailed" | "deploy_commandTreeActive" | "deploy_commandExecutionFailed" | "deploy_remoteUnknown" | "deploy_remoteFinished" | "deploy_bundleDirectoryExists" | "deploy_bundleFull" | "deploy_bundlePartial" | "deploy_bundleSelection" | "deploy_transportBodyLimitInvalid" | "deploy_transportKeyRingInvalid" | "deploy_uploadPasswordPrompt" | "deploy_uploadPasswordUnavailable" | "deploy_uploadPasswordCancelled" | "deploy_uploadPasswordInvalid" | "deploy_managedSecretsInvalid" | "deploy_secretImportFailed" | "deploy_projectNameRequired" | "deploy_projectNameOverrideRemoved" | "deploy_requestAccessInvalid" | "deploy_httpsPortsInvalid" | "deploy_httpsCertificateInvalid" | "deploy_bundleRuntime" | "deploy_refreshCookieSecureInvalid" | "deploy_postgresPasswordConflict" | "deploy_bundleVariables" | "deploy_bundleHttpOnly" | "deploy_bundleHttps" | "deploy_bundleAcme" | "deploy_bundleAccounts" | "deploy_bundleDirectories" | "deploy_downloadInvalid" | "deploy_imageSourceMissing" | "deploy_proxySystemUnsupported" | "deploy_middlewareFieldInvalid" | "deploy_middlewareFieldError" | "deploy_middlewareRequired" | "deploy_middlewareInteger" | "deploy_middlewareBoolean" | "deploy_middlewareUrl" | "deploy_middlewareS3Endpoint" | "deploy_middlewareTlsSyntax" | "deploy_middlewareMysqlTls" | "deploy_middlewarePostgresTls" | "deploy_middlewareHeaders" | "deploy_middlewareMethod" | "deploy_configResolutionFailed" | "deploy_reachEmptyProviderOverride" | "deploy_s3Engine", options?: _h_ai_core.MessageOptions) => string;
|
|
1076
1081
|
|
|
1077
1082
|
/**
|
|
1078
1083
|
* 部署中间件的后端与连接字段目录,供扫描、CLI 和容器规划共同使用。
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,13 @@ var DeploymentArtifactSchema = z.object({
|
|
|
29
29
|
appVersion: z.string().max(80).regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9a-z-]+(?:\.[0-9a-z-]+)*)?(?:\+[0-9a-z-]+(?:\.[0-9a-z-]+)*)?$/i),
|
|
30
30
|
/** 本次构建标识;同一应用版本允许重复构建。 */
|
|
31
31
|
buildId: z.string().max(128).regex(/^[a-z0-9][\w.+-]*$/i),
|
|
32
|
+
/** 构建启动时观察到的 Git 来源;历史清单可以省略。 */
|
|
33
|
+
source: z.object({
|
|
34
|
+
/** 工程 package.json 所在仓库的提交 SHA;无法确定时为 unknown。 */
|
|
35
|
+
commit: z.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64}|unknown)$/),
|
|
36
|
+
/** 工程目录有未提交改动时为 true;无法检查时为 null。 */
|
|
37
|
+
dirty: z.boolean().nullable()
|
|
38
|
+
}).optional(),
|
|
32
39
|
/** 只包含所选镜像的构建不能用于首次安装。 */
|
|
33
40
|
partial: z.boolean().default(false),
|
|
34
41
|
/** 是否包含浏览器端;仅构建 serv 时也保留完整工程的 Web 拓扑。 */
|
|
@@ -49,6 +56,8 @@ var DeploymentArtifactSchema = z.object({
|
|
|
49
56
|
imageRef: z.string().regex(/^[a-z0-9][a-z0-9./:_-]*:[a-z0-9_][a-z0-9_.-]*$/).refine((value) => !value.endsWith(":latest")),
|
|
50
57
|
/** tar 内容的 SHA-256,用于部署前校验。 */
|
|
51
58
|
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
59
|
+
/** 引擎实际构建的镜像 OS/架构;历史清单可以省略。 */
|
|
60
|
+
platform: z.string().regex(/^[a-z0-9][a-z0-9_.-]*\/[a-z0-9][a-z0-9_.-]*$/).optional(),
|
|
52
61
|
/** 容器内部监听端口;服务器公开端口由部署选择。 */
|
|
53
62
|
containerPort: z.number().int().min(1).max(65535).optional()
|
|
54
63
|
})).min(1).max(2).refine((images) => new Set(images.map((image) => image.name)).size === images.length)
|
|
@@ -183,12 +192,15 @@ var en_US_default = {
|
|
|
183
192
|
deploy_requestAccessInvalid: "Invalid request access policy ({field}). Check fields, IP addresses, timezones and time windows. For a file reference, use readable YAML no larger than 1 MiB. Fix the configuration and create a new bundle.",
|
|
184
193
|
deploy_httpsPortsInvalid: "HTTP and HTTPS ports must differ; Let\u2019s Encrypt HTTP-01 requires host port 80.",
|
|
185
194
|
deploy_httpsCertificateInvalid: "Invalid HTTPS certificate. Check readable PEM files, matching unencrypted private key, validity dates and domain, then repackage.",
|
|
186
|
-
deploy_bundleRuntime: "
|
|
195
|
+
deploy_bundleRuntime: "Configuration files and activation\nconfig/.env.runtime in the unpacked bundle is this release's input. It contains application configuration and may include bundled middleware candidates. Change the project environment and rebuild the bundle. apply.sh verifies the unpacked content.\n{directory}/config/.env.runtime is the active configuration. Serv and SvelteKit SSR read it from the read-only /run/hai/config mount on each start.\nThe active file uses literal dotenv syntax and is limited to 1 MiB. Missing, unreadable, oversized, or duplicate assignments fail before startup.\n{directory}/releases/{deploymentId}/config/.env.runtime records this release. Updates that only select Web or middleware copy the configuration active at the time. Inspect the root file for the active value and the matching release for a historical value.\nA full deployment uses the new bundle configuration and reuses stored managed credentials. A partial update of the primary application takes external connections and application settings from the new bundle and keeps existing managed connections. A partial update that excludes the primary application keeps the active configuration. Switching between bundled and external middleware requires a full deployment.\nFor a temporary Node backend fix, back up and edit the active file, run docker restart <container> or podman restart <container>, and verify health and the affected feature. Put lasting changes in the project environment so the next backend release carries them. An explicit HAI_* value in the container process takes precedence.\nRedeploy changes to static Web or native middleware environments, ports, mounts, Node options, Nginx routes or limits, and HTTPS assembly. A website base path change also requires a rebuild.\nRecovery restores the active application file before restarting previous services. The database maintenance procedure handles password and data changes already made inside the database.",
|
|
196
|
+
deploy_refreshCookieSecureInvalid: "HAI_SERV_REFRESH_COOKIE_SECURE must be true, false, or empty. Check the selected environment and packaging process for this variable.",
|
|
197
|
+
deploy_postgresPasswordConflict: "External PostgreSQL has different passwords in HAI_DB_URL (or HAI_DB.url) and HAI_DB_PASSWORD (or HAI_DB.password). Use a complete URL or separate connection fields.",
|
|
198
|
+
deploy_bundleVariables: "Environment variables and troubleshooting (names only)\nTarget environment: {environment}. Packaging priority, highest first: packaging process, .env.{environment}.local, .env.local, .env.{environment}, .env, and application YAML defaults. --env-dir selects the source directory. A field overrides its parent JSON in the same source. Higher-priority parent JSON replaces older structured fields.\nNames in this bundle's config/.env.runtime (--plan lists source input names): {keys}\nHAI_SERV_REFRESH_COOKIE_SECURE is a standalone process flag. Only the same name overrides it. true enables Secure, false is for controlled intranet or VPN HTTP access, and empty or absent uses the Serv environment default (enabled in production). Set HAI_SERV_CORS_ORIGIN to the actual HTTP origin. Verify login and refresh after deployment.\nExample for controlled HTTP: set HAI_SERV_REFRESH_COOKIE_SECURE=false in .env.{environment}.local and configure the actual CORS origin. With a successful full deployment and a serv image artifact, run pnpm run deploy --env {environment} --bundle-only --yes --services serv from the project. Unpack on the server and run sh ./apply.sh.\nExternal PostgreSQL uses HAI_DB_URL (a complete connection string with required authentication) or HAI_DB_HOST, HAI_DB_PORT, HAI_DB_USER, HAI_DB_DATABASE, and HAI_DB_PASSWORD. A URL takes precedence. Update the effective form when changing credentials. After updating the database account and the source environment, deploy serv or a full bundle.\nHAI_CACHE_*, HAI_STORAGE_*, HAI_VECDB_*, and HAI_IAM_LDAP_* configure application connections. S3 uses separate endpoint and access credentials. External or cloud-provisioned services normally have no native container variables in this bundle.\nFor bundled PostgreSQL, DB_PASSWORD in managed-secrets.env supplies HAI_DB_URL for the application and POSTGRES_PASSWORD for the image. POSTGRES_PASSWORD initializes an empty data directory. Other bundled images may use MYSQL_*, RUSTFS_*, MINIO_*, or LDAP_*. Rotate existing-volume credentials in both the actual account and managed state. A container restart or recreation alone cannot rotate a database password.\nNODE_ENV selects the application environment. The delivery topology determines listen settings in HOST, PORT, and HAI_SERV_SERVER_*. NODE_OPTIONS and HAI_DEPLOY_PRIVATE_PROXY come from container assembly. HAI_DEPLOY_PROVIDER_SSH_PASSWORD is used by the uploader for SSH.\nProtect the archive, runtime configuration, credentials, private keys, and failure logs. When sharing with operators or AI, use variable names, sources, redacted errors, and the deployment ID.",
|
|
187
199
|
deploy_bundleHttpOnly: "HTTPS: disabled. This bundle exposes HTTP port {port}, contains no certificate attachment and will not request a certificate on the server.",
|
|
188
200
|
deploy_bundleHttps: "HTTPS: enabled, https://{domain}:{port}; mode {mode}.\nServer certificate: {certificates}/fullchain.pem; private key: {certificates}/privkey.pem. Mounted read-only at /etc/nginx/tls/.\nEdit expose.https in HAI_DEPLOY_PROVIDER in the packaging environment .env.{environment}.local, or the unshadowed hai.json.deploy.provider.expose.https. Enable/disable, mode, domain or port changes require a new full bundle; editing .env.runtime and restarting does not issue a certificate for a new domain.",
|
|
189
201
|
deploy_bundleAcme: "Persistent Certbot state: {state}; current certificate entry: {state}/live/{domain}. Packaging does not contact the CA; issuance runs during server deployment, followed by automatic renewal. Public port 80 and root /.well-known/acme-challenge/ must remain reachable independently of the business context path.",
|
|
190
202
|
deploy_bundleAccounts: "Initial account variables (names and sources only; passwords omitted):\n{sources}\nApplications with matching bootstrap logic use HAI_CONFIG_ADMIN_PASSWORD to create the config_admin configuration administrator. HAI_ADMIN_DEFAULT_PASSWORD, HAI_AUDIT_ADMIN_PASSWORD and HAI_BUSINESS_OPERATOR_PASSWORD belong to the other template roles.\nFullstack creation generates independent initial passwords per environment. Packaging reads the selected environment and process overrides; server deployment does not generate new application account passwords. Startup creates missing configured accounts; changing variables does not reset existing passwords or restore old roles. Custom applications without this bootstrap follow their own implementation.",
|
|
191
|
-
deploy_bundleDirectories: "
|
|
203
|
+
deploy_bundleDirectories: "File index (server paths use the actual deployment root, default {directory})\nDelivery README.txt gives an overview. deploy.sh and deploy.ps1 upload and apply over SSH. deploy-target.json selects the target, authentication, and directory. read-target.awk reads that file for scripts. deploy-local.sh unpacks and applies on the server.\nIn the archive, APPLY.txt describes manual deployment and configuration. apply.sh verifies, locks, imports, and starts services. manifest.json records artifacts, mode, selected services, and non-secret metadata. images/ carries OCI archives for import into the engine.\nThe archive's .hai/compose.json contains selected services. The installed copy is the complete merged snapshot. .hai/SHA256SUMS checks the original unpacked files. Server copies can change during configuration finalization and merge.\nCompose uses .hai/middleware-runtime.env for bundled containers. The file can be empty when no native settings are needed. Retained services may refer to an older release, so follow env_file in the effective Compose snapshot. apply.sh consumes .hai/managed-candidates.env for first-install candidates.\n.hai/runtime-env.mjs loads and finalizes the Node environment. Optional files include .hai/request-access.yml, .hai/web.conf, proxy scripts, and .hai/tls/ for access policies, reverse proxying, and HTTPS.\nServer incoming/ holds this upload and unpacked files. releases/ holds deployment and recovery records. Protect and back up managed-secrets.env, persistent-backends, and data volumes together. .deploy.lock coordinates deployment and credential operations.\ncurrent updates after server health checks pass. result-{deploymentId}.json records the outcome and recovery state, steps-{deploymentId}.jsonl records progress, and diagnostics-{deploymentId}.log contains private startup diagnostics on failure. Check active Compose references, mounts, and recovery needs before pruning old releases.",
|
|
192
204
|
deploy_downloadInvalid: "Invalid download source or proxy configuration. URLs must not contain credentials or query parameters.",
|
|
193
205
|
deploy_imageSourceMissing: "Custom image source has no mapping for registry: {registry}",
|
|
194
206
|
deploy_proxySystemUnsupported: "Static system proxy is unavailable, or only PAC/auto-discovery is configured. Use inherit with environment variables or a custom HTTP(S) URL.",
|
|
@@ -323,12 +335,15 @@ var ja_JP_default = {
|
|
|
323
335
|
deploy_requestAccessInvalid: "\u30EA\u30AF\u30A8\u30B9\u30C8\u30A2\u30AF\u30BB\u30B9\u8A2D\u5B9A\uFF08{field}\uFF09\u304C\u7121\u52B9\u3067\u3059\u3002\u30D5\u30A3\u30FC\u30EB\u30C9\u3001IP\u3001\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3\u3001\u6642\u9593\u5E2F\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30D5\u30A1\u30A4\u30EB\u306F\u8AAD\u307F\u53D6\u308A\u53EF\u80FD\u306A 1 MiB \u4EE5\u4E0B\u306E YAML \u3092\u6307\u5B9A\u3057\u3001\u4FEE\u6B63\u5F8C\u306B\u518D\u30D1\u30C3\u30B1\u30FC\u30B8\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
324
336
|
deploy_httpsPortsInvalid: "HTTP \u3068 HTTPS \u306E\u30DD\u30FC\u30C8\u306F\u7570\u306A\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002Let\u2019s Encrypt HTTP-01 \u306B\u306F\u30DB\u30B9\u30C8\u306E\u30DD\u30FC\u30C8 80 \u304C\u5FC5\u8981\u3067\u3059\u3002",
|
|
325
337
|
deploy_httpsCertificateInvalid: "HTTPS \u8A3C\u660E\u66F8\u304C\u7121\u52B9\u3067\u3059\u3002PEM \u30D5\u30A1\u30A4\u30EB\u3001\u6697\u53F7\u5316\u3055\u308C\u3066\u3044\u306A\u3044\u79D8\u5BC6\u9375\u3068\u306E\u4E00\u81F4\u3001\u6709\u52B9\u671F\u9593\u3001\u30C9\u30E1\u30A4\u30F3\u3092\u78BA\u8A8D\u3057\u3001\u518D\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
326
|
-
deploy_bundleRuntime: "\
|
|
338
|
+
deploy_bundleRuntime: "\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u3068\u53CD\u6620\u306E\u30BF\u30A4\u30DF\u30F3\u30B0\n\u5C55\u958B\u5148\u306E config/.env.runtime \u306F\u4ECA\u56DE\u306E\u914D\u5099\u5165\u529B\u3067\u3059\u3002\u30A2\u30D7\u30EA\u8A2D\u5B9A\u3068\u540C\u68B1\u30DF\u30C9\u30EB\u30A6\u30A7\u30A2\u306E\u5019\u88DC\u5024\u304C\u542B\u307E\u308C\u307E\u3059\u3002\u5909\u66F4\u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u74B0\u5883\u8A2D\u5B9A\u306B\u53CD\u6620\u3057\u3066\u518D\u30D1\u30C3\u30B1\u30FC\u30B8\u5316\u3057\u3066\u304F\u3060\u3055\u3044\u3002apply.sh \u304C\u5C55\u958B\u5185\u5BB9\u3092\u691C\u8A3C\u3057\u307E\u3059\u3002\n{directory}/config/.env.runtime \u306F\u73FE\u5728\u306E\u5B9F\u884C\u8A2D\u5B9A\u3067\u3059\u3002Serv \u3068 SvelteKit SSR \u306F\u8D77\u52D5\u3054\u3068\u306B\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u306E /run/hai/config \u30DE\u30A6\u30F3\u30C8\u304B\u3089\u8AAD\u307F\u8FBC\u307F\u307E\u3059\u3002\n\u5B9F\u884C\u30D5\u30A1\u30A4\u30EB\u306F dotenv \u306E\u30EA\u30C6\u30E9\u30EB\u69CB\u6587\u3092\u4F7F\u7528\u3057\u3001\u4E0A\u9650\u306F 1 MiB \u3067\u3059\u3002\u6B20\u843D\u3001\u8AAD\u307F\u53D6\u308A\u4E0D\u80FD\u3001\u91CD\u8907\u5B9A\u7FA9\u3001\u4E0A\u9650\u8D85\u904E\u306F\u30A2\u30D7\u30EA\u8D77\u52D5\u524D\u306B\u30A8\u30E9\u30FC\u306B\u306A\u308A\u307E\u3059\u3002\n{directory}/releases/{deploymentId}/config/.env.runtime \u306F\u4ECA\u56DE\u306E\u914D\u5099\u8A18\u9332\u3067\u3059\u3002Web \u307E\u305F\u306F\u30DF\u30C9\u30EB\u30A6\u30A7\u30A2\u306E\u307F\u66F4\u65B0\u3059\u308B\u5834\u5408\u306F\u5F53\u6642\u306E\u5B9F\u884C\u8A2D\u5B9A\u3092\u8A18\u9332\u3057\u307E\u3059\u3002\u73FE\u5728\u5024\u306F\u30EB\u30FC\u30C8\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u3001\u904E\u53BB\u306E\u5024\u306F\u8A72\u5F53\u3059\u308B release \u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002\n\u5168\u91CF\u914D\u5099\u3067\u306F\u65B0\u3057\u3044\u30A2\u30D7\u30EA\u8A2D\u5B9A\u3068\u65E2\u5B58\u306E\u7BA1\u7406\u8CC7\u683C\u60C5\u5831\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002\u4E3B\u30A2\u30D7\u30EA\u3092\u542B\u3080\u90E8\u5206\u66F4\u65B0\u3067\u306F\u65B0\u3057\u3044\u30A2\u30D7\u30EA\u8A2D\u5B9A\u3068\u5916\u90E8\u63A5\u7D9A\u3092\u9069\u7528\u3057\u3001\u65E2\u5B58\u306E\u7BA1\u7406\u63A5\u7D9A\u3092\u7DAD\u6301\u3057\u307E\u3059\u3002\u4E3B\u30A2\u30D7\u30EA\u3092\u542B\u307E\u306A\u3044\u90E8\u5206\u66F4\u65B0\u3067\u306F\u73FE\u5728\u306E\u8A2D\u5B9A\u3092\u7DAD\u6301\u3057\u307E\u3059\u3002\u5916\u90E8\u3068\u540C\u68B1\u306E\u5207\u308A\u66FF\u3048\u306B\u306F\u5168\u91CF\u914D\u5099\u304C\u5FC5\u8981\u3067\u3059\u3002\nNode \u30D0\u30C3\u30AF\u30A8\u30F3\u30C9\u306E\u4E00\u6642\u4FEE\u6B63\u3067\u306F\u3001\u73FE\u5728\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3057\u3066\u7DE8\u96C6\u3057\u3001docker restart <\u30B3\u30F3\u30C6\u30CA\u30FC> \u307E\u305F\u306F podman restart <\u30B3\u30F3\u30C6\u30CA\u30FC> \u3092\u5B9F\u884C\u3057\u3066\u3001\u30D8\u30EB\u30B9\u3068\u5BFE\u8C61\u6A5F\u80FD\u3092\u78BA\u8A8D\u3057\u307E\u3059\u3002\u7D99\u7D9A\u3059\u308B\u5909\u66F4\u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u74B0\u5883\u8A2D\u5B9A\u306B\u3082\u53CD\u6620\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30B3\u30F3\u30C6\u30CA\u30FC\u30D7\u30ED\u30BB\u30B9\u306B\u660E\u793A\u3057\u305F\u540C\u540D\u306E HAI_* \u304C\u512A\u5148\u3055\u308C\u307E\u3059\u3002\n\u9759\u7684 Web\u3001\u30DF\u30C9\u30EB\u30A6\u30A7\u30A2\u56FA\u6709\u306E\u74B0\u5883\u5909\u6570\u3001\u30DD\u30FC\u30C8\u3001\u30DE\u30A6\u30F3\u30C8\u3001Node \u8D77\u52D5\u5F15\u6570\u3001Nginx \u306E\u30EB\u30FC\u30C8\u3084\u5236\u9650\u3001HTTPS \u306E\u5909\u66F4\u306F\u518D\u914D\u5099\u3057\u307E\u3059\u3002\u30B5\u30A4\u30C8\u306E base \u30D1\u30B9\u5909\u66F4\u306B\u306F\u518D\u30D3\u30EB\u30C9\u3082\u5FC5\u8981\u3067\u3059\u3002\n\u969C\u5BB3\u5FA9\u65E7\u3067\u306F\u5B9F\u884C\u8A2D\u5B9A\u3092\u5148\u306B\u623B\u3057\u3001\u4EE5\u524D\u306E\u30B5\u30FC\u30D3\u30B9\u3092\u5FA9\u5143\u3057\u307E\u3059\u3002\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u5185\u3067\u5B9F\u884C\u6E08\u307F\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3084\u30C7\u30FC\u30BF\u306E\u5909\u66F4\u306F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u4FDD\u5B88\u624B\u9806\u3067\u6271\u3044\u307E\u3059\u3002",
|
|
339
|
+
deploy_refreshCookieSecureInvalid: "HAI_SERV_REFRESH_COOKIE_SECURE \u306B\u306F true\u3001false\u3001\u307E\u305F\u306F\u7A7A\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u5BFE\u8C61\u74B0\u5883\u3068\u30D1\u30C3\u30B1\u30FC\u30B8\u4F5C\u6210\u30D7\u30ED\u30BB\u30B9\u306E\u540C\u540D\u5909\u6570\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
340
|
+
deploy_postgresPasswordConflict: "\u5916\u90E8 PostgreSQL \u306E HAI_DB_URL\uFF08\u307E\u305F\u306F HAI_DB.url\uFF09\u3068 HAI_DB_PASSWORD\uFF08\u307E\u305F\u306F HAI_DB.password\uFF09\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u5B8C\u5168\u306A\u63A5\u7D9A URL \u307E\u305F\u306F\u500B\u5225\u9805\u76EE\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
341
|
+
deploy_bundleVariables: "\u74B0\u5883\u5909\u6570\u3068\u8ABF\u67FB\uFF08\u540D\u524D\u306E\u307F\uFF09\n\u5BFE\u8C61\u74B0\u5883\u306F {environment} \u3067\u3059\u3002\u4F5C\u6210\u6642\u306E\u512A\u5148\u9806\u306F\u30D7\u30ED\u30BB\u30B9\u3001.env.{environment}.local\u3001.env.local\u3001.env.{environment}\u3001.env\u3001\u30A2\u30D7\u30EA YAML \u306E\u65E2\u5B9A\u5024\u3067\u3059\u3002--env-dir \u3067\u8AAD\u307F\u53D6\u308A\u5148\u3092\u9078\u3073\u307E\u3059\u3002\u540C\u3058\u30BD\u30FC\u30B9\u3067\u306F\u500B\u5225\u9805\u76EE\u304C\u89AA JSON \u3088\u308A\u512A\u5148\u3055\u308C\u3001\u4E0A\u4F4D\u306E\u89AA JSON \u306F\u4E0B\u4F4D\u306E\u69CB\u9020\u9805\u76EE\u3092\u7F6E\u304D\u63DB\u3048\u307E\u3059\u3002\n\u540C\u68B1\u306E config/.env.runtime \u306B\u542B\u307E\u308C\u308B\u5909\u6570\u540D\uFF08--plan \u306F\u5165\u529B\u5074\u306E\u540D\u524D\u3092\u8868\u793A\uFF09: {keys}\nHAI_SERV_REFRESH_COOKIE_SECURE \u306F\u72EC\u7ACB\u3057\u305F\u30D7\u30ED\u30BB\u30B9\u5909\u6570\u3067\u3001\u540C\u540D\u306E\u5024\u306E\u307F\u3067\u4E0A\u66F8\u304D\u3057\u307E\u3059\u3002true \u306F Secure \u3092\u6709\u52B9\u306B\u3057\u3001false \u306F\u7BA1\u7406\u3055\u308C\u305F\u30A4\u30F3\u30C8\u30E9\u30CD\u30C3\u30C8\u307E\u305F\u306F VPN \u306E HTTP \u7528\u3067\u3059\u3002\u7A7A\u5024\u3068\u672A\u8A2D\u5B9A\u306F Serv \u74B0\u5883\u306E\u65E2\u5B9A\u5024\uFF08\u672C\u756A\u3067\u306F\u6709\u52B9\uFF09\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002\u5B9F\u969B\u306E HTTP \u30AA\u30EA\u30B8\u30F3\u3092 HAI_SERV_CORS_ORIGIN \u306B\u8A2D\u5B9A\u3057\u3001\u914D\u5099\u5F8C\u306B\u30ED\u30B0\u30A4\u30F3\u3068\u66F4\u65B0\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\n\u7BA1\u7406\u3055\u308C\u305F HTTP \u306E\u4F8B\u3067\u306F\u3001.env.{environment}.local \u306B HAI_SERV_REFRESH_COOKIE_SECURE=false \u3068\u5B9F\u969B\u306E CORS \u30AA\u30EA\u30B8\u30F3\u3092\u8A2D\u5B9A\u3057\u307E\u3059\u3002\u5168\u91CF\u914D\u5099\u304C\u6210\u529F\u6E08\u307F\u3067 serv \u30A4\u30E1\u30FC\u30B8\u6210\u679C\u7269\u304C\u3042\u308B\u5834\u5408\u3001\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067 pnpm run deploy --env {environment} --bundle-only --yes --services serv \u3092\u5B9F\u884C\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u3067\u5C55\u958B\u3057\u3066 sh ./apply.sh \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\n\u5916\u90E8 PostgreSQL \u306F\u8A8D\u8A3C\u3092\u542B\u3080\u5B8C\u5168\u306A HAI_DB_URL\u3001\u307E\u305F\u306F HAI_DB_HOST\u3001HAI_DB_PORT\u3001HAI_DB_USER\u3001HAI_DB_DATABASE\u3001HAI_DB_PASSWORD \u3092\u4F7F\u7528\u3057\u307E\u3059\u3002URL \u304C\u512A\u5148\u3055\u308C\u307E\u3059\u3002\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u3068\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u74B0\u5883\u306E\u6709\u52B9\u306A\u8A2D\u5B9A\u3092\u66F4\u65B0\u3057\u3001serv \u307E\u305F\u306F\u5168\u91CF\u3092\u914D\u5099\u3057\u3066\u304F\u3060\u3055\u3044\u3002\nHAI_CACHE_*\u3001HAI_STORAGE_*\u3001HAI_VECDB_*\u3001HAI_IAM_LDAP_* \u306F\u30A2\u30D7\u30EA\u63A5\u7D9A\u7528\u3067\u3059\u3002S3 \u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3068\u30A2\u30AF\u30BB\u30B9\u30AD\u30FC\u306F\u500B\u5225\u306B\u8A2D\u5B9A\u3057\u307E\u3059\u3002\u5916\u90E8\u304A\u3088\u3073\u30AF\u30E9\u30A6\u30C9\u4E0A\u306E\u30B5\u30FC\u30D3\u30B9\u306B\u306F\u3001\u901A\u5E38\u3053\u306E\u30D0\u30F3\u30C9\u30EB\u306E\u30B3\u30F3\u30C6\u30CA\u30FC\u56FA\u6709\u5909\u6570\u306F\u3042\u308A\u307E\u305B\u3093\u3002\n\u540C\u68B1 PostgreSQL \u3067\u306F managed-secrets.env \u306E DB_PASSWORD \u304B\u3089\u30A2\u30D7\u30EA\u7528\u306E HAI_DB_URL \u3068\u30A4\u30E1\u30FC\u30B8\u7528\u306E POSTGRES_PASSWORD \u3092\u751F\u6210\u3057\u307E\u3059\u3002POSTGRES_PASSWORD \u306F\u7A7A\u306E\u30C7\u30FC\u30BF\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\u3092\u521D\u671F\u5316\u3057\u307E\u3059\u3002\u4ED6\u306E\u540C\u68B1\u30A4\u30E1\u30FC\u30B8\u3067\u306F MYSQL_*\u3001RUSTFS_*\u3001MINIO_*\u3001LDAP_* \u304C\u4F7F\u308F\u308C\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\u3002\u65E2\u5B58\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u5909\u66F4\u306F\u5B9F\u969B\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u3068\u7BA1\u7406\u72B6\u614B\u3092\u540C\u671F\u3057\u307E\u3059\u3002\nNODE_ENV \u306F\u30A2\u30D7\u30EA\u306E\u5B9F\u884C\u74B0\u5883\u3067\u3059\u3002HOST\u3001PORT\u3001HAI_SERV_SERVER_* \u306E\u5F85\u53D7\u8A2D\u5B9A\u306F\u914D\u5099\u6642\u306B\u78BA\u5B9A\u3057\u307E\u3059\u3002NODE_OPTIONS \u3068 HAI_DEPLOY_PRIVATE_PROXY \u306F\u30B3\u30F3\u30C6\u30CA\u30FC\u306E\u69CB\u6210\u3067\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002HAI_DEPLOY_PROVIDER_SSH_PASSWORD \u306F\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u5074\u306E SSH \u7528\u3067\u3059\u3002\n\u30A2\u30FC\u30AB\u30A4\u30D6\u3001\u5B9F\u884C\u8A2D\u5B9A\u3001\u8CC7\u683C\u60C5\u5831\u3001\u79D8\u5BC6\u9375\u3001\u969C\u5BB3\u30ED\u30B0\u306F\u975E\u516C\u958B\u3067\u4FDD\u7BA1\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u904B\u7528\u62C5\u5F53\u8005\u3084 AI \u3068\u5171\u6709\u3059\u308B\u969B\u306F\u5909\u6570\u540D\u3001\u53D6\u5F97\u5143\u3001\u79D8\u533F\u5316\u6E08\u307F\u306E\u30A8\u30E9\u30FC\u3001\u914D\u5099 ID \u306E\u307F\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
327
342
|
deploy_bundleHttpOnly: "HTTPS\uFF1A\u7121\u52B9\u3002HTTP \u30DD\u30FC\u30C8 {port} \u306E\u307F\u3092\u516C\u958B\u3057\u3001\u8A3C\u660E\u66F8\u306F\u540C\u68B1\u305B\u305A\u3001\u30B5\u30FC\u30D0\u30FC\u3067\u3082\u7533\u8ACB\u3057\u307E\u305B\u3093\u3002",
|
|
328
343
|
deploy_bundleHttps: "HTTPS\uFF1A\u6709\u52B9\u3001https://{domain}:{port}\u3001\u30E2\u30FC\u30C9 {mode}\u3002\n\u30B5\u30FC\u30D0\u30FC\u8A3C\u660E\u66F8\uFF1A{certificates}/fullchain.pem\u3001\u79D8\u5BC6\u9375\uFF1A{certificates}/privkey.pem\u3002\u30B3\u30F3\u30C6\u30CA\u306E /etc/nginx/tls/ \u306B\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u3067\u30DE\u30A6\u30F3\u30C8\u3057\u307E\u3059\u3002\n\u914D\u5E03\u5143 .env.{environment}.local \u306E HAI_DEPLOY_PROVIDER \u5185 expose.https\u3001\u307E\u305F\u306F\u4E0A\u66F8\u304D\u3055\u308C\u3066\u3044\u306A\u3044 hai.json.deploy.provider.expose.https \u3092\u7DE8\u96C6\u3057\u307E\u3059\u3002\u6709\u52B9/\u7121\u52B9\u3001\u30E2\u30FC\u30C9\u3001\u30C9\u30E1\u30A4\u30F3\u3001\u30DD\u30FC\u30C8\u5909\u66F4\u306F\u65B0\u3057\u3044\u5168\u91CF\u914D\u5099\u304C\u5FC5\u8981\u3067\u3059\u3002.env.runtime \u306E\u7DE8\u96C6\u3068\u518D\u8D77\u52D5\u3067\u306F\u65B0\u30C9\u30E1\u30A4\u30F3\u306E\u8A3C\u660E\u66F8\u3092\u7533\u8ACB\u3057\u307E\u305B\u3093\u3002",
|
|
329
344
|
deploy_bundleAcme: "Certbot \u6C38\u7D9A\u72B6\u614B\uFF1A{state}\u3001\u73FE\u5728\u306E\u8A3C\u660E\u66F8\u5165\u53E3\uFF1A{state}/live/{domain}\u3002\u30D1\u30C3\u30B1\u30FC\u30B8\u6642\u306F CA \u306B\u63A5\u7D9A\u305B\u305A\u3001\u30B5\u30FC\u30D0\u30FC\u914D\u5099\u6642\u306B\u7533\u8ACB\u3057\u3001\u305D\u306E\u5F8C\u81EA\u52D5\u66F4\u65B0\u3057\u307E\u3059\u3002\u516C\u958B\u30DD\u30FC\u30C8 80 \u3068\u30EB\u30FC\u30C8 /.well-known/acme-challenge/ \u306F\u696D\u52D9 context path \u3068\u5225\u306B\u5230\u9054\u53EF\u80FD\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
330
345
|
deploy_bundleAccounts: "\u521D\u671F\u30A2\u30AB\u30A6\u30F3\u30C8\u5909\u6570\uFF08\u540D\u524D\u3068\u53D6\u5F97\u5143\u306E\u307F\u3001\u30D1\u30B9\u30EF\u30FC\u30C9\u975E\u8868\u793A\uFF09\uFF1A\n{sources}\n\u5BFE\u5FDC\u3059\u308B\u521D\u671F\u5316\u3092\u6301\u3064\u30A2\u30D7\u30EA\u3067\u306F HAI_CONFIG_ADMIN_PASSWORD \u304C config_admin \u8A2D\u5B9A\u7BA1\u7406\u8005\u3092\u4F5C\u6210\u3057\u307E\u3059\u3002HAI_ADMIN_DEFAULT_PASSWORD\u3001HAI_AUDIT_ADMIN_PASSWORD\u3001HAI_BUSINESS_OPERATOR_PASSWORD \u306F\u4ED6\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u5F79\u5272\u306B\u5BFE\u5FDC\u3057\u307E\u3059\u3002\nFullstack \u4F5C\u6210\u6642\u306B\u74B0\u5883\u3054\u3068\u306E\u72EC\u7ACB\u521D\u671F\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u751F\u6210\u3057\u3001\u914D\u5E03\u6642\u306F\u9078\u629E\u74B0\u5883\u3068\u30D7\u30ED\u30BB\u30B9\u4E0A\u66F8\u304D\u3092\u8AAD\u307F\u307E\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u914D\u5099\u3067\u65B0\u305F\u306B\u751F\u6210\u3057\u307E\u305B\u3093\u3002\u8A2D\u5B9A\u304C\u3042\u308B\u672A\u4F5C\u6210\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u8D77\u52D5\u6642\u306B\u4F5C\u308A\u3001\u65E2\u5B58\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3084\u5909\u66F4\u5F8C\u306E\u5F79\u5272\u306F\u5909\u6570\u5909\u66F4\u3067\u623B\u3057\u307E\u305B\u3093\u3002\u72EC\u81EA\u30A2\u30D7\u30EA\u306F\u5B9F\u88C5\u306B\u5F93\u3044\u307E\u3059\u3002",
|
|
331
|
-
deploy_bundleDirectories: "\u30B5\u30FC\u30D0\u30FC\
|
|
346
|
+
deploy_bundleDirectories: "\u30D5\u30A1\u30A4\u30EB\u7D22\u5F15\uFF08\u30B5\u30FC\u30D0\u30FC\u30D1\u30B9\u306F\u5B9F\u969B\u306E\u914D\u5099\u30EB\u30FC\u30C8\u57FA\u6E96\u3001\u65E2\u5B9A\u5024\u306F {directory}\uFF09\n\u4EA4\u4ED8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\u306E README.txt \u306F\u6982\u8981\u3067\u3059\u3002deploy.sh \u3068 deploy.ps1 \u306F SSH \u3067\u8EE2\u9001\u3057\u3066\u9069\u7528\u3057\u307E\u3059\u3002deploy-target.json \u306F\u63A5\u7D9A\u5148\u3001\u8A8D\u8A3C\u3001\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\u3092\u6307\u5B9A\u3057\u3001read-target.awk \u306F\u30B9\u30AF\u30EA\u30D7\u30C8\u7528\u306E\u8AAD\u307F\u53D6\u308A\u51E6\u7406\u3067\u3059\u3002deploy-local.sh \u306F\u30B5\u30FC\u30D0\u30FC\u4E0A\u3067\u5C55\u958B\u3057\u3066\u9069\u7528\u3057\u307E\u3059\u3002\n\u30A2\u30FC\u30AB\u30A4\u30D6\u306E APPLY.txt \u306F\u624B\u52D5\u64CD\u4F5C\u3068\u8A2D\u5B9A\u306E\u8AAC\u660E\u3067\u3059\u3002apply.sh \u306F\u691C\u8A3C\u3001\u30ED\u30C3\u30AF\u3001\u30A4\u30F3\u30DD\u30FC\u30C8\u3001\u8D77\u52D5\u3092\u5B9F\u884C\u3057\u307E\u3059\u3002manifest.json \u306F\u6210\u679C\u7269\u3001\u914D\u5099\u30E2\u30FC\u30C9\u3001\u5BFE\u8C61\u30B5\u30FC\u30D3\u30B9\u3001\u975E\u6A5F\u5BC6\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u8A18\u9332\u3057\u307E\u3059\u3002images/ \u306E OCI \u30A2\u30FC\u30AB\u30A4\u30D6\u3092\u30A8\u30F3\u30B8\u30F3\u306B\u53D6\u308A\u8FBC\u307F\u307E\u3059\u3002\n\u30A2\u30FC\u30AB\u30A4\u30D6\u306E .hai/compose.json \u306F\u9078\u629E\u3057\u305F\u30B5\u30FC\u30D3\u30B9\u3092\u542B\u307F\u3001\u914D\u5099\u5F8C\u306F\u7D71\u5408\u6E08\u307F\u306E\u5B8C\u5168\u306A\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306B\u306A\u308A\u307E\u3059\u3002.hai/SHA256SUMS \u306F\u5143\u306E\u5C55\u958B\u5185\u5BB9\u3092\u691C\u8A3C\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u5074\u306E\u30B3\u30D4\u30FC\u306F\u8A2D\u5B9A\u78BA\u5B9A\u3084\u7D71\u5408\u6642\u306B\u5909\u66F4\u3055\u308C\u307E\u3059\u3002\n.hai/middleware-runtime.env \u306F\u540C\u68B1\u30B3\u30F3\u30C6\u30CA\u30FC\u7528\u306E Compose env_file \u3067\u3059\u3002\u5FC5\u8981\u306A\u56FA\u6709\u5909\u6570\u304C\u306A\u3051\u308C\u3070\u7A7A\u306B\u306A\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\u3002\u7DAD\u6301\u3057\u305F\u30B5\u30FC\u30D3\u30B9\u304C\u53E4\u3044 release \u3092\u53C2\u7167\u3059\u308B\u5834\u5408\u306F\u3001\u6709\u52B9\u306A Compose \u306E env_file \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002apply.sh \u306F .hai/managed-candidates.env \u306E\u521D\u56DE\u7528\u5019\u88DC\u3092\u51E6\u7406\u3057\u307E\u3059\u3002\n.hai/runtime-env.mjs \u306F Node \u306E\u8A2D\u5B9A\u78BA\u5B9A\u3068\u8D77\u52D5\u6642\u306E\u8AAD\u307F\u8FBC\u307F\u3092\u62C5\u5F53\u3057\u307E\u3059\u3002.hai/request-access.yml\u3001.hai/web.conf\u3001\u30D7\u30ED\u30AD\u30B7\u30B9\u30AF\u30EA\u30D7\u30C8\u3001.hai/tls/ \u306F\u30A2\u30AF\u30BB\u30B9\u5236\u5FA1\u3001\u30EA\u30D0\u30FC\u30B9\u30D7\u30ED\u30AD\u30B7\u3001HTTPS \u7528\u306E\u4EFB\u610F\u30D5\u30A1\u30A4\u30EB\u3067\u3059\u3002\n\u30B5\u30FC\u30D0\u30FC\u306E incoming/ \u306F\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3068\u5C55\u958B\u5185\u5BB9\u3001releases/ \u306F\u914D\u5099\u3068\u5FA9\u65E7\u306E\u8A18\u9332\u3092\u4FDD\u6301\u3057\u307E\u3059\u3002managed-secrets.env\u3001persistent-backends\u3001\u30C7\u30FC\u30BF\u30DC\u30EA\u30E5\u30FC\u30E0\u306F\u4E00\u7DD2\u306B\u4FDD\u8B77\u3057\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3057\u307E\u3059\u3002.deploy.lock \u306F\u914D\u5099\u3068\u8CC7\u683C\u60C5\u5831\u64CD\u4F5C\u306E\u8ABF\u6574\u306B\u4F7F\u3044\u307E\u3059\u3002\n\u30B5\u30FC\u30D0\u30FC\u306E\u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF\u901A\u904E\u5F8C\u306B current \u3092\u66F4\u65B0\u3057\u307E\u3059\u3002result-{deploymentId}.json \u306F\u7D50\u679C\u3068\u5FA9\u65E7\u72B6\u614B\u3001steps-{deploymentId}.jsonl \u306F\u9032\u884C\u72B6\u6CC1\u3001diagnostics-{deploymentId}.log \u306F\u8D77\u52D5\u5931\u6557\u6642\u306E\u975E\u516C\u958B\u8A3A\u65AD\u3067\u3059\u3002\u53E4\u3044 release \u306E\u6574\u7406\u524D\u306B\u73FE\u5728\u306E Compose \u306E\u53C2\u7167\u3001\u30DE\u30A6\u30F3\u30C8\u3001\u5FA9\u65E7\u306E\u8981\u4EF6\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
332
347
|
deploy_downloadInvalid: "\u53D6\u5F97\u5143\u307E\u305F\u306F\u30D7\u30ED\u30AD\u30B7\u8A2D\u5B9A\u304C\u7121\u52B9\u3067\u3059\u3002URL \u306B\u8A8D\u8A3C\u60C5\u5831\u3084\u30AF\u30A8\u30EA\u3092\u542B\u3081\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
333
348
|
deploy_imageSourceMissing: "\u30AB\u30B9\u30BF\u30E0\u53D6\u5F97\u5143\u306B\u30EC\u30B8\u30B9\u30C8\u30EA\u30FC\u306E\u5BFE\u5FDC\u8868\u304C\u3042\u308A\u307E\u305B\u3093\uFF1A{registry}",
|
|
334
349
|
deploy_proxySystemUnsupported: "\u9759\u7684\u30B7\u30B9\u30C6\u30E0\u30D7\u30ED\u30AD\u30B7\u3092\u53D6\u5F97\u3067\u304D\u306A\u3044\u304B\u3001PAC\uFF0F\u81EA\u52D5\u691C\u51FA\u306E\u307F\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u74B0\u5883\u5909\u6570\u3092 inherit \u3059\u308B\u304B\u3001custom HTTP(S) URL \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
@@ -463,12 +478,15 @@ var zh_CN_default = {
|
|
|
463
478
|
deploy_requestAccessInvalid: "\u8BF7\u6C42\u8BBF\u95EE\u7B56\u7565\u914D\u7F6E\u65E0\u6548\uFF08{field}\uFF09\u3002\u8BF7\u68C0\u67E5\u5B57\u6BB5\u3001IP\u3001\u65F6\u533A\u53CA\u65F6\u95F4\u7A97\u53E3\uFF1B\u5982\u5F15\u7528\u6587\u4EF6\uFF0C\u8BF7\u786E\u8BA4\u6587\u4EF6\u53EF\u8BFB\u3001\u683C\u5F0F\u4E3A YAML \u4E14\u4E0D\u8D85\u8FC7 1 MiB\u3002\u4FEE\u6B63\u540E\u91CD\u65B0\u6253\u5305\u3002",
|
|
464
479
|
deploy_httpsPortsInvalid: "HTTP \u4E0E HTTPS \u7AEF\u53E3\u5FC5\u987B\u4E0D\u540C\uFF1BLet\u2019s Encrypt \u7684 HTTP-01 \u5165\u53E3\u5FC5\u987B\u4F7F\u7528\u5BBF\u4E3B\u673A 80 \u7AEF\u53E3\u3002",
|
|
465
480
|
deploy_httpsCertificateInvalid: "HTTPS \u8BC1\u4E66\u65E0\u6548\uFF1A\u8BF7\u6838\u5BF9 PEM \u6587\u4EF6\u53EF\u8BFB\u3001\u8BC1\u4E66\u4E0E\u672A\u52A0\u5BC6\u79C1\u94A5\u5339\u914D\u3001\u8BC1\u4E66\u6709\u6548\u671F\u53CA\u57DF\u540D\uFF0C\u7136\u540E\u91CD\u65B0\u6253\u5305\u3002",
|
|
466
|
-
deploy_bundleRuntime: "\
|
|
481
|
+
deploy_bundleRuntime: "\u914D\u7F6E\u6587\u4EF6\u4E0E\u751F\u6548\u65F6\u673A\n\u89E3\u5305\u76EE\u5F55 config/.env.runtime \u662F\u672C\u5305\u8F93\u5165\uFF0C\u5305\u542B\u5E94\u7528\u914D\u7F6E\u548C\u53EF\u80FD\u7684\u968F\u5305\u4E2D\u95F4\u4EF6\u5019\u9009\u3002\u4FEE\u6539\u9879\u76EE\u6E90\u73AF\u5883\u540E\u91CD\u65B0\u6253\u5305\u3002apply.sh \u4F1A\u6821\u9A8C\u5F52\u6863\u5185\u5BB9\u3002\n{directory}/config/.env.runtime \u662F\u5F53\u524D\u8FD0\u884C\u914D\u7F6E\u3002Serv \u548C SvelteKit SSR \u6BCF\u6B21\u542F\u52A8\u4ECE\u53EA\u8BFB\u6302\u8F7D\u7684 /run/hai/config/.env.runtime \u8BFB\u53D6\u3002\n\u8FD0\u884C\u6587\u4EF6\u6309 dotenv \u5B57\u9762\u8BED\u6CD5\u8BFB\u53D6\uFF0C\u5927\u5C0F\u4E0A\u9650\u4E3A 1 MiB\u3002\u7F3A\u5931\u3001\u4E0D\u53EF\u8BFB\u3001\u91CD\u590D\u8D4B\u503C\u6216\u8D85\u9650\u65F6\u4F1A\u5728\u5E94\u7528\u542F\u52A8\u524D\u62A5\u9519\u3002\n{directory}/releases/{deploymentId}/config/.env.runtime \u662F\u672C\u6B21\u53D1\u5E03\u8BB0\u5F55\u3002\u4EC5\u66F4\u65B0 Web \u6216\u4E2D\u95F4\u4EF6\u65F6\uFF0C\u8BB0\u5F55\u91C7\u7528\u5F53\u65F6\u7684\u5F53\u524D\u914D\u7F6E\u3002\u67E5\u5F53\u524D\u503C\u7528\u90E8\u7F72\u6839\u6587\u4EF6\uFF0C\u67E5\u67D0\u6B21\u53D1\u5E03\u7528\u5BF9\u5E94 release\u3002\n\u5168\u91CF\u91C7\u7528\u65B0\u5305\u914D\u7F6E\u5E76\u590D\u7528\u670D\u52A1\u5668\u53D7\u7BA1\u5BC6\u7801\u3002\u5305\u542B\u4E3B\u5E94\u7528\u7684\u589E\u91CF\u91C7\u7528\u65B0\u5305\u7684\u5916\u90E8\u8FDE\u63A5\u548C\u5E94\u7528\u914D\u7F6E\uFF0C\u5E76\u4FDD\u7559\u65E2\u6709\u53D7\u7BA1\u8FDE\u63A5\u3002\u672A\u9009\u4E3B\u5E94\u7528\u7684\u589E\u91CF\u4FDD\u7559\u5F53\u524D\u914D\u7F6E\u3002\u5916\u90E8\u548C\u53D7\u7BA1\u4E4B\u95F4\u7684\u5207\u6362\u9700\u8981\u5168\u91CF\u53D1\u5E03\u3002\n\u4E34\u65F6\u4FEE\u590D Node \u540E\u7AEF\u914D\u7F6E\u65F6\uFF0C\u5907\u4EFD\u540E\u4FEE\u6539\u90E8\u7F72\u6839\u7684\u8FD0\u884C\u6587\u4EF6\uFF0C\u518D docker restart <\u5BB9\u5668\u540D> \u6216 podman restart <\u5BB9\u5668\u540D>\uFF0C\u9A8C\u8BC1\u5065\u5EB7\u548C\u76F8\u5173\u4E1A\u52A1\u3002\u957F\u671F\u4FEE\u6539\u5199\u56DE\u9879\u76EE\u6E90\u73AF\u5883\uFF0C\u5426\u5219\u4E0B\u6B21\u5305\u542B\u540E\u7AEF\u7684\u53D1\u5E03\u53EF\u80FD\u8986\u76D6\u3002\u5BB9\u5668\u8FDB\u7A0B\u663E\u5F0F\u4F20\u5165\u7684\u540C\u540D HAI_* \u4F18\u5148\u3002\n\u9759\u6001 Web\u3001\u4E2D\u95F4\u4EF6\u539F\u751F\u73AF\u5883\u3001\u7AEF\u53E3\u548C\u6302\u8F7D\u3001Node \u542F\u52A8\u53C2\u6570\u3001Nginx \u8DEF\u7531\u548C\u9650\u989D\u3001HTTPS \u88C5\u914D\u5747\u5728\u90E8\u7F72\u65F6\u751F\u6548\u3002\u7F51\u7AD9 base \u53D8\u66F4\u8FD8\u9700\u91CD\u5EFA\u3002\n\u5931\u8D25\u6062\u590D\u5148\u8FD8\u539F\u5E94\u7528\u8FD0\u884C\u6587\u4EF6\uFF0C\u518D\u6062\u590D\u65E7\u670D\u52A1\u3002\u6570\u636E\u5E93\u4E2D\u5DF2\u6267\u884C\u7684\u5BC6\u7801\u6216\u6570\u636E\u53D8\u66F4\u987B\u7531\u6570\u636E\u5E93\u7EF4\u62A4\u6D41\u7A0B\u5904\u7406\u3002",
|
|
482
|
+
deploy_refreshCookieSecureInvalid: "HAI_SERV_REFRESH_COOKIE_SECURE \u53EA\u63A5\u53D7 true\u3001false \u6216\u7A7A\u503C\u3002\u8BF7\u68C0\u67E5\u6240\u9009\u90E8\u7F72\u73AF\u5883\u53CA\u6253\u5305\u8FDB\u7A0B\u4E2D\u7684\u540C\u540D\u53D8\u91CF\u3002",
|
|
483
|
+
deploy_postgresPasswordConflict: "\u5916\u90E8 PostgreSQL \u7684 HAI_DB_URL\uFF08\u6216 HAI_DB.url\uFF09\u4E0E HAI_DB_PASSWORD\uFF08\u6216 HAI_DB.password\uFF09\u5BC6\u7801\u4E0D\u4E00\u81F4\u3002\u8BF7\u4F7F\u7528\u5B8C\u6574\u8FDE\u63A5\u4E32\u6216\u5206\u5B57\u6BB5\u914D\u7F6E\u3002",
|
|
484
|
+
deploy_bundleVariables: "\u73AF\u5883\u53D8\u91CF\u4E0E\u6392\u67E5\uFF08\u53EA\u5217\u540D\u79F0\uFF09\n\u6240\u9009\u73AF\u5883\u4E3A {environment}\u3002\u6253\u5305\u8F93\u5165\u4ECE\u9AD8\u5230\u4F4E\u4E3A\u6253\u5305\u8FDB\u7A0B\u3001.env.{environment}.local\u3001.env.local\u3001.env.{environment}\u3001.env\uFF0C\u7136\u540E\u662F\u5E94\u7528 YAML \u9ED8\u8BA4\u503C\u3002--env-dir \u9009\u62E9\u73AF\u5883\u6587\u4EF6\u76EE\u5F55\u3002\u540C\u6E90\u7EC6\u9879\u8986\u76D6\u7236 JSON\uFF0C\u8F83\u9AD8\u6765\u6E90\u7684\u7236 JSON \u66FF\u6362\u65E7\u7ED3\u6784\u7EC6\u9879\u3002\n\u672C\u5305 config/.env.runtime \u4E2D\u7684\u53D8\u91CF\u540D\uFF08--plan \u5217\u7684\u662F\u6E90\u73AF\u5883\u8F93\u5165\u952E\uFF09\uFF1A{keys}\nHAI_SERV_REFRESH_COOKIE_SECURE \u662F\u72EC\u7ACB\u8FDB\u7A0B\u5F00\u5173\uFF0C\u53EA\u7531\u540C\u540D\u53D8\u91CF\u8986\u76D6\u3002true \u542F\u7528 Secure\uFF0Cfalse \u4EC5\u7528\u4E8E\u53D7\u63A7\u5185\u7F51\u6216 VPN \u7684 HTTP \u5165\u53E3\uFF0C\u7A7A\u503C\u6216\u672A\u8BBE\u7F6E\u4F7F\u7528 Serv \u73AF\u5883\u9ED8\u8BA4\u7B56\u7565\uFF08\u751F\u4EA7\u5F00\u542F\uFF09\u3002HTTP \u5165\u53E3\u4ECD\u9700\u8BBE\u7F6E\u5B9E\u9645 HAI_SERV_CORS_ORIGIN\u3002\u90E8\u7F72\u540E\u786E\u8BA4\u767B\u5F55\u548C\u5237\u65B0\u3002\n\u793A\u4F8B\uFF1A\u5728\u53D7\u63A7 HTTP \u73AF\u5883\u7684 .env.{environment}.local \u4E2D\u5199 HAI_SERV_REFRESH_COOKIE_SECURE=false\uFF0C\u5E76\u8BBE\u7F6E\u5B9E\u9645\u7684 CORS Origin\u3002\u5DF2\u6709\u6210\u529F\u5168\u91CF\u548C serv \u955C\u50CF\u5236\u54C1\u65F6\uFF0C\u53EF\u5728\u9879\u76EE\u76EE\u5F55\u6267\u884C pnpm run deploy --env {environment} --bundle-only --yes --services serv\uFF0C\u7136\u540E\u5728\u670D\u52A1\u5668\u89E3\u5305\u5E76\u6267\u884C sh ./apply.sh\u3002\n\u5916\u90E8 PostgreSQL \u4F7F\u7528 HAI_DB_URL\uFF08\u5B8C\u6574\u8FDE\u63A5\u4E32\uFF0C\u542B\u6240\u9700\u8BA4\u8BC1\uFF09\u6216 HAI_DB_HOST\u3001HAI_DB_PORT\u3001HAI_DB_USER\u3001HAI_DB_DATABASE\u3001HAI_DB_PASSWORD\u3002URL \u4F1A\u4F18\u5148\uFF0C\u6539\u5BC6\u65F6\u66F4\u65B0\u751F\u6548\u7684\u914D\u7F6E\u65B9\u5F0F\u3002\u6570\u636E\u5E93\u8D26\u53F7\u548C\u6E90\u73AF\u5883\u6539\u597D\u540E\uFF0C\u91CD\u65B0\u53D1\u5E03 serv \u6216\u5168\u91CF\u53D1\u5E03\u3002\nHAI_CACHE_*\u3001HAI_STORAGE_*\u3001HAI_VECDB_* \u548C HAI_IAM_LDAP_* \u662F\u5E94\u7528\u8FDE\u63A5\u3002S3 \u5730\u5740\u4E0E\u8BBF\u95EE\u5BC6\u94A5\u5206\u522B\u914D\u7F6E\u3002\u5916\u90E8\u6216\u4E91\u5F00\u901A\u7684\u670D\u52A1\u7531\u5E94\u7528\u8FDE\u63A5\uFF0C\u901A\u5E38\u65E0\u672C\u5305\u7684\u955C\u50CF\u539F\u751F\u53D8\u91CF\u3002\n\u968F\u5305 PostgreSQL \u4ECE managed-secrets.env \u7684 DB_PASSWORD \u751F\u6210\u5E94\u7528\u8FDE\u63A5 HAI_DB_URL \u548C\u539F\u751F POSTGRES_PASSWORD\u3002POSTGRES_PASSWORD \u7528\u4E8E\u521D\u59CB\u5316\u7A7A\u6570\u636E\u76EE\u5F55\u3002\u5176\u4ED6\u968F\u5305\u955C\u50CF\u53EF\u80FD\u4F7F\u7528 MYSQL_*\u3001RUSTFS_*\u3001MINIO_* \u6216 LDAP_*\u3002\u5DF2\u6709\u5377\u7684\u8D26\u53F7\u8F6E\u6362\u9700\u8981\u540C\u6B65\u5B9E\u9645\u8D26\u53F7\u548C\u53D7\u7BA1\u72B6\u6001\u3002\u4EC5\u91CD\u542F\u6216\u91CD\u5EFA\u5BB9\u5668\u65E0\u6CD5\u5B8C\u6210\u6570\u636E\u5E93\u6362\u5BC6\u3002\nNODE_ENV \u5F71\u54CD\u5E94\u7528\u73AF\u5883\u3002HOST\u3001PORT \u548C HAI_SERV_SERVER_* \u7684\u76D1\u542C\u5730\u5740/\u7AEF\u53E3\u7531\u4EA4\u4ED8\u62D3\u6251\u5B9A\u7A3F\u3002NODE_OPTIONS \u548C HAI_DEPLOY_PRIVATE_PROXY \u5C5E\u4E8E\u5BB9\u5668\u88C5\u914D\u3002HAI_DEPLOY_PROVIDER_SSH_PASSWORD \u7531\u4E0A\u4F20\u7AEF\u7528\u4E8E SSH\uFF0C\u4E0E\u5E94\u7528\u8FDE\u63A5\u5206\u5F00\u3002\n\u5F52\u6863\u3001\u8FD0\u884C\u6587\u4EF6\u3001\u51ED\u636E\u3001\u79C1\u94A5\u548C\u6545\u969C\u65E5\u5FD7\u6309\u79C1\u6709\u8D44\u6599\u4FDD\u7BA1\u3002\u6392\u67E5\u6216\u4EA4\u7ED9 AI \u65F6\u53EA\u63D0\u4F9B\u53D8\u91CF\u540D\u3001\u6765\u6E90\u3001\u8131\u654F\u9519\u8BEF\u548C\u90E8\u7F72 ID\u3002",
|
|
467
485
|
deploy_bundleHttpOnly: "HTTPS\uFF1A\u672A\u542F\u7528\u3002\u672C\u5305\u4EC5\u53D1\u5E03 HTTP \u7AEF\u53E3 {port}\uFF0C\u6CA1\u6709\u8BC1\u4E66\u9644\u4EF6\uFF0C\u4E5F\u4E0D\u4F1A\u5728\u670D\u52A1\u5668\u7533\u8BF7\u8BC1\u4E66\u3002",
|
|
468
486
|
deploy_bundleHttps: "HTTPS\uFF1A\u5DF2\u542F\u7528\uFF0Chttps://{domain}:{port}\uFF1B\u6A21\u5F0F {mode}\u3002\n\u670D\u52A1\u5668\u8BC1\u4E66\uFF1A{certificates}/fullchain.pem\uFF1B\u79C1\u94A5\uFF1A{certificates}/privkey.pem\u3002\u5BB9\u5668\u53EA\u8BFB\u6302\u8F7D\u5230 /etc/nginx/tls/\u3002\n\u4FEE\u6539\u672C\u5730\u6253\u5305\u73AF\u5883 .env.{environment}.local \u7684 HAI_DEPLOY_PROVIDER \u4E2D expose.https\uFF0C\u6216\u672A\u88AB\u8986\u76D6\u7684 hai.json.deploy.provider.expose.https\u3002\u542F\u505C\u3001\u5207\u6362\u6A21\u5F0F/\u57DF\u540D/\u7AEF\u53E3\u540E\u751F\u6210\u65B0\u7684\u5168\u91CF\u90E8\u7F72\u5305\uFF1B\u4FEE\u6539 .env.runtime \u5E76\u91CD\u542F\u4E0D\u80FD\u89E6\u53D1\u65B0\u57DF\u540D\u7B7E\u53D1\u3002",
|
|
469
487
|
deploy_bundleAcme: "Certbot \u6301\u4E45\u72B6\u6001\uFF1A{state}\uFF1B\u5F53\u524D\u8BC1\u4E66\u5165\u53E3\uFF1A{state}/live/{domain}\u3002\u6253\u5305\u4E0D\u8BF7\u6C42 CA\uFF0C\u670D\u52A1\u5668\u90E8\u7F72\u65F6\u7533\u8BF7\uFF0C\u4E4B\u540E\u81EA\u52A8\u7EED\u671F\u3002\u516C\u7F51 80 \u7AEF\u53E3\u53CA\u6839\u8DEF\u5F84 /.well-known/acme-challenge/ \u5FC5\u987B\u53EF\u8FBE\uFF0C\u4E0D\u80FD\u53EA\u5141\u8BB8\u4E1A\u52A1 context path\u3002",
|
|
470
488
|
deploy_bundleAccounts: "\u521D\u59CB\u8D26\u53F7\u53D8\u91CF\uFF08\u53EA\u5217\u540D\u79F0\u548C\u6765\u6E90\uFF0C\u4E0D\u663E\u793A\u5BC6\u7801\uFF09\uFF1A\n{sources}\nHAI_CONFIG_ADMIN_PASSWORD \u4F9B\u6709\u76F8\u5E94\u5F15\u5BFC\u903B\u8F91\u7684\u5E94\u7528\u521B\u5EFA config_admin \u914D\u7F6E\u7BA1\u7406\u5458\uFF1BHAI_ADMIN_DEFAULT_PASSWORD\u3001HAI_AUDIT_ADMIN_PASSWORD\u3001HAI_BUSINESS_OPERATOR_PASSWORD \u5BF9\u5E94\u5176\u4ED6\u6A21\u677F\u804C\u8D23\u8D26\u53F7\u3002\nCLI \u521B\u5EFA Fullstack \u65F6\u4E3A\u5404\u73AF\u5883\u751F\u6210\u72EC\u7ACB\u521D\u59CB\u5BC6\u7801\uFF1B\u6253\u5305\u8BFB\u53D6\u6240\u9009\u73AF\u5883\u4E0E\u8FDB\u7A0B\u8986\u76D6\uFF0C\u4E0D\u4F1A\u56E0\u670D\u52A1\u5668\u90E8\u7F72\u518D\u751F\u6210\u5E94\u7528\u8D26\u53F7\u5BC6\u7801\u3002\u6709\u914D\u7F6E\u4E14\u8D26\u53F7\u7F3A\u5931\u65F6\u7531\u5E94\u7528\u542F\u52A8\u5F15\u5BFC\uFF1B\u5DF2\u6709\u8D26\u53F7\u4E0D\u4F1A\u56E0\u4FEE\u6539\u53D8\u91CF\u91CD\u7F6E\u5BC6\u7801\u6216\u6062\u590D\u65E7\u804C\u8D23\u3002\u65E0\u76F8\u5E94\u5F15\u5BFC\u903B\u8F91\u7684\u81EA\u5B9A\u4E49\u5E94\u7528\u4EE5\u81EA\u8EAB\u5B9E\u73B0\u4E3A\u51C6\u3002",
|
|
471
|
-
deploy_bundleDirectories: "\u670D\u52A1\u5668\
|
|
489
|
+
deploy_bundleDirectories: "\u6587\u4EF6\u7D22\u5F15\uFF08\u670D\u52A1\u5668\u8DEF\u5F84\u4EE5\u5B9E\u9645\u90E8\u7F72\u6839\u4E3A\u51C6\uFF0C\u9ED8\u8BA4 {directory}\uFF09\n\u4EA4\u4ED8\u76EE\u5F55 README.txt \u63D0\u4F9B\u603B\u89C8\u3002deploy.sh \u548C deploy.ps1 \u901A\u8FC7 SSH \u4F20\u8F93\u5E76\u6267\u884C\u3002deploy-target.json \u9009\u62E9\u76EE\u6807\u3001\u9274\u6743\u548C\u76EE\u5F55\uFF0Cread-target.awk \u4F9B\u811A\u672C\u8BFB\u53D6\u914D\u7F6E\u3002deploy-local.sh \u5728\u670D\u52A1\u5668\u672C\u5730\u89E3\u5305\u5E76\u6267\u884C\u3002\n\u5F52\u6863\u5185 APPLY.txt \u662F\u624B\u5DE5\u64CD\u4F5C\u548C\u914D\u7F6E\u8BF4\u660E\u3002apply.sh \u6821\u9A8C\u3001\u52A0\u9501\u3001\u5BFC\u5165\u5E76\u542F\u52A8\u3002manifest.json \u8BB0\u5F55\u5236\u54C1\u3001\u6A21\u5F0F\u3001\u9009\u4E2D\u670D\u52A1\u53CA\u975E\u654F\u611F\u5143\u6570\u636E\u3002images/ \u662F OCI \u955C\u50CF\u5F52\u6863\uFF0C\u5BFC\u5165\u540E\u955C\u50CF\u7531\u5F15\u64CE\u4FDD\u5B58\u3002\n\u5F52\u6863\u5185 .hai/compose.json \u8BB0\u5F55\u6240\u9009\u670D\u52A1\uFF0C\u5B89\u88C5\u540E\u7684\u540C\u540D\u6587\u4EF6\u662F\u5408\u5E76\u540E\u7684\u5B8C\u6574\u670D\u52A1\u5FEB\u7167\u3002.hai/SHA256SUMS \u7528\u4E8E\u6821\u9A8C\u539F\u59CB\u89E3\u5305\u5185\u5BB9\u3002\u670D\u52A1\u5668\u526F\u672C\u4F1A\u5728\u5B9A\u7A3F\u548C\u5408\u5E76\u65F6\u6539\u53D8\u3002\n.hai/middleware-runtime.env \u53EA\u4F9B\u968F\u5305\u4E2D\u95F4\u4EF6\u7684 Compose env_file \u4F7F\u7528\u3002\u65E0\u539F\u751F\u73AF\u5883\u65F6\u53EF\u4EE5\u4E3A\u7A7A\u3002\u589E\u91CF\u4FDD\u7559\u7684\u670D\u52A1\u53EF\u80FD\u5F15\u7528\u66F4\u65E9\u7684 release\uFF0C\u4EE5\u6709\u6548 Compose \u7684 env_file \u4E3A\u51C6\u3002.hai/managed-candidates.env \u662F\u9996\u6B21\u5B89\u88C5\u5019\u9009\uFF0C\u7531 apply.sh \u6D88\u8D39\u3002\n.hai/runtime-env.mjs \u662F Node \u542F\u52A8\u52A0\u8F7D\u5668\u548C\u914D\u7F6E\u5B9A\u7A3F\u811A\u672C\u3002\u6309\u9700\u5305\u542B .hai/request-access.yml\u3001.hai/web.conf\u3001\u4EE3\u7406\u811A\u672C\u548C .hai/tls/ \u7B49\u8BBF\u95EE\u7B56\u7565\u3001\u53CD\u5411\u4EE3\u7406\u548C HTTPS \u8D44\u4EA7\u3002\n\u670D\u52A1\u5668 incoming/ \u4FDD\u5B58\u672C\u6B21\u4E0A\u4F20\u548C\u89E3\u5305\u5185\u5BB9\u3002releases/ \u4FDD\u5B58\u53D1\u5E03\u4E0E\u6062\u590D\u8BB0\u5F55\u3002managed-secrets.env\u3001persistent-backends \u548C\u6570\u636E\u5377\u6210\u5957\u4FDD\u62A4\u4E0E\u5907\u4EFD\uFF0C.deploy.lock \u4F9B\u90E8\u7F72\u548C\u51ED\u636E\u64CD\u4F5C\u534F\u8C03\u3002\ncurrent \u5728\u670D\u52A1\u5668\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7\u540E\u66F4\u65B0\u3002result-{deploymentId}.json \u8BB0\u5F55\u7ED3\u679C\u548C\u6062\u590D\u72B6\u6001\uFF0Csteps-{deploymentId}.jsonl \u8BB0\u5F55\u6B65\u9AA4\uFF0Cdiagnostics-{deploymentId}.log \u5728\u542F\u52A8\u5931\u8D25\u65F6\u63D0\u4F9B\u79C1\u6709\u8BCA\u65AD\u3002\u6E05\u7406\u65E7 release \u524D\u6838\u5BF9\u5F53\u524D Compose\u3001\u6D3B\u52A8\u6302\u8F7D\u4E0E\u6062\u590D\u9700\u8981\u3002",
|
|
472
490
|
deploy_downloadInvalid: "\u4E0B\u8F7D\u6E90\u6216\u4EE3\u7406\u914D\u7F6E\u65E0\u6548\uFF0C\u5730\u5740\u4E0D\u80FD\u5305\u542B\u8BA4\u8BC1\u4FE1\u606F\u6216\u67E5\u8BE2\u53C2\u6570\u3002",
|
|
473
491
|
deploy_imageSourceMissing: "\u81EA\u5B9A\u4E49\u955C\u50CF\u6E90\u7F3A\u5C11\u4ED3\u5E93\u6620\u5C04\uFF1A{registry}",
|
|
474
492
|
deploy_proxySystemUnsupported: "\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u7CFB\u7EDF\u7684\u9759\u6001\u4EE3\u7406\uFF0C\u6216\u7CFB\u7EDF\u4EC5\u63D0\u4F9B PAC/\u81EA\u52A8\u53D1\u73B0\u3002\u8BF7\u4F7F\u7528 inherit \u73AF\u5883\u53D8\u91CF\u6216 custom HTTP(S) \u5730\u5740\u3002",
|
|
@@ -2474,6 +2492,18 @@ var deploy_config_shapes_default = {
|
|
|
2474
2492
|
type: "string",
|
|
2475
2493
|
pattern: "^[A-Z_]\\w*$"
|
|
2476
2494
|
}
|
|
2495
|
+
},
|
|
2496
|
+
gitEnvironmentRefs: {
|
|
2497
|
+
default: {},
|
|
2498
|
+
type: "object",
|
|
2499
|
+
propertyNames: {
|
|
2500
|
+
type: "string",
|
|
2501
|
+
pattern: "^[A-Z_]\\w*$"
|
|
2502
|
+
},
|
|
2503
|
+
additionalProperties: {
|
|
2504
|
+
type: "string",
|
|
2505
|
+
pattern: "^[A-Z_]\\w*$"
|
|
2506
|
+
}
|
|
2477
2507
|
}
|
|
2478
2508
|
},
|
|
2479
2509
|
required: [
|
|
@@ -6221,6 +6251,8 @@ function generatedVariables(values) {
|
|
|
6221
6251
|
continue;
|
|
6222
6252
|
const text = typeof value === "string" ? value : value === null || typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
6223
6253
|
generated[name] = text;
|
|
6254
|
+
if (name === "HAI_SERV_REFRESH_COOKIE_SECURE")
|
|
6255
|
+
continue;
|
|
6224
6256
|
const module = /^HAI_([A-Z0-9]+)(?:_|$)/.exec(name)?.[1]?.toLowerCase();
|
|
6225
6257
|
if (!module || !shapes[module])
|
|
6226
6258
|
continue;
|
|
@@ -7106,7 +7138,7 @@ deployment_metadata_init() {
|
|
|
7106
7138
|
deployment_metadata_file() {
|
|
7107
7139
|
metadata_directory=$1
|
|
7108
7140
|
metadata_name=$2
|
|
7109
|
-
case "$metadata_name" in layout|health-paths|image-list|dependencies|managed-project|managed-bindings|managed-volumes|managed-app-keys|state-backends|storage-routing|web-base-path|node-runtime|proxy-service|https) ;; *) printf 'Unknown deployment metadata field.\n' >&2; return 1;; esac
|
|
7141
|
+
case "$metadata_name" in layout|health-paths|image-list|dependencies|managed-project|managed-bindings|managed-volumes|managed-app-keys|unmanaged-app-keys|state-backends|storage-routing|web-base-path|node-runtime|proxy-service|https) ;; *) printf 'Unknown deployment metadata field.\n' >&2; return 1;; esac
|
|
7110
7142
|
test -f "$metadata_directory/manifest.json" && test ! -L "$metadata_directory/manifest.json" || return 1
|
|
7111
7143
|
metadata_identity=$(printf '%s' "$metadata_directory" | sha256sum | awk '{print $1}')
|
|
7112
7144
|
metadata_cached="$metadata_work/$metadata_identity-$metadata_name"
|
|
@@ -8725,6 +8757,23 @@ fi
|
|
|
8725
8757
|
resolve_backend_state "$root" "$source_dir" "$runtime" "$previous" check
|
|
8726
8758
|
if [ "$partial" = true ]; then
|
|
8727
8759
|
test -n "$previous" || { printf 'Partial deployment requires a successful full installation. Deploy a complete bundle first.\n' >&2; exit 1; }
|
|
8760
|
+
# 比较完整连接计划,而不是增量 Compose 中携带的服务子集。
|
|
8761
|
+
case " $selected " in
|
|
8762
|
+
*' @@PRIMARY@@ '*)
|
|
8763
|
+
installed_keys=$(deployment_metadata_file "$root/releases/$previous" managed-app-keys)
|
|
8764
|
+
incoming_keys=$(deployment_metadata_file "$source_dir" managed-app-keys)
|
|
8765
|
+
unmanaged_keys=$(deployment_metadata_file "$source_dir" unmanaged-app-keys)
|
|
8766
|
+
if ! LC_ALL=C awk '
|
|
8767
|
+
!NF {next}
|
|
8768
|
+
FILENAME == ARGV[1] {installed[$0]=1; next}
|
|
8769
|
+
FILENAME == ARGV[2] {if (!($0 in installed)) exit 1; next}
|
|
8770
|
+
$0 in installed {exit 1}
|
|
8771
|
+
' "$installed_keys" "$incoming_keys" "$unmanaged_keys"; then
|
|
8772
|
+
printf 'Managed middleware connections changed. Use a full deployment to switch between bundled and external middleware.\n' >&2
|
|
8773
|
+
exit 1
|
|
8774
|
+
fi
|
|
8775
|
+
;;
|
|
8776
|
+
esac
|
|
8728
8777
|
# 目录属于完整Web拓扑;旧版本缺省为根目录,服务增量不能意外丢失或改变既有目录。
|
|
8729
8778
|
current_web_base=$(deployment_json read metadata.web-base-path string "$source_dir/manifest.json")
|
|
8730
8779
|
previous_web_base=$(deployment_json read metadata.web-base-path string "$root/releases/$previous/manifest.json")
|
|
@@ -9510,8 +9559,10 @@ async function createDeploymentBundle(options) {
|
|
|
9510
9559
|
files.push(`images/${file}`);
|
|
9511
9560
|
imageList.push(`${file} ${reference}`);
|
|
9512
9561
|
}
|
|
9513
|
-
|
|
9514
|
-
|
|
9562
|
+
const applicationEnvironment = readFileSync(join(directory, ".env.runtime"), "utf8");
|
|
9563
|
+
put("config/.env.runtime", applicationEnvironment);
|
|
9564
|
+
const updatesApp = selected.includes(artifact.primaryService);
|
|
9565
|
+
if (updatesApp && existsSync(join(directory, "request-access.yml")))
|
|
9515
9566
|
put(".hai/request-access.yml", readFileSync(join(directory, "request-access.yml"), "utf8"));
|
|
9516
9567
|
if (nodeRuntime)
|
|
9517
9568
|
put(".hai/runtime-env.mjs", readFileSync(new URL("./deploy-runtime-env.mjs", import.meta.url), "utf8"));
|
|
@@ -9547,10 +9598,13 @@ async function createDeploymentBundle(options) {
|
|
|
9547
9598
|
"proxy-service": options.hasWebConfig ? options.proxyService ?? "web" : "",
|
|
9548
9599
|
"https": options.httpsAssets?.https ?? "",
|
|
9549
9600
|
"managed-project": managed["managed-project"],
|
|
9550
|
-
|
|
9601
|
+
// 未选应用时只带容器原生绑定,保持当前发布的应用连接归属。
|
|
9602
|
+
"managed-bindings": updatesApp ? managed["managed-bindings"] : managed["managed-bindings"].replace(/^.* prefix\n/gm, ""),
|
|
9551
9603
|
"managed-volumes": managed["managed-volumes"],
|
|
9552
|
-
"managed-app-keys": `${[...new Set(options.managedAppKeys)].join("\n")}
|
|
9553
|
-
|
|
9604
|
+
"managed-app-keys": updatesApp ? `${[...new Set(options.managedAppKeys)].join("\n")}
|
|
9605
|
+
` : "\n",
|
|
9606
|
+
"unmanaged-app-keys": updatesApp ? `${[...new Set(options.unmanagedAppKeys)].join("\n")}
|
|
9607
|
+
` : "\n",
|
|
9554
9608
|
"state-backends": backend["state-backends"]
|
|
9555
9609
|
};
|
|
9556
9610
|
put("manifest.json", `${JSON.stringify({ ...artifact, bundleFormat: 2, images: artifact.images.filter((image) => references.has(image.imageRef)), deploymentId: options.deploymentId, selectedServices: selected, partial: options.partial, metadata }, null, 2)}
|
|
@@ -9563,12 +9617,13 @@ async function createDeploymentBundle(options) {
|
|
|
9563
9617
|
const instructions = `${selection}
|
|
9564
9618
|
${deployM("deploy_bundleInstructions", { params: instructionParams })}`;
|
|
9565
9619
|
const runtimeGuide = deployM("deploy_bundleRuntime", { params: { directory: serverDirectory, deploymentId: options.deploymentId } });
|
|
9620
|
+
const variableGuide = deployM("deploy_bundleVariables", { params: { environment, keys: Object.keys(core.config.parseEnv(applicationEnvironment)).sort().join(", ") || "\u2014" } });
|
|
9566
9621
|
const https = config.expose.https;
|
|
9567
9622
|
const certificates = https?.type === "files" ? `${serverDirectory}/releases/${options.deploymentId}/.hai/tls` : `${serverDirectory}/https/certificates/${https?.domain}`;
|
|
9568
9623
|
const httpsGuide = https ? deployM("deploy_bundleHttps", { params: { domain: https.domain, port: https.port, mode: https.type, certificates, environment } }) + (https.type === "letsencrypt" ? `
|
|
9569
9624
|
${deployM("deploy_bundleAcme", { params: { state: `${serverDirectory}/https/acme`, domain: https.domain } })}` : "") : deployM("deploy_bundleHttpOnly", { params: { port: config.expose.hostPort } });
|
|
9570
9625
|
const accountGuide = deployM("deploy_bundleAccounts", { params: { sources: options.accountSources || "\u2014" } });
|
|
9571
|
-
const guides = [runtimeGuide, httpsGuide, accountGuide, deployM("deploy_bundleDirectories", { params: { directory: serverDirectory, deploymentId: options.deploymentId } })].join("\n\n");
|
|
9626
|
+
const guides = [runtimeGuide, variableGuide, httpsGuide, accountGuide, deployM("deploy_bundleDirectories", { params: { directory: serverDirectory, deploymentId: options.deploymentId } })].join("\n\n");
|
|
9572
9627
|
const bundleMetadata = deployM("deploy_bundleMetadata", { params: { version: artifact.appVersion, buildId: artifact.buildId, deploymentId: options.deploymentId, compose: ".hai/compose.json" } });
|
|
9573
9628
|
const manualGuide = deployM("deploy_bundleApplyGuide", { params: { file: shellArgument(basename(output)), directory: serverDirectory, target: shellArgument(serverDirectory), runtime: config.remote.runtime, deploymentId: options.deploymentId } });
|
|
9574
9629
|
put("APPLY.txt", `${bundleMetadata}
|
|
@@ -9576,7 +9631,7 @@ ${selection}
|
|
|
9576
9631
|
|
|
9577
9632
|
${manualGuide}
|
|
9578
9633
|
|
|
9579
|
-
${
|
|
9634
|
+
${guides}
|
|
9580
9635
|
`);
|
|
9581
9636
|
const readme = `${bundleMetadata}
|
|
9582
9637
|
${instructions}
|
|
@@ -10560,6 +10615,21 @@ function createDockerSshProvider(config, container) {
|
|
|
10560
10615
|
if (gateway)
|
|
10561
10616
|
healthPaths.push("/_hai/gateway-health");
|
|
10562
10617
|
const updatesApp = options?.selectedServices ? options.selectedServices.includes(primaryService) : !!app;
|
|
10618
|
+
const cookieSecure = env.HAI_SERV_REFRESH_COOKIE_SECURE;
|
|
10619
|
+
if (updatesApp && cookieSecure && cookieSecure !== "true" && cookieSecure !== "false")
|
|
10620
|
+
return err(HaiDeployError.CONFIG_ERROR, deployM("deploy_refreshCookieSecureInvalid"));
|
|
10621
|
+
if (updatesApp && !sidecar.services.includes("db") && !provisionEnv.HAI_DB) {
|
|
10622
|
+
const database = scan.middlewares?.find((item) => item.service === "db" && item.backend === "postgresql")?.config;
|
|
10623
|
+
if (typeof database?.url === "string" && database.url && typeof database.password === "string" && database.password) {
|
|
10624
|
+
try {
|
|
10625
|
+
const url2 = new URL(database.url);
|
|
10626
|
+
const urlPassword = url2.searchParams.getAll("password").at(-1) || decodeURIComponent(url2.password);
|
|
10627
|
+
if (urlPassword !== database.password)
|
|
10628
|
+
return err(HaiDeployError.CONFIG_ERROR, deployM("deploy_postgresPasswordConflict"));
|
|
10629
|
+
} catch {
|
|
10630
|
+
}
|
|
10631
|
+
}
|
|
10632
|
+
}
|
|
10563
10633
|
const serverPath = join(appDir, "config", "_serv.yml");
|
|
10564
10634
|
const server = existsSync(serverPath) || hasWebProxy ? loadDeploymentConfig("serv", serverPath, env) : ok({});
|
|
10565
10635
|
if (!server.success)
|
|
@@ -10773,6 +10843,7 @@ function createDockerSshProvider(config, container) {
|
|
|
10773
10843
|
storageRouting,
|
|
10774
10844
|
containerPort,
|
|
10775
10845
|
managedAppKeys: Object.keys(sidecar.env),
|
|
10846
|
+
unmanagedAppKeys: scan.middlewares?.filter((item) => !Object.hasOwn(sidecar.env, item.envPrefix)).map((item) => item.envPrefix),
|
|
10776
10847
|
accountSources: describeDeploymentVariableSources(options?.envDir ?? scan.envDir ?? appDir, options?.environment ?? "prod", env, ["HAI_ADMIN_DEFAULT_PASSWORD", "HAI_AUDIT_ADMIN_PASSWORD", "HAI_CONFIG_ADMIN_PASSWORD", "HAI_BUSINESS_OPERATOR_PASSWORD"]),
|
|
10777
10848
|
healthPaths,
|
|
10778
10849
|
httpsAssets,
|