@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/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
- /** 镜像制品清单,例如 `{ version: 3, appVersion: '1.2.3', buildId: '1.2.3-build1', partial: false, hasWeb: false, images: [...] }`。 */
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
- /** 构建器与部署器共享的镜像交付结构;参见 DeploymentArtifactSchema 示例。 */
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
- * @example `const checksum = await artifactChecksum("/release/app-1.2.3.tar")`
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
- * @example `const artifact = await readDeploymentArtifact("/release/build-1")`
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
- * 本文件定义部署模块的错误码、Zod Schema 和配置类型。
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
- /** SSH 连接配置(parse 后) */
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
- /** 端口暴露配置(parse 后) */
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
- /** docker-ssh 部署平台配置(parse 后) */
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
- /** 部署模块完整配置 Schema */
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
- /** 部署配置类型(parse 后) */
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
- /** 部署环境快照;例如 prod 的 targetValues 只来自 `.env.prod`,不包含基础/私有覆盖。 */
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 `loadDeploymentConfig('deploy', '/app/config/_deploy.yml', environment.values)`
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 `loadDeploymentEnvironment({ environment: 'prod', envDir: '.' })`
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 `saveDeploymentEnvironment(snapshot, { HAI_DB_TYPE: 'postgresql' })`
240
- * @example `saveDeploymentEnvironment(snapshot, { HAI_DEPLOY_PROVIDER: JSON.stringify(provider) }, { private: true })`
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
- * const result = await deploy.deployApp('./apps/my-app')
273
- * if (!result.success) {
274
- * const error: DeployError = result.error
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
- /** 每项中间件的处理方式;keep 不修改配置,也不开通服务。 */
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
- /** 扫描环境;例如 `{ environment: 'test', envDir: '/workspace/app' }`。 */
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
- /** 依赖对应的中间件;例如 IAM 的 LDAP 位于 `iam.ldap`,可处于 disabled 状态。 */
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
- /** 加载凭证文件并注入 `process.env`。 */
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 deploy.init({ provider: { type: 'vercel', token: 'xxx' } })
450
- * const result = await deploy.deployApp('./apps/my-app')
451
- * if (result.success) {
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
- /** 初始化模块(加载配置、创建 Provider 和 Provisioner 实例) */
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
- * await deploy.init({ provider: { type: 'vercel', token: 'xxx' } })
507
- * const result = await deploy.deployApp('./apps/my-app')
508
- * await deploy.close()
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 text = deployM('deploy_notInitialized')
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
- /** 连接字段;例如 `{ name: 'port', defaultValue: '5432', kind: 'port' }`。 */
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
- /** 后端目录项;例如 PostgreSQL 对应 `backend: 'postgresql'`。 */
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
- * @example `DEPLOY_MIDDLEWARE.db.map(item => item.label)` 返回数据库选择项。
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
- * @example `describeMiddlewareBackend(DEPLOY_MIDDLEWARE.db[0])`
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 };