@h-ai/deploy 1.0.0-beta.2 → 1.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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>;
@@ -102,11 +107,26 @@ declare const SshConfigSchema: z.ZodObject<{
102
107
  strictHostKeyChecking: z.ZodDefault<z.ZodBoolean>;
103
108
  connectTimeoutSeconds: z.ZodDefault<z.ZodNumber>;
104
109
  }, z.core.$strip>;
105
- /** 端口直出暴露配置 */
110
+ /** HTTP 端口及可选 HTTPS 入口;Let's Encrypt 使用 HTTP-01,HTTP 必须映射 80。 */
106
111
  declare const PortExposeSchema: z.ZodObject<{
107
112
  type: z.ZodDefault<z.ZodLiteral<"port">>;
108
113
  containerPort: z.ZodDefault<z.ZodNumber>;
109
114
  hostPort: z.ZodNumber;
115
+ https: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
116
+ certificateFile: z.ZodString;
117
+ privateKeyFile: z.ZodString;
118
+ domain: z.ZodString;
119
+ port: z.ZodDefault<z.ZodNumber>;
120
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
121
+ type: z.ZodLiteral<"files">;
122
+ }, z.core.$strip>, z.ZodObject<{
123
+ domain: z.ZodString;
124
+ email: z.ZodEmail;
125
+ acceptTerms: z.ZodLiteral<true>;
126
+ port: z.ZodDefault<z.ZodNumber>;
127
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
128
+ type: z.ZodLiteral<"letsencrypt">;
129
+ }, z.core.$strip>], "type">>;
110
130
  }, z.core.$strip>;
111
131
  /** docker-ssh 部署平台配置 */
112
132
  declare const DockerSshProviderConfigSchema: z.ZodObject<{
@@ -137,6 +157,21 @@ declare const DockerSshProviderConfigSchema: z.ZodObject<{
137
157
  type: z.ZodDefault<z.ZodLiteral<"port">>;
138
158
  containerPort: z.ZodDefault<z.ZodNumber>;
139
159
  hostPort: z.ZodNumber;
160
+ https: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
161
+ certificateFile: z.ZodString;
162
+ privateKeyFile: z.ZodString;
163
+ domain: z.ZodString;
164
+ port: z.ZodDefault<z.ZodNumber>;
165
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
166
+ type: z.ZodLiteral<"files">;
167
+ }, z.core.$strip>, z.ZodObject<{
168
+ domain: z.ZodString;
169
+ email: z.ZodEmail;
170
+ acceptTerms: z.ZodLiteral<true>;
171
+ port: z.ZodDefault<z.ZodNumber>;
172
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
173
+ type: z.ZodLiteral<"letsencrypt">;
174
+ }, z.core.$strip>], "type">>;
140
175
  }, z.core.$strip>;
141
176
  trustedEdgeProxies: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
142
177
  }, z.core.$strip>;
@@ -182,6 +217,21 @@ declare const ProviderConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
182
217
  type: z.ZodDefault<z.ZodLiteral<"port">>;
183
218
  containerPort: z.ZodDefault<z.ZodNumber>;
184
219
  hostPort: z.ZodNumber;
220
+ https: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
221
+ certificateFile: z.ZodString;
222
+ privateKeyFile: z.ZodString;
223
+ domain: z.ZodString;
224
+ port: z.ZodDefault<z.ZodNumber>;
225
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
226
+ type: z.ZodLiteral<"files">;
227
+ }, z.core.$strip>, z.ZodObject<{
228
+ domain: z.ZodString;
229
+ email: z.ZodEmail;
230
+ acceptTerms: z.ZodLiteral<true>;
231
+ port: z.ZodDefault<z.ZodNumber>;
232
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
233
+ type: z.ZodLiteral<"letsencrypt">;
234
+ }, z.core.$strip>], "type">>;
185
235
  }, z.core.$strip>;
186
236
  trustedEdgeProxies: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
187
237
  }, z.core.$strip>], "type">;
@@ -257,6 +307,21 @@ declare const DeployConfigSchema: z.ZodObject<{
257
307
  type: z.ZodDefault<z.ZodLiteral<"port">>;
258
308
  containerPort: z.ZodDefault<z.ZodNumber>;
259
309
  hostPort: z.ZodNumber;
310
+ https: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
311
+ certificateFile: z.ZodString;
312
+ privateKeyFile: z.ZodString;
313
+ domain: z.ZodString;
314
+ port: z.ZodDefault<z.ZodNumber>;
315
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
316
+ type: z.ZodLiteral<"files">;
317
+ }, z.core.$strip>, z.ZodObject<{
318
+ domain: z.ZodString;
319
+ email: z.ZodEmail;
320
+ acceptTerms: z.ZodLiteral<true>;
321
+ port: z.ZodDefault<z.ZodNumber>;
322
+ redirectHttp: z.ZodDefault<z.ZodBoolean>;
323
+ type: z.ZodLiteral<"letsencrypt">;
324
+ }, z.core.$strip>], "type">>;
260
325
  }, z.core.$strip>;
261
326
  trustedEdgeProxies: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
262
327
  }, z.core.$strip>], "type">;
@@ -294,6 +359,16 @@ declare const DeployConfigSchema: z.ZodObject<{
294
359
  rustfs: "rustfs";
295
360
  minio: "minio";
296
361
  }>>;
362
+ compose: z.ZodOptional<z.ZodObject<{
363
+ services: z.ZodObject<{
364
+ serv: z.ZodOptional<z.ZodObject<{
365
+ extra_hosts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6]>>>;
366
+ }, z.core.$strict>>;
367
+ web: z.ZodOptional<z.ZodObject<{
368
+ extra_hosts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6]>>>;
369
+ }, z.core.$strict>>;
370
+ }, z.core.$strict>;
371
+ }, z.core.$strict>>;
297
372
  }, z.core.$strip>>;
298
373
  }, z.core.$strip>;
299
374
  /**
@@ -315,100 +390,6 @@ type DeployConfig = z.infer<typeof DeployConfigSchema>;
315
390
  */
316
391
  type DeployConfigInput = z.input<typeof DeployConfigSchema>;
317
392
 
318
- /** 部署环境的加载和持久化;公开环境文件不保存真实凭据。 */
319
-
320
- /**
321
- * 部署环境快照;例如 prod 的 targetValues 只来自 `.env.prod`,不包含基础/私有覆盖。
322
- * @example
323
- * ```ts
324
- * import type { DeploymentEnvironment } from '@h-ai/deploy'
325
- * const environment: DeploymentEnvironment = { environment: 'prod', envDir: '/workspace/shop', values: { HAI_DB_TYPE: 'postgresql' }, targetValues: { HAI_DB_TYPE: 'postgresql' } }
326
- * // values 可能还含私有凭据,不能整体写入日志。
327
- * ```
328
- */
329
- interface DeploymentEnvironment {
330
- /** 文件模式(dev/test/prod 或其他合法模式名)。 */
331
- environment: string;
332
- /** 环境文件的绝对目录。 */
333
- envDir: string;
334
- /** 合并后的部署变量,可能含私有值,不得直接记录日志。 */
335
- values: Record<string, string>;
336
- /** 仅目标环境文件显式声明的变量,用于判断能否“保持不变”。 */
337
- targetValues: Record<string, string>;
338
- }
339
- /**
340
- * 按来源归并环境变量;HAI 高层父配置清除旧叶,同层按父→叶处理。
341
- * @param layers - 从低到高优先级的环境来源。
342
- * @param prefix - 可选变量前缀,仅归并该模块。
343
- * @returns 归并后的字面量环境变量,可能包含秘密。
344
- * @example 模块内部上下文
345
- * ```ts
346
- * const env = mergeEnvironmentLayers([{ HAI_CACHE_TYPE: 'memory' }, { HAI_CACHE: '{"type":"redis"}' }])
347
- * ```
348
- */
349
- declare function mergeEnvironmentLayers(layers: Array<Record<string, string | undefined>>, prefix?: string): Record<string, string>;
350
- /**
351
- * 按部署环境解析配置;未选择的可选 Provisioner 缺少凭据时保留空值,选择完成后由 Schema 校验。
352
- * hai.json 只读取对应的根分区;运行时模块继续读取 YAML。不修改 core 缓存或进程变量。
353
- * @param name - 模块配置名,例如 deploy/db/iam
354
- * @param path - hai.json 或运行时 YAML 文件的绝对路径
355
- * @param values - 已加载的目标环境变量
356
- * @returns 配置对象;解析错误已脱敏
357
- * @example
358
- * ```ts
359
- * import { loadDeploymentConfig, loadDeploymentEnvironment } from '@h-ai/deploy'
360
- * const environment = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
361
- * if (!environment.success) throw new Error(environment.error.message)
362
- * const config = loadDeploymentConfig('deploy', `${process.cwd()}/hai.json`, environment.data.values)
363
- * if (!config.success) throw new Error(config.error.message)
364
- * // 返回对象仍需经 DeployConfigSchema 或 deploy.init 验证。
365
- * ```
366
- */
367
- declare function loadDeploymentConfig(name: string, path: string, values: Record<string, string | undefined>): HaiResult<Record<string, unknown>>;
368
- /**
369
- * 加载部署环境;指定环境文件缺失时返回错误并要求用户创建。
370
- * 部署目标按进程 > 模式私有 > 模式公共 > 旧全局私有 > 基础归并。
371
- * 其它模块保留进程 > 模式私有 > 旧全局私有 > 模式公共 > 基础;targetValues 仅记录模式公共项。
372
- * @param options - 模式、环境目录与是否强制存在目标文件
373
- * @param options.environment - dev/test/prod 或自定义模式
374
- * @param options.envDir - 环境文件所在目录
375
- * @param options.requireFile - 默认 true;扫描无显式环境时可只读取已有基础文件
376
- * @returns 环境快照,可能包含私有值,不得直接输出
377
- * @example
378
- * ```ts
379
- * import { loadDeploymentEnvironment } from '@h-ai/deploy'
380
- * const loaded = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
381
- * if (!loaded.success) throw new Error(loaded.error.message)
382
- * const explicitlyConfigured = loaded.data.targetValues.HAI_DB_TYPE
383
- * ```
384
- */
385
- declare function loadDeploymentEnvironment(options: {
386
- environment: string;
387
- envDir: string;
388
- requireFile?: boolean;
389
- }): HaiResult<DeploymentEnvironment>;
390
- /**
391
- * 保存部署变量:公共值写目标环境文件,凭据写 `.env.<environment>.local`;旧共享私有文件不删除。
392
- * 返回实际写入的变量名,调用者只展示名称或脱敏值。
393
- * @param environment - 已加载的目标环境快照
394
- * @param values - 需要更新的变量;未提供的项保持原状
395
- * @param options - private 为 true 时所有值只保存在本机;适用于 SSH 地址、端口及密钥路径
396
- * @param options.private - 是否将全部值保存到选中模式的私有文件
397
- * @returns 已保存的变量名或脱敏错误
398
- * @example
399
- * ```ts
400
- * import { loadDeploymentEnvironment, saveDeploymentEnvironment } from '@h-ai/deploy'
401
- * const loaded = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
402
- * if (!loaded.success) throw new Error(loaded.error.message)
403
- * const saved = saveDeploymentEnvironment(loaded.data, { HAI_DB_HOST: 'db' })
404
- * if (!saved.success) throw new Error(saved.error.message)
405
- * // 密钥应以 { private: true } 写入被忽略的 .env.prod.local,不能放公共环境文件。
406
- * ```
407
- */
408
- declare function saveDeploymentEnvironment(environment: DeploymentEnvironment, values: Record<string, string>, options?: {
409
- private?: boolean;
410
- }): HaiResult<string[]>;
411
-
412
393
  /**
413
394
  *
414
395
  * @example
@@ -492,7 +473,7 @@ interface DeployScanOptions {
492
473
  envDir?: string;
493
474
  }
494
475
  /**
495
- * 依赖对应的中间件;例如 IAM 的 LDAP 位于 `iam.ldap`,可处于 disabled 状态。
476
+ * 已启用能力对应的中间件;例如 LDAP 仅在 `iam.login.ldap` 为 true 时纳入扫描。
496
477
  * @example
497
478
  * ```ts
498
479
  * import type { MiddlewareRequirement } from '@h-ai/deploy'
@@ -575,7 +556,7 @@ interface DeployResult {
575
556
  bundlePath?: string;
576
557
  /** 手工搬运和启动说明;仅打包不代表服务器已运行。 */
577
558
  instructions?: string;
578
- /** 已设置的环境变量名列表 */
559
+ /** 保留的有效环境变量名;packaged 状态仅表示交付计划,尚未在服务器设置。 */
579
560
  envVarsSet: string[];
580
561
  /** 部署 Provider 名称(如 vercel / docker-ssh),容器部署时返回 */
581
562
  provider?: string;
@@ -662,8 +643,12 @@ interface DeployCommandState {
662
643
  * ```
663
644
  */
664
645
  interface DeployAppOptions {
646
+ /** 本地打包所需镜像的下载源;Compose 与部署身份保留原始镜像引用。 */
647
+ imageSource?: ImageSourceConfig;
648
+ /** 本次拉取子进程的代理;远程 Podman/Docker daemon 的代理需在引擎侧设置。 */
649
+ proxy?: DownloadProxyConfig;
665
650
  /** 接收实际执行阶段,用于终端进度显示;不包含凭据或配置原文。 */
666
- onProgress?: (stage: 'packaging' | 'preflight' | 'images' | 'dependencies' | 'start' | 'health' | 'complete') => void;
651
+ onProgress?: (stage: 'packaging' | 'preflight' | 'images' | 'dependencies' | 'start' | 'https' | 'health' | 'complete') => void;
667
652
  /** 只更新指定的 Compose 服务;省略时完整制品部署全部,部分制品只部署其镜像。 */
668
653
  selectedServices?: string[];
669
654
  /** 打包中间件镜像所用的本地引擎,auto 优先 Podman。 */
@@ -683,6 +668,31 @@ interface DeployAppOptions {
683
668
  /** 交付包命名路径;默认在 .hai/deploy/<环境>/bundle-<项目>-<部署ID>-<版本>/ 中输出同名 tar 和脚本,自定义 release.tar 输出 release-<版本>/release-<版本>.tar;已有目录拒绝覆盖。 */
684
669
  output?: string;
685
670
  }
671
+ /**
672
+ * 镜像下载源;自定义映射可带命名空间路径,不含认证信息。
673
+ * @example
674
+ * ```ts
675
+ * import type { ImageSourceConfig } from '@h-ai/deploy'
676
+ * const source: ImageSourceConfig = { type: 'custom', registries: { 'docker.io': 'mirror.example.com/docker.io', 'ghcr.io': 'mirror.example.com/ghcr.io' } }
677
+ * ```
678
+ */
679
+ interface ImageSourceConfig {
680
+ type: 'official' | 'cn' | 'custom';
681
+ registries?: Record<string, string>;
682
+ }
683
+ /**
684
+ * 下载代理;自定义地址仅接受无认证的 HTTP(S),认证代理从进程环境继承。
685
+ * @example
686
+ * ```ts
687
+ * import type { DownloadProxyConfig } from '@h-ai/deploy'
688
+ * const proxy: DownloadProxyConfig = { mode: 'custom', url: 'http://127.0.0.1:10808', bypass: 'localhost,127.0.0.1' }
689
+ * ```
690
+ */
691
+ interface DownloadProxyConfig {
692
+ mode: 'inherit' | 'system' | 'custom' | 'none';
693
+ url?: string;
694
+ bypass?: string;
695
+ }
686
696
  /**
687
697
  * Deploy 凭证文件操作。
688
698
  *
@@ -869,6 +879,131 @@ interface DeployFunctions {
869
879
  deployApp: (appDir: string, options?: DeployAppOptions) => Promise<HaiResult<DeployResult>>;
870
880
  }
871
881
 
882
+ /** 构建与交付共用的下载源解析;不修改系统或容器引擎配置。 */
883
+
884
+ /**
885
+ * 将镜像引用映射到所选下载源,保留命名空间、版本与摘要。
886
+ * @param reference - Docker/OCI 镜像引用。
887
+ * @param source - 官方、大陆或按原仓库配置的自定义源。
888
+ * @returns 下载引用;官方源保留输入引用。
889
+ * @throws Error - 源、仓库映射或镜像引用不合法。
890
+ * @example
891
+ * ```ts
892
+ * import { resolveImageReference } from '@h-ai/deploy'
893
+ * const image = resolveImageReference('node:24.22.1-bookworm-slim', { type: 'cn' })
894
+ * // docker.1ms.run/library/node:24.22.1-bookworm-slim
895
+ * ```
896
+ */
897
+ declare function resolveImageReference(reference: string, source?: ImageSourceConfig): string;
898
+ /**
899
+ * 解析本次下载使用的代理环境,不写配置、不重启引擎。
900
+ * @param config - 继承进程、读取系统、自定义或禁用代理。
901
+ * @returns 显式覆盖大小写代理变量的环境;远程引擎仍需自身配置代理。
902
+ * @throws Error - 配置非法、系统仅提供 PAC 或平台不支持读取系统代理。
903
+ * @example
904
+ * ```ts
905
+ * import { resolveDownloadProxy } from '@h-ai/deploy'
906
+ * const environment = resolveDownloadProxy({ mode: 'custom', url: 'http://127.0.0.1:10808' })
907
+ * // environment.HTTPS_PROXY 供本次子进程使用,不写进运行镜像。
908
+ * ```
909
+ */
910
+ declare function resolveDownloadProxy(config?: DownloadProxyConfig): Record<string, string>;
911
+
912
+ /** 部署环境的加载和持久化;公开环境文件不保存真实凭据。 */
913
+
914
+ /**
915
+ * 部署环境快照;例如 prod 的 targetValues 只来自 `.env.prod`,不包含基础/私有覆盖。
916
+ * @example
917
+ * ```ts
918
+ * import type { DeploymentEnvironment } from '@h-ai/deploy'
919
+ * const environment: DeploymentEnvironment = { environment: 'prod', envDir: '/workspace/shop', values: { HAI_DB_TYPE: 'postgresql' }, targetValues: { HAI_DB_TYPE: 'postgresql' } }
920
+ * // values 可能还含私有凭据,不能整体写入日志。
921
+ * ```
922
+ */
923
+ interface DeploymentEnvironment {
924
+ /** 文件模式(dev/test/prod 或其他合法模式名)。 */
925
+ environment: string;
926
+ /** 环境文件的绝对目录。 */
927
+ envDir: string;
928
+ /** 合并后的部署变量,可能含私有值,不得直接记录日志。 */
929
+ values: Record<string, string>;
930
+ /** 仅目标环境文件显式声明的变量,用于判断能否“保持不变”。 */
931
+ targetValues: Record<string, string>;
932
+ }
933
+ /**
934
+ * 按来源归并环境变量;HAI 高层父配置清除旧叶,同层按父→叶处理。
935
+ * @param layers - 从低到高优先级的环境来源。
936
+ * @param prefix - 可选变量前缀,仅归并该模块。
937
+ * @returns 归并后的字面量环境变量,可能包含秘密。
938
+ * @example 模块内部上下文
939
+ * ```ts
940
+ * const env = mergeEnvironmentLayers([{ HAI_CACHE_TYPE: 'memory' }, { HAI_CACHE: '{"type":"redis"}' }])
941
+ * ```
942
+ */
943
+ declare function mergeEnvironmentLayers(layers: Array<Record<string, string | undefined>>, prefix?: string): Record<string, string>;
944
+ /**
945
+ * 按部署环境解析配置;未选择的可选 Provisioner 缺少凭据时保留空值,选择完成后由 Schema 校验。
946
+ * hai.json 只读取对应的根分区;运行时模块继续读取 YAML。不修改 core 缓存或进程变量。
947
+ * @param name - 模块配置名,例如 deploy/db/iam
948
+ * @param path - hai.json 或运行时 YAML 文件的绝对路径
949
+ * @param values - 已加载的目标环境变量
950
+ * @returns 配置对象;解析错误已脱敏
951
+ * @example
952
+ * ```ts
953
+ * import { loadDeploymentConfig, loadDeploymentEnvironment } from '@h-ai/deploy'
954
+ * const environment = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
955
+ * if (!environment.success) throw new Error(environment.error.message)
956
+ * const config = loadDeploymentConfig('deploy', `${process.cwd()}/hai.json`, environment.data.values)
957
+ * if (!config.success) throw new Error(config.error.message)
958
+ * // 返回对象仍需经 DeployConfigSchema 或 deploy.init 验证。
959
+ * ```
960
+ */
961
+ declare function loadDeploymentConfig(name: string, path: string, values: Record<string, string | undefined>): HaiResult<Record<string, unknown>>;
962
+ /**
963
+ * 加载部署环境;指定环境文件缺失时返回错误并要求用户创建。
964
+ * 统一按进程 > 模式私有 > 全局私有 > 模式公共 > 基础归并;targetValues 仅记录模式公共项。
965
+ * @param options - 模式、环境目录与是否强制存在目标文件
966
+ * @param options.environment - dev/test/prod 或自定义模式
967
+ * @param options.envDir - 环境文件所在目录
968
+ * @param options.requireFile - 默认 true;扫描无显式环境时可只读取已有基础文件
969
+ * @returns 环境快照,可能包含私有值,不得直接输出
970
+ * @example
971
+ * ```ts
972
+ * import { loadDeploymentEnvironment } from '@h-ai/deploy'
973
+ * const loaded = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
974
+ * if (!loaded.success) throw new Error(loaded.error.message)
975
+ * const explicitlyConfigured = loaded.data.targetValues.HAI_DB_TYPE
976
+ * ```
977
+ */
978
+ declare function loadDeploymentEnvironment(options: {
979
+ environment: string;
980
+ envDir: string;
981
+ requireFile?: boolean;
982
+ }): HaiResult<DeploymentEnvironment>;
983
+ /**
984
+ * 保存部署变量:公共值写目标环境文件,凭据写 `.env.<environment>.local`;旧共享私有文件不删除。
985
+ * 返回实际写入的变量名,调用者只展示名称或脱敏值。
986
+ * @param environment - 已加载的目标环境快照
987
+ * @param values - 需要更新的变量;未提供的项保持原状
988
+ * @param options - private 为 true 时所有值只保存在本机;适用于 SSH 地址、端口及密钥路径
989
+ * @param options.private - 是否将全部值保存到选中模式的私有文件
990
+ * @param options.replace - 本次完整替换的配置前缀,只清理该模式中对应项。
991
+ * @returns 已保存的变量名或脱敏错误
992
+ * @example
993
+ * ```ts
994
+ * import { loadDeploymentEnvironment, saveDeploymentEnvironment } from '@h-ai/deploy'
995
+ * const loaded = loadDeploymentEnvironment({ environment: 'prod', envDir: process.cwd() })
996
+ * if (!loaded.success) throw new Error(loaded.error.message)
997
+ * const saved = saveDeploymentEnvironment(loaded.data, { HAI_DB_HOST: 'db' })
998
+ * if (!saved.success) throw new Error(saved.error.message)
999
+ * // 密钥应以 { private: true } 写入被忽略的 .env.prod.local,不能放公共环境文件。
1000
+ * ```
1001
+ */
1002
+ declare function saveDeploymentEnvironment(environment: DeploymentEnvironment, values: Record<string, unknown>, options?: {
1003
+ private?: boolean;
1004
+ replace?: readonly string[];
1005
+ }): HaiResult<string[]>;
1006
+
872
1007
  /**
873
1008
  * @h-ai/deploy — 部署辅助函数
874
1009
  *
@@ -942,7 +1077,7 @@ declare const deploy: DeployFunctions;
942
1077
  * const message = deployM('deploy_sshRequired')
943
1078
  * ```
944
1079
  */
945
- 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_webBaseConflict" | "deploy_storageProxyInvalid" | "deploy_storagePublicEndpointInvalid" | "deploy_storageBackendRequired" | "deploy_artifactInvalid" | "deploy_sshRequired" | "deploy_sshPasswordInvalid" | "deploy_sshAskpassFailed" | "deploy_sshAskpassCleanupFailed" | "deploy_targetAuth" | "deploy_targetPasswordEnv" | "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_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", 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;
946
1081
 
947
1082
  /**
948
1083
  * 部署中间件的后端与连接字段目录,供扫描、CLI 和容器规划共同使用。
@@ -967,6 +1102,8 @@ interface MiddlewareField {
967
1102
  required?: boolean;
968
1103
  /** 密码输入与私有环境文件写入标记。 */
969
1104
  secret?: boolean;
1105
+ /** 自建服务会定稿此字段,默认模式允许尚未生成。 */
1106
+ managed?: boolean;
970
1107
  /** 交互校验类型;端口范围为 1–65535。 */
971
1108
  kind?: 'port' | 'boolean' | 'number' | 'url';
972
1109
  /** 数值下限;未声明时为 0。 */
@@ -991,6 +1128,26 @@ interface MiddlewareBackend {
991
1128
  purpose: Parameters<typeof deployM>[0];
992
1129
  /** 云自动开通器;缺失表示不能自动开通该云服务。 */
993
1130
  provisioner?: 'neon' | 'upstash' | 'cloudflare-r2' | 'resend' | 'aliyun';
1131
+ /** 云凭据字段,由所属开通器 Schema 派生。 */
1132
+ cloudFields?: string[];
1133
+ /** 是否支持容器自动创建;省略为支持。 */
1134
+ containerSupported?: boolean;
1135
+ /** 自建容器的可选实现,配置位置属于 deploy.container。 */
1136
+ containerOptions?: Array<{
1137
+ /** deploy.container 中的字段。 */
1138
+ field: string;
1139
+ /** 对应细项环境变量。 */
1140
+ variable: string;
1141
+ /** 输入提示的消息键。 */
1142
+ purpose: Parameters<typeof deployM>[0];
1143
+ /** 未配置时的选择。 */
1144
+ defaultValue: string;
1145
+ /** 可选实现。 */
1146
+ choices: Array<{
1147
+ label: string; /** 配置值。 */
1148
+ value: string;
1149
+ }>;
1150
+ }>;
994
1151
  /** 自定义连接需要逐项输入的字段。 */
995
1152
  fields: MiddlewareField[];
996
1153
  }
@@ -1018,10 +1175,91 @@ declare const DEPLOY_MIDDLEWARE: Record<ServiceType, MiddlewareBackend[]>;
1018
1175
  * }
1019
1176
  * ```
1020
1177
  */
1021
- declare function describeMiddlewareBackend(backend: MiddlewareBackend): string;
1178
+ declare function describeMiddlewareBackend(backend: Pick<MiddlewareBackend, 'purpose'>): string;
1179
+
1180
+ /** 中间件表单值与模块配置之间的部署适配;CLI 仅收集输入,不解释模块字段。 */
1181
+
1182
+ /**
1183
+ * 判断目标模式是否显式配置了所选连接,凭据可来自更高优先级的私有来源。
1184
+ * @param requirement - 扫描得到的连接需求。
1185
+ * @param backend - 选择的后端及连接字段目录。
1186
+ * @param environment - 合并值与目标文件的原始值。
1187
+ * @returns 目标环境的公开或私有文件声明后端和必要连接字段时为 true。
1188
+ * @example
1189
+ * ```ts
1190
+ * import { canKeepMiddleware, DEPLOY_MIDDLEWARE } from '@h-ai/deploy'
1191
+ * const keep = canKeepMiddleware({ service: 'cache', backend: 'memory', source: 'cache', configName: 'cache', configPath: [], envPrefix: 'HAI_CACHE', config: {} }, DEPLOY_MIDDLEWARE.cache[0]!, { environment: 'test', envDir: '.', values: {}, targetValues: { HAI_CACHE_TYPE: 'memory' } })
1192
+ * ```
1193
+ */
1194
+ declare function canKeepMiddleware(requirement: MiddlewareRequirement, backend: MiddlewareBackend, environment: DeploymentEnvironment): boolean;
1195
+ /**
1196
+ * 校验部署连接字段,TLS 复用数据库模块的公开 Schema。
1197
+ * @param options - 原始值、字段定义及实际后端。
1198
+ * @param options.value - 字面输入值。
1199
+ * @param options.field - 已声明的连接字段。
1200
+ * @param options.backend - 实际后端名称。
1201
+ * @returns 输入有效时为 true,不包含输入值或凭据。
1202
+ * @example
1203
+ * ```ts
1204
+ * import { validateMiddlewareField } from '@h-ai/deploy'
1205
+ * const valid = validateMiddlewareField({ value: '5432', field: { name: 'port', kind: 'port' }, backend: 'postgresql' })
1206
+ * ```
1207
+ */
1208
+ declare function validateMiddlewareField(options: {
1209
+ value: string;
1210
+ field: MiddlewareField;
1211
+ backend: string;
1212
+ }): boolean;
1213
+ /**
1214
+ * 将已校验表单值还原为连接字段类型,不进行 dotenv 序列化。
1215
+ * @param options - 输入值、字段和后端。
1216
+ * @param options.value - 字面输入值。
1217
+ * @param options.field - 已声明的连接字段。
1218
+ * @param options.backend - 实际后端名称。
1219
+ * @param options.managed - 默认开通时允许托管秘密尚未生成。
1220
+ * @returns 类型化值或配置错误;空值表示移除该可选字段。
1221
+ * @example
1222
+ * ```ts
1223
+ * import { parseMiddlewareField } from '@h-ai/deploy'
1224
+ * const parsed = parseMiddlewareField({ value: 'false', field: { name: 'secure', kind: 'boolean' }, backend: 'smtp' })
1225
+ * if (!parsed.success) throw new Error(parsed.error.message)
1226
+ * ```
1227
+ */
1228
+ declare function parseMiddlewareField(options: {
1229
+ value: string;
1230
+ field: MiddlewareField;
1231
+ backend: string;
1232
+ managed?: boolean;
1233
+ }): HaiResult<unknown>;
1234
+ /**
1235
+ * 保存选择后的完整连接,声明配置节点并清理该模式中被替换的旧连接字段。
1236
+ * @param environment - 目标环境快照,不修改进程环境。
1237
+ * @param options - 应用目录、扫描需求、后端、可选连接和其他生成项。
1238
+ * @param options.appDir - 应用配置文件所在根目录。
1239
+ * @param options.requirement - 扫描的中间件配置路径。
1240
+ * @param options.backend - 选定的后端。
1241
+ * @param options.configuration - 本次完整连接;云开通前可不提供。
1242
+ * @param options.updates - 同次选择需要保存的其他配置。
1243
+ * @returns 实际写入的变量名;错误不包含配置值。
1244
+ * @example
1245
+ * ```ts
1246
+ * import { loadDeploymentEnvironment, saveMiddlewareEnvironment } from '@h-ai/deploy'
1247
+ * const loaded = loadDeploymentEnvironment({ environment: 'test', envDir: process.cwd() })
1248
+ * if (!loaded.success) throw new Error(loaded.error.message)
1249
+ * const saved = saveMiddlewareEnvironment(loaded.data, { appDir: process.cwd(), requirement: { service: 'cache', backend: 'memory', source: 'cache', configName: 'cache', configPath: [], envPrefix: 'HAI_CACHE', config: {} }, backend: 'memory', configuration: { type: 'memory' } })
1250
+ * ```
1251
+ */
1252
+ declare function saveMiddlewareEnvironment(environment: DeploymentEnvironment, options: {
1253
+ appDir: string;
1254
+ requirement: MiddlewareRequirement;
1255
+ backend: string;
1256
+ configuration?: Record<string, unknown>;
1257
+ updates?: Record<string, unknown>;
1258
+ }): HaiResult<string[]>;
1022
1259
 
1023
1260
  /**
1024
1261
  * 查看与执行入口相同的扫描、环境、项目身份和制品校验结果。远端 current 只报告为待执行时核验。
1262
+ * 输出 root 是工程根,serviceDir 是读取运行配置、扫描依赖的部署服务目录。
1025
1263
  * @example
1026
1264
  * ```ts
1027
1265
  * import { createDeploymentPlan } from '@h-ai/deploy'
@@ -1038,7 +1276,7 @@ declare function createDeploymentPlan(appDir: string, input: DeployConfigInput,
1038
1276
  data: {
1039
1277
  projectName: string;
1040
1278
  root: string;
1041
- appDir: string;
1279
+ serviceDir: string;
1042
1280
  environment: string;
1043
1281
  target: {
1044
1282
  provider: "docker-ssh";
@@ -1047,6 +1285,11 @@ declare function createDeploymentPlan(appDir: string, input: DeployConfigInput,
1047
1285
  directory: string | undefined;
1048
1286
  runtime: "auto" | "docker" | "podman";
1049
1287
  hostPort: number;
1288
+ https: {
1289
+ type: "files" | "letsencrypt";
1290
+ domain: string;
1291
+ port: number;
1292
+ } | undefined;
1050
1293
  } | {
1051
1294
  provider: "vercel";
1052
1295
  host?: undefined;
@@ -1054,6 +1297,7 @@ declare function createDeploymentPlan(appDir: string, input: DeployConfigInput,
1054
1297
  directory?: undefined;
1055
1298
  runtime?: undefined;
1056
1299
  hostPort?: undefined;
1300
+ https?: undefined;
1057
1301
  };
1058
1302
  artifact: {
1059
1303
  directory: string;
@@ -1156,4 +1400,5 @@ declare function importDeploymentSecrets(options: {
1156
1400
  changed: boolean;
1157
1401
  }>>;
1158
1402
 
1159
- 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, createDeploymentPlan, deploy, describeMiddlewareBackend, getDeployCommandState, getDeployRecovery, importDeploymentSecrets, loadDeploymentConfig, loadDeploymentEnvironment, mergeEnvironmentLayers, normalizeProjectName, readDeploymentArtifact, saveDeploymentEnvironment };
1403
+ export { DEPLOY_MIDDLEWARE, DeployConfigSchema, DeploymentArtifactSchema, HaiDeployError, ProviderConfigSchema, artifactChecksum, canKeepMiddleware, createDeploymentPlan, deploy, describeMiddlewareBackend, getDeployCommandState, getDeployRecovery, importDeploymentSecrets, loadDeploymentConfig, loadDeploymentEnvironment, mergeEnvironmentLayers, normalizeProjectName, parseMiddlewareField, readDeploymentArtifact, resolveDownloadProxy, resolveImageReference, saveDeploymentEnvironment, saveMiddlewareEnvironment, validateMiddlewareField };
1404
+ export type { DeployAppOptions, DeployCommandState, DeployConfig, DeployConfigInput, DeployCredentialOperations, DeployError, DeployFunctions, DeployRecoveryInfo, DeployResult, DeployScanOptions, DeploymentArtifact, DeploymentEnvironment, DockerSshProviderConfig, DownloadProxyConfig, ImageSourceConfig, MiddlewareBackend, MiddlewareField, MiddlewareMode, MiddlewareRequirement, PortExposeConfig, ProvisionResult, ScanResult, ServiceType, SshConfig };