@h-ai/deploy 0.1.0-alpha.67 → 0.1.0-alpha.68
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 +28 -5
- package/README.ja.md +28 -5
- package/README.md +38 -15
- package/dist/index.d.ts +466 -61
- package/dist/index.js +930 -158
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,19 @@ import { z } from 'zod';
|
|
|
2
2
|
import * as _h_ai_core from '@h-ai/core';
|
|
3
3
|
import { HaiResult, HaiError } from '@h-ai/core';
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* 镜像制品清单,例如 `{ version: 3, appVersion: '1.2.3', buildId: '1.2.3-build1', partial: false, hasWeb: false, images: [...] }`。
|
|
7
|
+
* 清单格式版本为 3;完整产物必须包含 app,声明 hasWeb 时还须包含 web。结构验证不能代替真实归档校验。
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { readFile } from 'node:fs/promises'
|
|
11
|
+
* import { DeploymentArtifactSchema } from '@h-ai/deploy'
|
|
12
|
+
* const content = await readFile('.hai/build/docker/build-id/manifest.json', 'utf8')
|
|
13
|
+
* const parsed = DeploymentArtifactSchema.safeParse(JSON.parse(content))
|
|
14
|
+
* if (!parsed.success) throw new Error('Invalid artifact manifest')
|
|
15
|
+
* // Schema 只验证结构;文件路径与 SHA-256 核验使用 readDeploymentArtifact。
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
6
18
|
declare const DeploymentArtifactSchema: z.ZodObject<{
|
|
7
19
|
version: z.ZodLiteral<3>;
|
|
8
20
|
appVersion: z.ZodString;
|
|
@@ -22,23 +34,50 @@ declare const DeploymentArtifactSchema: z.ZodObject<{
|
|
|
22
34
|
containerPort: z.ZodOptional<z.ZodNumber>;
|
|
23
35
|
}, z.core.$strip>>;
|
|
24
36
|
}, z.core.$strip>;
|
|
25
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* 构建器与部署器共享的镜像交付结构;参见 DeploymentArtifactSchema 示例。
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import type { DeploymentArtifact } from '@h-ai/deploy'
|
|
42
|
+
* import { readDeploymentArtifact } from '@h-ai/deploy'
|
|
43
|
+
* const directory = '.hai/build/docker/build-id'
|
|
44
|
+
* const artifact = await readDeploymentArtifact(directory)
|
|
45
|
+
* const verified: DeploymentArtifact = artifact
|
|
46
|
+
* const references = verified.images.map(image => image.imageRef)
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
26
49
|
type DeploymentArtifact = z.infer<typeof DeploymentArtifactSchema>;
|
|
27
50
|
/**
|
|
28
51
|
* 流式计算制品校验和,避免将大镜像一次性读入内存。
|
|
29
|
-
* @
|
|
52
|
+
* @throws Error - 文件读取失败;返回真实 tar 内容的 SHA-256,不校验清单其它字段。
|
|
53
|
+
* @param file - 真实镜像归档文件路径。
|
|
54
|
+
* @returns 文件内容的 SHA-256 十六进制摘要。
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { artifactChecksum } from '@h-ai/deploy'
|
|
58
|
+
* const digest = await artifactChecksum('.hai/build/docker/build-id/app-1.0.0.tar')
|
|
59
|
+
* ```
|
|
30
60
|
*/
|
|
31
61
|
declare function artifactChecksum(file: string): Promise<string>;
|
|
32
62
|
/**
|
|
33
63
|
* 校验完整构建产物;缺失、损坏或非法清单均抛错,由部署边界转换为 HaiResult。
|
|
34
|
-
* @
|
|
64
|
+
* @throws Error - 清单、路径、镜像 tar 或摘要校验失败;不能用未验证的清单绕过本函数。
|
|
65
|
+
* @param directory - 包含已准备制品或部署文件的目录;具体见函数用途。
|
|
66
|
+
* @returns 已经验证的构建制品清单。
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* import { readDeploymentArtifact } from '@h-ai/deploy'
|
|
70
|
+
* const directory = '.hai/build/docker/build-id'
|
|
71
|
+
* const artifact = await readDeploymentArtifact(directory)
|
|
72
|
+
* const images = artifact.images.map(image => ({ name: image.name, imageRef: image.imageRef }))
|
|
73
|
+
* ```
|
|
35
74
|
*/
|
|
36
75
|
declare function readDeploymentArtifact(directory: string): Promise<DeploymentArtifact>;
|
|
37
76
|
|
|
38
77
|
/**
|
|
39
78
|
* @h-ai/deploy — 部署配置 Schema
|
|
40
79
|
*
|
|
41
|
-
*
|
|
80
|
+
* 本文件定义部署模块的 Zod Schema 和配置类型;错误定义位于 deploy-types.ts。
|
|
42
81
|
* @module deploy-config
|
|
43
82
|
*/
|
|
44
83
|
|
|
@@ -84,7 +123,17 @@ declare const DockerSshProviderConfigSchema: z.ZodObject<{
|
|
|
84
123
|
hostPort: z.ZodNumber;
|
|
85
124
|
}, z.core.$strip>;
|
|
86
125
|
}, z.core.$strip>;
|
|
87
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* 部署平台配置联合类型(后续可扩展更多平台)
|
|
128
|
+
* 按 type 区分 Vercel 与 docker-ssh;仅校验配置形状,不验证远端连通性或云凭据。
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* import { ProviderConfigSchema } from '@h-ai/deploy'
|
|
132
|
+
* const result = ProviderConfigSchema.safeParse({ type: 'docker-ssh', expose: { hostPort: 8080 } })
|
|
133
|
+
* if (!result.success) throw new Error('Invalid deployment provider')
|
|
134
|
+
* const provider = result.data
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
88
137
|
declare const ProviderConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
89
138
|
type: z.ZodLiteral<"vercel">;
|
|
90
139
|
token: z.ZodString;
|
|
@@ -113,13 +162,45 @@ declare const ProviderConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
113
162
|
hostPort: z.ZodNumber;
|
|
114
163
|
}, z.core.$strip>;
|
|
115
164
|
}, z.core.$strip>], "type">;
|
|
116
|
-
/**
|
|
165
|
+
/**
|
|
166
|
+
* SSH 连接配置(parse 后)
|
|
167
|
+
* 这是 Schema 解析后的类型,默认字段已必填;私钥路径可省略以使用 ssh-agent/默认密钥。
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* import type { SshConfig } from '@h-ai/deploy'
|
|
171
|
+
* const config: SshConfig = { host: 'deploy.example.net', username: 'deploy', port: 22, strictHostKeyChecking: true, connectTimeoutSeconds: 10 }
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
117
174
|
type SshConfig = z.infer<typeof SshConfigSchema>;
|
|
118
|
-
/**
|
|
175
|
+
/**
|
|
176
|
+
* 端口暴露配置(parse 后)
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* import type { PortExposeConfig } from '@h-ai/deploy'
|
|
180
|
+
* const ports: PortExposeConfig = { type: 'port', hostPort: 8080, containerPort: 3000 }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
119
183
|
type PortExposeConfig = z.infer<typeof PortExposeSchema>;
|
|
120
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* docker-ssh 部署平台配置(parse 后)
|
|
186
|
+
* SSH 可省略用于离线打包;真正在线发布必须提供 SSH 配置。
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* import type { DockerSshProviderConfig } from '@h-ai/deploy'
|
|
190
|
+
* const provider: DockerSshProviderConfig = { type: 'docker-ssh', remote: { baseDir: '/opt/hai/apps', runtime: 'auto' }, expose: { type: 'port', hostPort: 8080, containerPort: 3000 } }
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
121
193
|
type DockerSshProviderConfig = z.infer<typeof DockerSshProviderConfigSchema>;
|
|
122
|
-
/**
|
|
194
|
+
/**
|
|
195
|
+
* 部署模块完整配置 Schema
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* import { DeployConfigSchema } from '@h-ai/deploy'
|
|
199
|
+
* const parsed = DeployConfigSchema.safeParse({ environment: 'prod', provider: { type: 'docker-ssh', expose: { hostPort: 8080 } } })
|
|
200
|
+
* if (!parsed.success) throw new Error('Invalid deployment configuration')
|
|
201
|
+
* const baseDir = parsed.data.provider.type === 'docker-ssh' ? parsed.data.provider.remote.baseDir : undefined
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
123
204
|
declare const DeployConfigSchema: z.ZodObject<{
|
|
124
205
|
environment: z.ZodOptional<z.ZodString>;
|
|
125
206
|
provider: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -186,14 +267,36 @@ declare const DeployConfigSchema: z.ZodObject<{
|
|
|
186
267
|
}>>;
|
|
187
268
|
}, z.core.$strip>>;
|
|
188
269
|
}, z.core.$strip>;
|
|
189
|
-
/**
|
|
270
|
+
/**
|
|
271
|
+
* 部署配置类型(parse 后)
|
|
272
|
+
* @example
|
|
273
|
+
* ```ts
|
|
274
|
+
* import type { DeployConfig } from '@h-ai/deploy'
|
|
275
|
+
* const config: DeployConfig = { environment: 'prod', provider: { type: 'docker-ssh', remote: { baseDir: '/opt/hai/apps', runtime: 'auto' }, expose: { type: 'port', hostPort: 8080, containerPort: 3000 } } }
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
190
278
|
type DeployConfig = z.infer<typeof DeployConfigSchema>;
|
|
191
|
-
/**
|
|
279
|
+
/**
|
|
280
|
+
* 部署配置输入类型(用户输入)
|
|
281
|
+
* @example
|
|
282
|
+
* ```ts
|
|
283
|
+
* import type { DeployConfigInput } from '@h-ai/deploy'
|
|
284
|
+
* const input: DeployConfigInput = { provider: { type: 'docker-ssh', expose: { hostPort: 8080 } } } // 由 init 应用 remote 等默认值。
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
192
287
|
type DeployConfigInput = z.input<typeof DeployConfigSchema>;
|
|
193
288
|
|
|
194
289
|
/** 部署环境的加载和持久化;公开环境文件不保存真实凭据。 */
|
|
195
290
|
|
|
196
|
-
/**
|
|
291
|
+
/**
|
|
292
|
+
* 部署环境快照;例如 prod 的 targetValues 只来自 `.env.prod`,不包含基础/私有覆盖。
|
|
293
|
+
* @example
|
|
294
|
+
* ```ts
|
|
295
|
+
* import type { DeploymentEnvironment } from '@h-ai/deploy'
|
|
296
|
+
* const environment: DeploymentEnvironment = { environment: 'prod', envDir: '/workspace/shop', values: { HAI_DB_TYPE: 'postgresql' }, targetValues: { HAI_DB_TYPE: 'postgresql' } }
|
|
297
|
+
* // values 可能还含私有凭据,不能整体写入日志。
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
197
300
|
interface DeploymentEnvironment {
|
|
198
301
|
/** 文件模式(dev/test/prod 或其他合法模式名)。 */
|
|
199
302
|
environment: string;
|
|
@@ -211,17 +314,32 @@ interface DeploymentEnvironment {
|
|
|
211
314
|
* @param path - YAML 文件绝对路径
|
|
212
315
|
* @param values - 已加载的目标环境变量
|
|
213
316
|
* @returns 配置对象;解析错误已脱敏
|
|
214
|
-
* @example
|
|
317
|
+
* @example
|
|
318
|
+
* ```ts
|
|
319
|
+
* import { loadDeploymentConfig, loadDeploymentEnvironment } from '@h-ai/deploy'
|
|
320
|
+
* const environment = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
|
|
321
|
+
* if (!environment.success) throw new Error(environment.error.message)
|
|
322
|
+
* const config = loadDeploymentConfig('deploy', `${process.cwd()}/config/_deploy.yml`, environment.data.values)
|
|
323
|
+
* if (!config.success) throw new Error(config.error.message)
|
|
324
|
+
* // 返回对象仍需经 DeployConfigSchema 或 deploy.init 验证。
|
|
325
|
+
* ```
|
|
215
326
|
*/
|
|
216
327
|
declare function loadDeploymentConfig(name: string, path: string, values: Record<string, string | undefined>): HaiResult<Record<string, unknown>>;
|
|
217
328
|
/**
|
|
218
329
|
* 加载部署环境;指定环境文件缺失时返回错误并要求用户创建。
|
|
330
|
+
* 进程环境优先于 .env.local、目标环境文件、基础文件;targetValues 只记录目标文件显式项,不包含其它覆盖。
|
|
219
331
|
* @param options - 模式、环境目录与是否强制存在目标文件
|
|
220
332
|
* @param options.environment - dev/test/prod 或自定义模式
|
|
221
333
|
* @param options.envDir - 环境文件所在目录
|
|
222
334
|
* @param options.requireFile - 默认 true;扫描无显式环境时可只读取已有基础文件
|
|
223
335
|
* @returns 环境快照,可能包含私有值,不得直接输出
|
|
224
|
-
* @example
|
|
336
|
+
* @example
|
|
337
|
+
* ```ts
|
|
338
|
+
* import { loadDeploymentEnvironment } from '@h-ai/deploy'
|
|
339
|
+
* const loaded = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
|
|
340
|
+
* if (!loaded.success) throw new Error(loaded.error.message)
|
|
341
|
+
* const explicitlyConfigured = loaded.data.targetValues.HAI_DB_TYPE
|
|
342
|
+
* ```
|
|
225
343
|
*/
|
|
226
344
|
declare function loadDeploymentEnvironment(options: {
|
|
227
345
|
environment: string;
|
|
@@ -236,13 +354,32 @@ declare function loadDeploymentEnvironment(options: {
|
|
|
236
354
|
* @param options - private 为 true 时所有值只保存在本机;适用于 SSH 地址、端口及密钥路径
|
|
237
355
|
* @param options.private - 是否将全部值仅保存到 .env.local
|
|
238
356
|
* @returns 已保存的变量名或脱敏错误
|
|
239
|
-
* @example
|
|
240
|
-
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```ts
|
|
359
|
+
* import { loadDeploymentEnvironment, saveDeploymentEnvironment } from '@h-ai/deploy'
|
|
360
|
+
* const loaded = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
|
|
361
|
+
* if (!loaded.success) throw new Error(loaded.error.message)
|
|
362
|
+
* const saved = saveDeploymentEnvironment(loaded.data, { HAI_DB_HOST: 'db' })
|
|
363
|
+
* if (!saved.success) throw new Error(saved.error.message)
|
|
364
|
+
* // 密钥应以 { private: true } 写入被忽略的 .env.local,不能放公共环境文件。
|
|
365
|
+
* ```
|
|
241
366
|
*/
|
|
242
367
|
declare function saveDeploymentEnvironment(environment: DeploymentEnvironment, values: Record<string, string>, options?: {
|
|
243
368
|
private?: boolean;
|
|
244
369
|
}): HaiResult<string[]>;
|
|
245
370
|
|
|
371
|
+
/**
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```ts
|
|
375
|
+
* import { err } from '@h-ai/core'
|
|
376
|
+
* import { HaiDeployError } from '@h-ai/deploy'
|
|
377
|
+
* const result = err(HaiDeployError.CONFIG_ERROR, 'Invalid deployment configuration')
|
|
378
|
+
* if (!result.success && result.error.code === HaiDeployError.CONFIG_ERROR.code) {
|
|
379
|
+
* process.stderr.write(result.error.message + '\n')
|
|
380
|
+
* }
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
246
383
|
declare const HaiDeployError: {
|
|
247
384
|
readonly DEPLOY_FAILED: _h_ai_core.HaiErrorDef;
|
|
248
385
|
readonly PROJECT_CREATE_FAILED: _h_ai_core.HaiErrorDef;
|
|
@@ -265,15 +402,12 @@ declare const HaiDeployError: {
|
|
|
265
402
|
/**
|
|
266
403
|
* 部署错误接口
|
|
267
404
|
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
405
|
+
* 用于组合错误定义、消息与可选 cause 的描述对象;业务操作返回的 error 遵循 core.HaiError,请按 success 分支读取 code/message。
|
|
270
406
|
* @example
|
|
271
407
|
* ```ts
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
* // 根据 error.code 处理
|
|
276
|
-
* }
|
|
408
|
+
* import type { DeployError } from '@h-ai/deploy'
|
|
409
|
+
* import { HaiDeployError } from '@h-ai/deploy'
|
|
410
|
+
* const detail: DeployError = { def: HaiDeployError.DEPLOY_FAILED, message: 'Deployment failed' }
|
|
277
411
|
* ```
|
|
278
412
|
*/
|
|
279
413
|
interface DeployError {
|
|
@@ -284,18 +418,47 @@ interface DeployError {
|
|
|
284
418
|
/** 原始错误(可选) */
|
|
285
419
|
cause?: unknown;
|
|
286
420
|
}
|
|
287
|
-
/**
|
|
421
|
+
/**
|
|
422
|
+
* 基础设施服务类型
|
|
423
|
+
* @example
|
|
424
|
+
* ```ts
|
|
425
|
+
* import type { ServiceType } from '@h-ai/deploy'
|
|
426
|
+
* const service: ServiceType = 'db'
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
288
429
|
type ServiceType = 'db' | 'cache' | 'storage' | 'email' | 'sms' | 'vecdb' | 'ldap';
|
|
289
|
-
/**
|
|
430
|
+
/**
|
|
431
|
+
* 每项中间件的处理方式;keep 不修改配置,也不开通服务。
|
|
432
|
+
* @example
|
|
433
|
+
* ```ts
|
|
434
|
+
* import type { MiddlewareMode } from '@h-ai/deploy'
|
|
435
|
+
* const mode: MiddlewareMode = 'keep' // 复用已有服务,不修改连接配置或自动开通。
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
290
438
|
type MiddlewareMode = 'default' | 'custom' | 'keep';
|
|
291
|
-
/**
|
|
439
|
+
/**
|
|
440
|
+
* 扫描环境;例如 `{ environment: 'test', envDir: '/workspace/app' }`。
|
|
441
|
+
* @example
|
|
442
|
+
* ```ts
|
|
443
|
+
* import type { DeployScanOptions } from '@h-ai/deploy'
|
|
444
|
+
* const options: DeployScanOptions = { environment: 'prod', envDir: '/workspace/shop' }
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
292
447
|
interface DeployScanOptions {
|
|
293
448
|
/** 环境文件模式。 */
|
|
294
449
|
environment?: string;
|
|
295
450
|
/** 环境文件目录;默认自动定位到应用或 workspace 根。 */
|
|
296
451
|
envDir?: string;
|
|
297
452
|
}
|
|
298
|
-
/**
|
|
453
|
+
/**
|
|
454
|
+
* 依赖对应的中间件;例如 IAM 的 LDAP 位于 `iam.ldap`,可处于 disabled 状态。
|
|
455
|
+
* @example
|
|
456
|
+
* ```ts
|
|
457
|
+
* import type { MiddlewareRequirement } from '@h-ai/deploy'
|
|
458
|
+
* const requirement: MiddlewareRequirement = { service: 'db', backend: 'postgresql', source: '@h-ai/reldb', configName: 'db', configPath: [], envPrefix: 'HAI_DB', config: { host: 'db', database: 'shop' } }
|
|
459
|
+
* // config 可能含私有值;展示时只选择安全字段。
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
299
462
|
interface MiddlewareRequirement {
|
|
300
463
|
/** 中间件类别。 */
|
|
301
464
|
service: ServiceType;
|
|
@@ -316,6 +479,16 @@ interface MiddlewareRequirement {
|
|
|
316
479
|
* 应用扫描结果
|
|
317
480
|
*
|
|
318
481
|
* 由 scanner 分析应用目录后返回,描述应用的框架类型、依赖和部署需求。
|
|
482
|
+
* 扫描是文件系统能力,不依赖 init,也不代表远程服务已经连通。
|
|
483
|
+
* @example
|
|
484
|
+
* ```ts
|
|
485
|
+
* import type { ScanResult } from '@h-ai/deploy'
|
|
486
|
+
* import { deploy } from '@h-ai/deploy'
|
|
487
|
+
* const result = await deploy.scan(process.cwd(), { environment: 'prod' })
|
|
488
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
489
|
+
* const scan: ScanResult = result.data
|
|
490
|
+
* const services = scan.requiredServices
|
|
491
|
+
* ```
|
|
319
492
|
*/
|
|
320
493
|
interface ScanResult {
|
|
321
494
|
/** 调用者指定的部署目录,对应 lockfile 中的一个 importer。 */
|
|
@@ -343,6 +516,12 @@ interface ScanResult {
|
|
|
343
516
|
* 部署结果
|
|
344
517
|
*
|
|
345
518
|
* 包含部署后的访问 URL、状态和已设置的环境变量。
|
|
519
|
+
* @example
|
|
520
|
+
* ```ts
|
|
521
|
+
* import type { DeployResult } from '@h-ai/deploy'
|
|
522
|
+
* const packaged: DeployResult = { url: '', deploymentId: 'deploy-shop-001', status: 'packaged', bundlePath: '/workspace/shop/.hai/deploy/shop-1.0.0.tar', envVarsSet: [], provider: 'docker-ssh', healthCheck: 'skipped' }
|
|
523
|
+
* // packaged 只代表交付包生成;不将其展示为服务已上线。
|
|
524
|
+
* ```
|
|
346
525
|
*/
|
|
347
526
|
interface DeployResult {
|
|
348
527
|
/** 部署后的访问 URL */
|
|
@@ -366,6 +545,12 @@ interface DeployResult {
|
|
|
366
545
|
* 基础设施开通结果
|
|
367
546
|
*
|
|
368
547
|
* 由 Provisioner 开通服务后返回,包含要注入到部署平台的环境变量。
|
|
548
|
+
* @example
|
|
549
|
+
* ```ts
|
|
550
|
+
* import type { ProvisionResult } from '@h-ai/deploy'
|
|
551
|
+
* const reused: ProvisionResult = { resourceStatus: 'reused', serviceType: 'db', provisionerName: 'neon', envVars: { HAI_DB_TYPE: 'postgresql' }, resourceInfo: 'Existing shop database' }
|
|
552
|
+
* // envVars 可能含密码;不能直接输出。
|
|
553
|
+
* ```
|
|
369
554
|
*/
|
|
370
555
|
interface ProvisionResult {
|
|
371
556
|
/** 本次新建或复用;凭证型服务始终为 reused */
|
|
@@ -379,7 +564,15 @@ interface ProvisionResult {
|
|
|
379
564
|
/** 资源标识信息(如项目名、数据库名等),用于日志和展示 */
|
|
380
565
|
resourceInfo: string;
|
|
381
566
|
}
|
|
382
|
-
/**
|
|
567
|
+
/**
|
|
568
|
+
* 部署失败后的安全恢复信息,不含环境变量值或原始异常。
|
|
569
|
+
* @example
|
|
570
|
+
* ```ts
|
|
571
|
+
* import type { DeployRecoveryInfo } from '@h-ai/deploy'
|
|
572
|
+
* const recovery: DeployRecoveryInfo = { projectName: 'shop', stage: 'provision', resources: [{ serviceType: 'db', provisionerName: 'neon', resourceInfo: 'shop', resourceStatus: 'unknown' }] }
|
|
573
|
+
* // 先在供应商控制台核对 unknown 资源;避免重复创建计费资源。
|
|
574
|
+
* ```
|
|
575
|
+
*/
|
|
383
576
|
interface DeployRecoveryInfo {
|
|
384
577
|
projectName: string;
|
|
385
578
|
stage: string;
|
|
@@ -391,7 +584,40 @@ interface DeployRecoveryInfo {
|
|
|
391
584
|
resourceStatus: 'created' | 'reused' | 'unknown';
|
|
392
585
|
}>;
|
|
393
586
|
}
|
|
394
|
-
/**
|
|
587
|
+
/**
|
|
588
|
+
* 命令失败后的已核验执行状态;远端 finished 仅指部署脚本及恢复已完成,不代表容器停止。
|
|
589
|
+
* @example
|
|
590
|
+
* ```ts
|
|
591
|
+
* import type { DeployCommandState } from '@h-ai/deploy'
|
|
592
|
+
* const state: DeployCommandState = { reason: 'timeout', localTermination: 'confirmed', remoteExecution: 'unknown', deploymentId: 'deploy-shop-001', resultFile: '/opt/hai/apps/shop/results/deploy-shop-001' }
|
|
593
|
+
* if (state.remoteExecution === 'unknown') process.stderr.write('Verify the matching remote deployment result before retrying\n')
|
|
594
|
+
* ```
|
|
595
|
+
*/
|
|
596
|
+
interface DeployCommandState {
|
|
597
|
+
/** 失败触发原因。 */
|
|
598
|
+
reason: 'timeout' | 'output' | 'input' | 'spawn' | 'exit' | 'configuration';
|
|
599
|
+
/** 本地受管理树已全部退出、无法证明,或尚未启动。 */
|
|
600
|
+
localTermination: 'confirmed' | 'unknown' | 'not-started';
|
|
601
|
+
/** SSH 失败默认 unknown;读取匹配部署 ID 的完整终态结果后才为 finished。 */
|
|
602
|
+
remoteExecution?: 'unknown' | 'finished';
|
|
603
|
+
/** 本次不可变部署 ID,可与服务器结果核对。 */
|
|
604
|
+
deploymentId?: string;
|
|
605
|
+
/** 服务器端结果文件;无凭据。 */
|
|
606
|
+
resultFile?: string;
|
|
607
|
+
/** 匹配终态结果中的真实脚本退出码。 */
|
|
608
|
+
remoteExitCode?: number;
|
|
609
|
+
/** 匹配终态结果中的最后阶段。 */
|
|
610
|
+
remoteStage?: string;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* 部署选项
|
|
614
|
+
* 仅更新指定服务时仍受完整/部分制品与首次部署约束;bundleOnly 不触发 SSH。
|
|
615
|
+
* @example
|
|
616
|
+
* ```ts
|
|
617
|
+
* import type { DeployAppOptions } from '@h-ai/deploy'
|
|
618
|
+
* const options: DeployAppOptions = { environment: 'prod', bundleOnly: true, artifactDir: '.hai/build/docker/build-id', selectedServices: ['app'], output: '.hai/deploy/shop.tar' }
|
|
619
|
+
* ```
|
|
620
|
+
*/
|
|
395
621
|
interface DeployAppOptions {
|
|
396
622
|
/** 接收实际执行阶段,用于终端进度显示;不包含凭据或配置原文。 */
|
|
397
623
|
onProgress?: (stage: 'packaging' | 'preflight' | 'images' | 'dependencies' | 'start' | 'health' | 'complete') => void;
|
|
@@ -420,15 +646,58 @@ interface DeployAppOptions {
|
|
|
420
646
|
* Deploy 凭证文件操作。
|
|
421
647
|
*
|
|
422
648
|
* 这些方法仅操作 `~/.hai/credentials.yml`,不依赖 `deploy.init()`。
|
|
649
|
+
* @example
|
|
650
|
+
* ```ts
|
|
651
|
+
* import type { DeployCredentialOperations } from '@h-ai/deploy'
|
|
652
|
+
* import { deploy } from '@h-ai/deploy'
|
|
653
|
+
* const credentials: DeployCredentialOperations = deploy.credentials
|
|
654
|
+
* const path = credentials.getPath() // 无需先 init。
|
|
655
|
+
* ```
|
|
423
656
|
*/
|
|
424
657
|
interface DeployCredentialOperations {
|
|
425
|
-
/**
|
|
658
|
+
/**
|
|
659
|
+
* 获取凭证文件绝对路径。
|
|
660
|
+
* @example
|
|
661
|
+
* ```ts
|
|
662
|
+
* import { deploy } from '@h-ai/deploy'
|
|
663
|
+
* const path = deploy.credentials.getPath() // 当前用户的全局凭证文件。
|
|
664
|
+
* ```
|
|
665
|
+
*/
|
|
426
666
|
getPath: () => string;
|
|
427
|
-
/**
|
|
667
|
+
/**
|
|
668
|
+
* 加载凭证文件并注入 `process.env`。
|
|
669
|
+
* @example
|
|
670
|
+
* ```ts
|
|
671
|
+
* import { deploy } from '@h-ai/deploy'
|
|
672
|
+
* const loaded = deploy.credentials.load()
|
|
673
|
+
* if (!loaded.success) throw new Error(loaded.error.message)
|
|
674
|
+
* const names = loaded.data // 不输出被注入的值。
|
|
675
|
+
* ```
|
|
676
|
+
*/
|
|
428
677
|
load: () => HaiResult<string[]>;
|
|
429
|
-
/**
|
|
678
|
+
/**
|
|
679
|
+
* 保存单个凭证。
|
|
680
|
+
* @example
|
|
681
|
+
* ```ts
|
|
682
|
+
* import { deploy } from '@h-ai/deploy'
|
|
683
|
+
* const token = process.env.HAI_DEPLOY_PROVIDER_TOKEN
|
|
684
|
+
* if (!token) throw new Error('Provide HAI_DEPLOY_PROVIDER_TOKEN privately')
|
|
685
|
+
* const saved = deploy.credentials.save('HAI_DEPLOY_PROVIDER_TOKEN', token)
|
|
686
|
+
* if (!saved.success) throw new Error(saved.error.message)
|
|
687
|
+
* ```
|
|
688
|
+
*/
|
|
430
689
|
save: (key: string, value: string) => HaiResult<void>;
|
|
431
|
-
/**
|
|
690
|
+
/**
|
|
691
|
+
* 批量保存凭证。
|
|
692
|
+
* @example
|
|
693
|
+
* ```ts
|
|
694
|
+
* import { deploy } from '@h-ai/deploy'
|
|
695
|
+
* const token = process.env.HAI_DEPLOY_PROVIDER_TOKEN
|
|
696
|
+
* if (!token) throw new Error('Provide HAI_DEPLOY_PROVIDER_TOKEN privately')
|
|
697
|
+
* const saved = deploy.credentials.saveAll({ HAI_DEPLOY_PROVIDER_TOKEN: token })
|
|
698
|
+
* if (!saved.success) throw new Error(saved.error.message)
|
|
699
|
+
* ```
|
|
700
|
+
*/
|
|
432
701
|
saveAll: (entries: Record<string, string>) => HaiResult<void>;
|
|
433
702
|
}
|
|
434
703
|
/**
|
|
@@ -441,25 +710,51 @@ interface DeployCredentialOperations {
|
|
|
441
710
|
* - `deploy.provisionAll()` — 开通所有已配置的基础设施
|
|
442
711
|
* - `deploy.deployApp()` — 完整部署流程
|
|
443
712
|
* - `deploy.close()` — 关闭模块
|
|
444
|
-
*
|
|
713
|
+
* scan 与 credentials 不需要 init;部署与开通遵循 init → 检查结果 → use → finally close。close 返回 Promise<void>,不伪造 HaiResult。
|
|
445
714
|
* @example
|
|
446
715
|
* ```ts
|
|
716
|
+
* import type { DeployFunctions } from '@h-ai/deploy'
|
|
447
717
|
* import { deploy } from '@h-ai/deploy'
|
|
448
|
-
*
|
|
449
|
-
* await
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
* console.log(`Deployed: ${result.data.url}`)
|
|
453
|
-
* }
|
|
454
|
-
* await deploy.close()
|
|
718
|
+
* const operations: DeployFunctions = deploy
|
|
719
|
+
* const scan = await operations.scan(process.cwd())
|
|
720
|
+
* if (!scan.success) throw new Error(scan.error.message)
|
|
721
|
+
* const required = scan.data.requiredServices
|
|
455
722
|
* ```
|
|
456
723
|
*/
|
|
457
724
|
interface DeployFunctions {
|
|
458
725
|
/** 全局部署凭证文件操作。 */
|
|
459
726
|
readonly credentials: DeployCredentialOperations;
|
|
460
|
-
/**
|
|
727
|
+
/**
|
|
728
|
+
* 初始化模块(加载配置、创建 Provider 和 Provisioner 实例)
|
|
729
|
+
* @example
|
|
730
|
+
* ```ts
|
|
731
|
+
* import { deploy } from '@h-ai/deploy'
|
|
732
|
+
* const initialized = await deploy.init({ provider: { type: 'docker-ssh', expose: { hostPort: 8080 } } })
|
|
733
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
734
|
+
* try {
|
|
735
|
+
* const ready = deploy.isInitialized
|
|
736
|
+
* }
|
|
737
|
+
* finally {
|
|
738
|
+
* await deploy.close()
|
|
739
|
+
* }
|
|
740
|
+
* ```
|
|
741
|
+
*/
|
|
461
742
|
init: (config: DeployConfigInput) => Promise<HaiResult<void>>;
|
|
462
|
-
/**
|
|
743
|
+
/**
|
|
744
|
+
* 关闭模块
|
|
745
|
+
* @example
|
|
746
|
+
* ```ts
|
|
747
|
+
* import { deploy } from '@h-ai/deploy'
|
|
748
|
+
* const initialized = await deploy.init({ provider: { type: 'docker-ssh', expose: { hostPort: 8080 } } })
|
|
749
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
750
|
+
* try {
|
|
751
|
+
* const provider = deploy.config?.provider.type
|
|
752
|
+
* }
|
|
753
|
+
* finally {
|
|
754
|
+
* await deploy.close() // Promise<void>;不检查不存在的 success 字段。
|
|
755
|
+
* }
|
|
756
|
+
* ```
|
|
757
|
+
*/
|
|
463
758
|
close: () => Promise<void>;
|
|
464
759
|
/** 当前配置 */
|
|
465
760
|
readonly config: DeployConfig | null;
|
|
@@ -471,6 +766,13 @@ interface DeployFunctions {
|
|
|
471
766
|
* 这是纯文件系统分析能力,不依赖云端认证状态,可在 `deploy.init()` 之前调用。
|
|
472
767
|
*
|
|
473
768
|
* @param appDir - 应用根目录路径
|
|
769
|
+
* @example
|
|
770
|
+
* ```ts
|
|
771
|
+
* import { deploy } from '@h-ai/deploy'
|
|
772
|
+
* const scanned = await deploy.scan(process.cwd(), { environment: 'prod' })
|
|
773
|
+
* if (!scanned.success) throw new Error(scanned.error.message)
|
|
774
|
+
* const services = scanned.data.requiredServices // 无需 init。
|
|
775
|
+
* ```
|
|
474
776
|
*/
|
|
475
777
|
scan: (appDir: string, options?: DeployScanOptions) => Promise<HaiResult<ScanResult>>;
|
|
476
778
|
/**
|
|
@@ -478,6 +780,28 @@ interface DeployFunctions {
|
|
|
478
780
|
*
|
|
479
781
|
* @param projectName - 用于资源命名的项目名
|
|
480
782
|
* @returns 所有 Provisioner 的结果列表
|
|
783
|
+
* @example
|
|
784
|
+
* ```ts
|
|
785
|
+
* import { deploy, getDeployRecovery } from '@h-ai/deploy'
|
|
786
|
+
* const apiKey = process.env.HAI_DEPLOY_SERVICES_DB_APIKEY
|
|
787
|
+
* if (!apiKey) throw new Error('Provide HAI_DEPLOY_SERVICES_DB_APIKEY privately')
|
|
788
|
+
* const initialized = await deploy.init({ provider: { type: 'docker-ssh', expose: { hostPort: 8080 } }, services: { db: { provisioner: 'neon', apiKey } } })
|
|
789
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
790
|
+
* try {
|
|
791
|
+
* // 会访问真实云服务并可能新建资源。
|
|
792
|
+
* const result = await deploy.provisionAll('shop', ['db'])
|
|
793
|
+
* if (!result.success) {
|
|
794
|
+
* const recovery = getDeployRecovery(result.error)
|
|
795
|
+
* if (recovery?.resources.some(resource => resource.resourceStatus === 'unknown')) {
|
|
796
|
+
* process.stderr.write('Verify unknown resources at the provider before retrying\n')
|
|
797
|
+
* }
|
|
798
|
+
* throw new Error(result.error.message)
|
|
799
|
+
* }
|
|
800
|
+
* }
|
|
801
|
+
* finally {
|
|
802
|
+
* await deploy.close()
|
|
803
|
+
* }
|
|
804
|
+
* ```
|
|
481
805
|
*/
|
|
482
806
|
provisionAll: (projectName: string, services?: ServiceType[]) => Promise<HaiResult<ProvisionResult[]>>;
|
|
483
807
|
/**
|
|
@@ -485,6 +809,21 @@ interface DeployFunctions {
|
|
|
485
809
|
*
|
|
486
810
|
* @param appDir - 应用根目录路径
|
|
487
811
|
* @param options - 部署选项
|
|
812
|
+
* @example
|
|
813
|
+
* ```ts
|
|
814
|
+
* import { deploy } from '@h-ai/deploy'
|
|
815
|
+
* const initialized = await deploy.init({ provider: { type: 'docker-ssh', expose: { hostPort: 8080 } } })
|
|
816
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
817
|
+
* try {
|
|
818
|
+
* // 当前项目必须已有构建镜像清单与生产环境配置。
|
|
819
|
+
* const result = await deploy.deployApp(process.cwd(), { environment: 'prod', bundleOnly: true })
|
|
820
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
821
|
+
* const status = result.data.status // packaged 不代表线上运行。
|
|
822
|
+
* }
|
|
823
|
+
* finally {
|
|
824
|
+
* await deploy.close()
|
|
825
|
+
* }
|
|
826
|
+
* ```
|
|
488
827
|
*/
|
|
489
828
|
deployApp: (appDir: string, options?: DeployAppOptions) => Promise<HaiResult<DeployResult>>;
|
|
490
829
|
}
|
|
@@ -498,14 +837,29 @@ interface DeployFunctions {
|
|
|
498
837
|
|
|
499
838
|
/**
|
|
500
839
|
* Deploy 模块单例
|
|
501
|
-
*
|
|
840
|
+
* 每次 init 检查 HaiResult;只打包不会连接 SSH,成功打包也不代表服务器已部署。远端 unknown 必须先核对匹配部署 ID 的结果,不能盲目重试。
|
|
502
841
|
* @example
|
|
503
842
|
* ```ts
|
|
504
|
-
* import { deploy } from '@h-ai/deploy'
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
843
|
+
* import { deploy, getDeployCommandState } from '@h-ai/deploy'
|
|
844
|
+
* const initialized = await deploy.init({ provider: { type: 'docker-ssh', expose: { hostPort: 8080 } } })
|
|
845
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
846
|
+
* try {
|
|
847
|
+
* // 当前项目已有镜像产物与部署环境;只打包,不连接服务器。
|
|
848
|
+
* const result = await deploy.deployApp(process.cwd(), { environment: 'prod', bundleOnly: true })
|
|
849
|
+
* if (!result.success) {
|
|
850
|
+
* const state = getDeployCommandState(result.error)
|
|
851
|
+
* if (state?.remoteExecution === 'unknown') {
|
|
852
|
+
* process.stderr.write('Inspect the matching server result before retrying\n')
|
|
853
|
+
* }
|
|
854
|
+
* throw new Error(result.error.message)
|
|
855
|
+
* }
|
|
856
|
+
* if (result.data.status === 'packaged') {
|
|
857
|
+
* const bundle = result.data.bundlePath
|
|
858
|
+
* }
|
|
859
|
+
* }
|
|
860
|
+
* finally {
|
|
861
|
+
* await deploy.close()
|
|
862
|
+
* }
|
|
509
863
|
* ```
|
|
510
864
|
*/
|
|
511
865
|
declare const deploy: DeployFunctions;
|
|
@@ -518,17 +872,16 @@ declare const deploy: DeployFunctions;
|
|
|
518
872
|
*/
|
|
519
873
|
/**
|
|
520
874
|
* 获取部署模块文案
|
|
521
|
-
*
|
|
875
|
+
* 使用 core 请求/全局 locale 的现有中英字典;不自行缓存调用时的语言。
|
|
522
876
|
* @param key - 文案 Key
|
|
523
877
|
* @param options - 插值参数与格式化选项
|
|
524
878
|
* @returns 本地化后的文案字符串
|
|
525
|
-
*
|
|
526
|
-
* @example
|
|
879
|
+
* @example 模块内部上下文
|
|
527
880
|
* ```ts
|
|
528
|
-
* const
|
|
881
|
+
* const message = deployM('deploy_sshRequired')
|
|
529
882
|
* ```
|
|
530
883
|
*/
|
|
531
|
-
declare const deployM: (key: "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_artifactInvalid" | "deploy_sshRequired" | "deploy_bundleInstructions" | "deploy_bundleMetadata" | "deploy_bundleOnlyContainer" | "deploy_selectedContainerOnly" | "deploy_selectionInvalid" | "deploy_storageArtifactRequired" | "deploy_imageVersionRequired" | "deploy_bundleRuntimeRequired" | "deploy_bundleFailed" | "deploy_configFileInvalid" | "deploy_configFileUnreadable" | "deploy_bundleNameInvalid" | "deploy_secretsInvalid", options?: _h_ai_core.MessageOptions) => string;
|
|
884
|
+
declare const deployM: (key: "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_artifactInvalid" | "deploy_sshRequired" | "deploy_bundleInstructions" | "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_storageArtifactRequired" | "deploy_imageVersionRequired" | "deploy_bundleRuntimeRequired" | "deploy_bundleFailed" | "deploy_configFileInvalid" | "deploy_configFileUnreadable" | "deploy_bundleNameInvalid" | "deploy_secretsInvalid" | "deploy_localStopped" | "deploy_localUnknown" | "deploy_localNotStarted" | "deploy_commandOutputFailed" | "deploy_commandInputFailed" | "deploy_commandTreeActive" | "deploy_commandExecutionFailed" | "deploy_remoteUnknown" | "deploy_remoteFinished", options?: _h_ai_core.MessageOptions) => string;
|
|
532
885
|
|
|
533
886
|
/**
|
|
534
887
|
* 部署中间件的后端与连接字段目录,供扫描、CLI 和容器规划共同使用。
|
|
@@ -536,7 +889,14 @@ declare const deployM: (key: "deploy_notInitialized" | "deploy_initFailed" | "de
|
|
|
536
889
|
* @module deploy-middleware
|
|
537
890
|
*/
|
|
538
891
|
|
|
539
|
-
/**
|
|
892
|
+
/**
|
|
893
|
+
* 连接字段;例如 `{ name: 'port', defaultValue: '5432', kind: 'port' }`。
|
|
894
|
+
* @example
|
|
895
|
+
* ```ts
|
|
896
|
+
* import type { MiddlewareField } from '@h-ai/deploy'
|
|
897
|
+
* const field: MiddlewareField = { name: 'port', defaultValue: '5432', required: true, kind: 'port' }
|
|
898
|
+
* ```
|
|
899
|
+
*/
|
|
540
900
|
interface MiddlewareField {
|
|
541
901
|
/** 模块配置字段名,camelCase 不拆词。 */
|
|
542
902
|
name: string;
|
|
@@ -553,7 +913,14 @@ interface MiddlewareField {
|
|
|
553
913
|
/** 数值上限;例如 Redis db 为 15。 */
|
|
554
914
|
maximum?: number;
|
|
555
915
|
}
|
|
556
|
-
/**
|
|
916
|
+
/**
|
|
917
|
+
* 后端目录项;例如 PostgreSQL 对应 `backend: 'postgresql'`。
|
|
918
|
+
* @example
|
|
919
|
+
* ```ts
|
|
920
|
+
* import type { MiddlewareBackend } from '@h-ai/deploy'
|
|
921
|
+
* const backend: MiddlewareBackend = { backend: 'postgresql', label: 'PostgreSQL', purpose: 'deploy_purposeDatabase', fields: [{ name: 'database', required: true }] }
|
|
922
|
+
* ```
|
|
923
|
+
*/
|
|
557
924
|
interface MiddlewareBackend {
|
|
558
925
|
/** 模块 Schema 接受的后端标识。 */
|
|
559
926
|
backend: string;
|
|
@@ -569,16 +936,54 @@ interface MiddlewareBackend {
|
|
|
569
936
|
/**
|
|
570
937
|
* 所有可部署中间件的连接目录。
|
|
571
938
|
* SQLite、memory、local 与 disabled 保留本地/禁用语义,不创建无关 sidecar。
|
|
572
|
-
*
|
|
939
|
+
* 目录同时描述本机、禁用、自建与云后端;存在依赖不等于必须开通新资源。
|
|
940
|
+
* @example
|
|
941
|
+
* ```ts
|
|
942
|
+
* import { DEPLOY_MIDDLEWARE, describeMiddlewareBackend } from '@h-ai/deploy'
|
|
943
|
+
* const choices = DEPLOY_MIDDLEWARE.db.map(backend => ({ value: backend.backend, description: describeMiddlewareBackend(backend) }))
|
|
944
|
+
* ```
|
|
573
945
|
*/
|
|
574
946
|
declare const DEPLOY_MIDDLEWARE: Record<ServiceType, MiddlewareBackend[]>;
|
|
575
947
|
/**
|
|
576
948
|
* 返回当前语言的后端用途说明。
|
|
577
|
-
* @
|
|
949
|
+
* @param backend - 部署目录中的后端条目。
|
|
950
|
+
* @returns 当前 locale 的用途说明。
|
|
951
|
+
* @example
|
|
952
|
+
* ```ts
|
|
953
|
+
* import { DEPLOY_MIDDLEWARE, describeMiddlewareBackend } from '@h-ai/deploy'
|
|
954
|
+
* const backend = DEPLOY_MIDDLEWARE.db.find(item => item.backend === 'postgresql')
|
|
955
|
+
* if (backend) {
|
|
956
|
+
* const description = describeMiddlewareBackend(backend)
|
|
957
|
+
* }
|
|
958
|
+
* ```
|
|
578
959
|
*/
|
|
579
960
|
declare function describeMiddlewareBackend(backend: MiddlewareBackend): string;
|
|
580
961
|
|
|
581
|
-
/**
|
|
962
|
+
/**
|
|
963
|
+
* 读取命令失败的安全状态;不把本地 SSH 退出解释为远端停止。
|
|
964
|
+
* @param error - 部署错误
|
|
965
|
+
* @returns 通过结构校验的命令状态,或 undefined
|
|
966
|
+
* @example
|
|
967
|
+
* ```ts
|
|
968
|
+
* import { getDeployCommandState, HaiDeployError } from '@h-ai/deploy'
|
|
969
|
+
* const state = getDeployCommandState({ ...HaiDeployError.REMOTE_COMMAND_FAILED, message: 'SSH connection interrupted', ext: { commandExecution: { reason: 'exit', localTermination: 'confirmed', remoteExecution: 'unknown' } } })
|
|
970
|
+
* if (state?.remoteExecution === 'unknown') process.stderr.write('Remote execution is unknown\n')
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
973
|
+
declare function getDeployCommandState(error: HaiError): DeployCommandState | undefined;
|
|
974
|
+
/**
|
|
975
|
+
* 读取错误中的恢复清单;仅返回明确允许展示的字段。
|
|
976
|
+
* @param error - 上层捕获的部署 HaiError;不直接展示其 cause。
|
|
977
|
+
* @returns 安全恢复清单;结构不满足约定时为 undefined。
|
|
978
|
+
* @example
|
|
979
|
+
* ```ts
|
|
980
|
+
* import { getDeployRecovery, HaiDeployError } from '@h-ai/deploy'
|
|
981
|
+
* const recovery = getDeployRecovery({ ...HaiDeployError.PROVISION_FAILED, message: 'Provisioning failed', ext: { recovery: { projectName: 'shop', stage: 'provision', resources: [] } } })
|
|
982
|
+
* if (recovery) {
|
|
983
|
+
* const stage = recovery.stage
|
|
984
|
+
* }
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
582
987
|
declare function getDeployRecovery(error: HaiError): DeployRecoveryInfo | undefined;
|
|
583
988
|
|
|
584
|
-
export { DEPLOY_MIDDLEWARE, type DeployAppOptions, type DeployConfig, type DeployConfigInput, DeployConfigSchema, type DeployCredentialOperations, type DeployError, type DeployFunctions, type DeployRecoveryInfo, type DeployResult, type DeployScanOptions, type DeploymentArtifact, DeploymentArtifactSchema, type DeploymentEnvironment, type DockerSshProviderConfig, HaiDeployError, type MiddlewareBackend, type MiddlewareField, type MiddlewareMode, type MiddlewareRequirement, type PortExposeConfig, ProviderConfigSchema, type ProvisionResult, type ScanResult, type ServiceType, type SshConfig, artifactChecksum, deploy, describeMiddlewareBackend, getDeployRecovery, loadDeploymentConfig, loadDeploymentEnvironment, readDeploymentArtifact, saveDeploymentEnvironment };
|
|
989
|
+
export { DEPLOY_MIDDLEWARE, type DeployAppOptions, type DeployCommandState, type DeployConfig, type DeployConfigInput, DeployConfigSchema, type DeployCredentialOperations, type DeployError, type DeployFunctions, type DeployRecoveryInfo, type DeployResult, type DeployScanOptions, type DeploymentArtifact, DeploymentArtifactSchema, type DeploymentEnvironment, type DockerSshProviderConfig, HaiDeployError, type MiddlewareBackend, type MiddlewareField, type MiddlewareMode, type MiddlewareRequirement, type PortExposeConfig, ProviderConfigSchema, type ProvisionResult, type ScanResult, type ServiceType, type SshConfig, artifactChecksum, deploy, describeMiddlewareBackend, getDeployCommandState, getDeployRecovery, loadDeploymentConfig, loadDeploymentEnvironment, readDeploymentArtifact, saveDeploymentEnvironment };
|