@h-ai/deploy 0.1.0-alpha.53 → 0.1.0-alpha.55
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.md +14 -8
- package/dist/index.d.ts +23 -2
- package/dist/index.js +125 -85
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## 支持的服务
|
|
6
6
|
|
|
7
|
-
| 服务类型 | Provisioner | 说明
|
|
8
|
-
| -------- | ------------- |
|
|
9
|
-
| 部署 | Vercel | SvelteKit 应用部署
|
|
10
|
-
| 数据库 | Neon | PostgreSQL Serverless
|
|
11
|
-
| 缓存 | Upstash | Redis
|
|
12
|
-
| 存储 | Cloudflare R2 | S3 兼容对象存储
|
|
13
|
-
| 邮件 | Resend |
|
|
14
|
-
| 短信 | 阿里云 | 阿里云短信服务
|
|
7
|
+
| 服务类型 | Provisioner | 说明 |
|
|
8
|
+
| -------- | ------------- | ---------------------- |
|
|
9
|
+
| 部署 | Vercel | SvelteKit 应用部署 |
|
|
10
|
+
| 数据库 | Neon | PostgreSQL Serverless |
|
|
11
|
+
| 缓存 | Upstash | Redis TCP + TLS |
|
|
12
|
+
| 存储 | Cloudflare R2 | S3 兼容对象存储 |
|
|
13
|
+
| 邮件 | Resend | SMTP(已有已验证域名) |
|
|
14
|
+
| 短信 | 阿里云 | 阿里云短信服务 |
|
|
15
15
|
|
|
16
16
|
## 快速开始
|
|
17
17
|
|
|
@@ -115,3 +115,9 @@ pnpm --filter @h-ai/deploy test
|
|
|
115
115
|
## License
|
|
116
116
|
|
|
117
117
|
Apache-2.0
|
|
118
|
+
|
|
119
|
+
云资源配置消费:Neon 输出 HAI_DB(PostgreSQL JSON),Upstash 输出 HAI_CACHE(Redis rediss URL JSON),R2 输出 HAI_STORAGE(扁平 S3 JSON)。邮件/短信输出 HAI_REACH_PROVIDERS 数组,deployApp 合并两个渠道并保留 YAML 中的消息模板;此覆盖替换原 providers 数组。Core 支持整体对象/数组覆盖,父节点优先于叶子变量,仍执行 Schema 校验;构建子进程与目标运行环境使用相同开通结果。R2 必须提供已有 S3 accessKeyId/secretAccessKey;Resend 必须提供已验证域名的 from;阿里云必须提供已审核 signName/模板。应用须已有相应\_db/\_cache/\_storage/\_reach.yml 并在启动时加载,网络客户端需要 Node 运行时。
|
|
120
|
+
|
|
121
|
+
配置依据:[Upstash TLS](https://upstash.com/docs/redis/features/security)、[Resend SMTP](https://resend.com/docs/send-with-smtp)。确定性验收真实生成应用并通过 Core 和各模块 Schema;未创建云资源、未发送邮件/短信,不能据此声称云端写入读取已验收。
|
|
122
|
+
|
|
123
|
+
部署失败恢复:`ProvisionResult.resourceStatus` 标记 created/reused;`getDeployRecovery(result.error)` 读取 projectName、stage、platformProjectId 和资源清单,unknown 表示请求结果不确定,必须先在服务商控制台核对。失败资源已返回 ID 时保留该 ID。恢复结果不含 envVars、原始异常或连接凭证,CLI 会展示清单和建议。同名重试复用现有资源;不自动删除复用资源,新建资源仅在人工确认未被使用后清理。
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import * as _h_ai_core from '@h-ai/core';
|
|
3
|
-
import { HaiResult } from '@h-ai/core';
|
|
3
|
+
import { HaiResult, HaiError } from '@h-ai/core';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @h-ai/deploy — 部署配置 Schema
|
|
@@ -32,15 +32,19 @@ declare const DeployConfigSchema: z.ZodObject<{
|
|
|
32
32
|
}, z.core.$strip>], "provisioner">>;
|
|
33
33
|
storage: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
34
34
|
provisioner: z.ZodLiteral<"cloudflare-r2">;
|
|
35
|
+
accessKeyId: z.ZodString;
|
|
36
|
+
secretAccessKey: z.ZodString;
|
|
35
37
|
accountId: z.ZodString;
|
|
36
38
|
apiToken: z.ZodString;
|
|
37
39
|
}, z.core.$strip>], "provisioner">>;
|
|
38
40
|
email: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
39
41
|
provisioner: z.ZodLiteral<"resend">;
|
|
42
|
+
from: z.ZodString;
|
|
40
43
|
apiKey: z.ZodString;
|
|
41
44
|
}, z.core.$strip>], "provisioner">>;
|
|
42
45
|
sms: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
43
46
|
provisioner: z.ZodLiteral<"aliyun">;
|
|
47
|
+
signName: z.ZodString;
|
|
44
48
|
accessKeyId: z.ZodString;
|
|
45
49
|
accessKeySecret: z.ZodString;
|
|
46
50
|
}, z.core.$strip>], "provisioner">>;
|
|
@@ -129,6 +133,8 @@ interface DeployResult {
|
|
|
129
133
|
* 由 Provisioner 开通服务后返回,包含要注入到部署平台的环境变量。
|
|
130
134
|
*/
|
|
131
135
|
interface ProvisionResult {
|
|
136
|
+
/** 本次新建或复用;凭证型服务始终为 reused */
|
|
137
|
+
resourceStatus: 'created' | 'reused';
|
|
132
138
|
/** 服务类型 */
|
|
133
139
|
serviceType: ServiceType;
|
|
134
140
|
/** Provisioner 名称 */
|
|
@@ -138,6 +144,18 @@ interface ProvisionResult {
|
|
|
138
144
|
/** 资源标识信息(如项目名、数据库名等),用于日志和展示 */
|
|
139
145
|
resourceInfo: string;
|
|
140
146
|
}
|
|
147
|
+
/** 部署失败后的安全恢复信息,不含环境变量值或原始异常。 */
|
|
148
|
+
interface DeployRecoveryInfo {
|
|
149
|
+
projectName: string;
|
|
150
|
+
stage: string;
|
|
151
|
+
platformProjectId?: string;
|
|
152
|
+
resources: Array<{
|
|
153
|
+
serviceType: ServiceType;
|
|
154
|
+
provisionerName: string;
|
|
155
|
+
resourceInfo: string;
|
|
156
|
+
resourceStatus: 'created' | 'reused' | 'unknown';
|
|
157
|
+
}>;
|
|
158
|
+
}
|
|
141
159
|
/** 部署选项 */
|
|
142
160
|
interface DeployAppOptions {
|
|
143
161
|
/** 项目名称(默认从 package.json name 提取) */
|
|
@@ -241,4 +259,7 @@ interface DeployFunctions {
|
|
|
241
259
|
*/
|
|
242
260
|
declare const deploy: DeployFunctions;
|
|
243
261
|
|
|
244
|
-
|
|
262
|
+
/** 读取错误中的恢复清单;仅返回明确允许展示的字段。 */
|
|
263
|
+
declare function getDeployRecovery(error: HaiError): DeployRecoveryInfo | undefined;
|
|
264
|
+
|
|
265
|
+
export { type DeployAppOptions, type DeployConfig, type DeployConfigInput, DeployConfigSchema, type DeployCredentialOperations, type DeployError, type DeployFunctions, type DeployRecoveryInfo, type DeployResult, HaiDeployError, ProviderConfigSchema, type ProvisionResult, type ScanResult, type ServiceType, deploy, getDeployRecovery };
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,9 @@ var en_US_default = {
|
|
|
36
36
|
deploy_credentialMissing: "Missing credential fields: {fields}",
|
|
37
37
|
deploy_apiError: "{service} API error ({status})",
|
|
38
38
|
deploy_fileUploadFailed: "File upload failed ({status})",
|
|
39
|
-
deploy_provisionNoResult: "No connection info returned from {service}"
|
|
39
|
+
deploy_provisionNoResult: "No connection info returned from {service}",
|
|
40
|
+
deploy_recoveryFailure: "Deployment stopped at {stage}; inspect the recovery details.",
|
|
41
|
+
deploy_recoverySuggestion: "Inspect listed resources in the provider console before retrying with the same project name. Unknown means the request may have created a resource. Reused resources are never deleted automatically; remove newly created resources manually only after checking their use."
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
// messages/zh-CN.json
|
|
@@ -64,7 +66,9 @@ var zh_CN_default = {
|
|
|
64
66
|
deploy_credentialMissing: "\u7F3A\u5C11\u51ED\u8BC1\u5B57\u6BB5\uFF1A{fields}",
|
|
65
67
|
deploy_apiError: "{service} API \u8BF7\u6C42\u5931\u8D25\uFF08{status}\uFF09",
|
|
66
68
|
deploy_fileUploadFailed: "\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF08{status}\uFF09",
|
|
67
|
-
deploy_provisionNoResult: "{service} \u672A\u8FD4\u56DE\u8FDE\u63A5\u4FE1\u606F"
|
|
69
|
+
deploy_provisionNoResult: "{service} \u672A\u8FD4\u56DE\u8FDE\u63A5\u4FE1\u606F",
|
|
70
|
+
deploy_recoveryFailure: "\u90E8\u7F72\u5728 {stage} \u9636\u6BB5\u505C\u6B62\uFF0C\u8BF7\u67E5\u770B\u6062\u590D\u6E05\u5355\u3002",
|
|
71
|
+
deploy_recoverySuggestion: "\u91CD\u8BD5\u524D\u5728\u670D\u52A1\u5546\u63A7\u5236\u53F0\u6838\u5BF9\u6E05\u5355\uFF0C\u5E76\u4F7F\u7528\u76F8\u540C\u9879\u76EE\u540D\u3002unknown \u8868\u793A\u8BF7\u6C42\u53EF\u80FD\u5DF2\u521B\u5EFA\u8D44\u6E90\u3002\u590D\u7528\u8D44\u6E90\u4E0D\u4F1A\u81EA\u52A8\u5220\u9664\uFF1B\u65B0\u5EFA\u8D44\u6E90\u4EC5\u5728\u786E\u8BA4\u672A\u88AB\u4F7F\u7528\u540E\u4EBA\u5DE5\u6E05\u7406\u3002"
|
|
68
72
|
};
|
|
69
73
|
|
|
70
74
|
// src/deploy-i18n.ts
|
|
@@ -92,15 +96,19 @@ var UpstashServiceSchema = z.object({
|
|
|
92
96
|
});
|
|
93
97
|
var R2ServiceSchema = z.object({
|
|
94
98
|
provisioner: z.literal("cloudflare-r2"),
|
|
99
|
+
accessKeyId: z.string().min(1),
|
|
100
|
+
secretAccessKey: z.string().min(1),
|
|
95
101
|
accountId: z.string().min(1),
|
|
96
102
|
apiToken: z.string().min(1)
|
|
97
103
|
});
|
|
98
104
|
var ResendServiceSchema = z.object({
|
|
99
105
|
provisioner: z.literal("resend"),
|
|
106
|
+
from: z.string().email(),
|
|
100
107
|
apiKey: z.string().min(1)
|
|
101
108
|
});
|
|
102
109
|
var AliyunSmsServiceSchema = z.object({
|
|
103
110
|
provisioner: z.literal("aliyun"),
|
|
111
|
+
signName: z.string().min(1),
|
|
104
112
|
accessKeyId: z.string().min(1),
|
|
105
113
|
accessKeySecret: z.string().min(1)
|
|
106
114
|
});
|
|
@@ -255,13 +263,13 @@ function saveCredentials(entries) {
|
|
|
255
263
|
}
|
|
256
264
|
}
|
|
257
265
|
var logger2 = core.logger.child({ module: "deploy", scope: "functions" });
|
|
258
|
-
function buildApp(appDir, buildCommand) {
|
|
266
|
+
function buildApp(appDir, buildCommand, envVars = {}) {
|
|
259
267
|
logger2.info("Building application", { appDir, buildCommand });
|
|
260
268
|
try {
|
|
261
269
|
execSync(buildCommand, {
|
|
262
270
|
cwd: appDir,
|
|
263
271
|
stdio: "inherit",
|
|
264
|
-
env: { ...process.env }
|
|
272
|
+
env: { ...process.env, ...envVars }
|
|
265
273
|
});
|
|
266
274
|
return ok(void 0);
|
|
267
275
|
} catch (error) {
|
|
@@ -287,6 +295,32 @@ function resolveOutputDir(appDir, providerType) {
|
|
|
287
295
|
return join(appDir, "build");
|
|
288
296
|
}
|
|
289
297
|
}
|
|
298
|
+
var RecoverySchema = z.object({
|
|
299
|
+
projectName: z.string(),
|
|
300
|
+
stage: z.string(),
|
|
301
|
+
platformProjectId: z.string().optional(),
|
|
302
|
+
resources: z.array(z.object({
|
|
303
|
+
serviceType: z.enum(["db", "cache", "storage", "email", "sms"]),
|
|
304
|
+
provisionerName: z.string(),
|
|
305
|
+
resourceInfo: z.string(),
|
|
306
|
+
resourceStatus: z.enum(["created", "reused", "unknown"])
|
|
307
|
+
}))
|
|
308
|
+
});
|
|
309
|
+
function getDeployRecovery(error) {
|
|
310
|
+
const parsed = RecoverySchema.safeParse(error.ext?.recovery);
|
|
311
|
+
return parsed.success ? parsed.data : void 0;
|
|
312
|
+
}
|
|
313
|
+
function recoveryFailure(error, recovery) {
|
|
314
|
+
return err({
|
|
315
|
+
code: error.code,
|
|
316
|
+
httpStatus: error.httpStatus,
|
|
317
|
+
system: error.system,
|
|
318
|
+
module: error.module,
|
|
319
|
+
message: deployM("deploy_recoveryFailure", { params: { stage: recovery.stage } }),
|
|
320
|
+
suggestion: deployM("deploy_recoverySuggestion"),
|
|
321
|
+
ext: { recovery }
|
|
322
|
+
});
|
|
323
|
+
}
|
|
290
324
|
var logger3 = core.logger.child({ module: "deploy", scope: "scanner" });
|
|
291
325
|
function readYaml(filePath) {
|
|
292
326
|
if (!existsSync(filePath)) {
|
|
@@ -698,6 +732,7 @@ var logger5 = core.logger.child({ module: "deploy", scope: "provisioner-aliyun"
|
|
|
698
732
|
function createAliyunProvisioner() {
|
|
699
733
|
let accessKey = null;
|
|
700
734
|
let secretKey = null;
|
|
735
|
+
let signName = "";
|
|
701
736
|
return {
|
|
702
737
|
name: "aliyun",
|
|
703
738
|
serviceType: "sms",
|
|
@@ -706,11 +741,12 @@ function createAliyunProvisioner() {
|
|
|
706
741
|
try {
|
|
707
742
|
const akId = credentials.accessKeyId ?? credentials.access_key_id ?? credentials.access_key ?? "";
|
|
708
743
|
const akSecret = credentials.accessKeySecret ?? credentials.access_key_secret ?? credentials.secret_key ?? "";
|
|
709
|
-
if (!akId || !akSecret) {
|
|
710
|
-
throw new Error(deployM("deploy_credentialMissing", { params: { fields: "
|
|
744
|
+
if (!akId || !akSecret || !credentials.signName) {
|
|
745
|
+
throw new Error(deployM("deploy_credentialMissing", { params: { fields: "accessKeyId, accessKeySecret, signName" } }));
|
|
711
746
|
}
|
|
712
747
|
accessKey = akId;
|
|
713
748
|
secretKey = akSecret;
|
|
749
|
+
signName = credentials.signName;
|
|
714
750
|
logger5.info("Aliyun authenticated", { accessKeyId: `${akId.slice(0, 6)}***` });
|
|
715
751
|
return ok(akId);
|
|
716
752
|
} catch (error) {
|
|
@@ -735,9 +771,9 @@ function createAliyunProvisioner() {
|
|
|
735
771
|
return ok({
|
|
736
772
|
serviceType: "sms",
|
|
737
773
|
provisionerName: "aliyun",
|
|
774
|
+
resourceStatus: "reused",
|
|
738
775
|
envVars: {
|
|
739
|
-
|
|
740
|
-
HAI_REACH_SMS_SECRET_KEY: secretKey
|
|
776
|
+
HAI_REACH_PROVIDERS: JSON.stringify([{ name: "sms", type: "aliyun-sms", accessKeyId: accessKey, accessKeySecret: secretKey, signName }])
|
|
741
777
|
},
|
|
742
778
|
resourceInfo: "aliyun:verify-only"
|
|
743
779
|
});
|
|
@@ -786,12 +822,13 @@ async function getNeonConnectionUri(token, projectId) {
|
|
|
786
822
|
}
|
|
787
823
|
return data.uri;
|
|
788
824
|
}
|
|
789
|
-
function buildNeonProvisionResult(projectId, connectionUri) {
|
|
825
|
+
function buildNeonProvisionResult(projectId, connectionUri, resourceStatus) {
|
|
790
826
|
return {
|
|
791
827
|
serviceType: "db",
|
|
792
828
|
provisionerName: "neon",
|
|
829
|
+
resourceStatus,
|
|
793
830
|
envVars: {
|
|
794
|
-
|
|
831
|
+
HAI_DB: JSON.stringify({ type: "postgresql", url: connectionUri, database: decodeURIComponent(new URL(connectionUri).pathname.slice(1)) })
|
|
795
832
|
},
|
|
796
833
|
resourceInfo: `neon-project:${projectId}`
|
|
797
834
|
};
|
|
@@ -831,16 +868,18 @@ function createNeonProvisioner() {
|
|
|
831
868
|
);
|
|
832
869
|
}
|
|
833
870
|
logger6.debug("Provisioning Neon database", { appName });
|
|
871
|
+
let resource;
|
|
834
872
|
try {
|
|
835
873
|
const projectName = `${appName}-db`;
|
|
836
874
|
const existingProject = await findExistingNeonProject(token, projectName);
|
|
837
875
|
if (existingProject !== null) {
|
|
876
|
+
resource = { resourceInfo: `neon-project:${existingProject.id}`, resourceStatus: "reused" };
|
|
838
877
|
const connectionUri2 = await getNeonConnectionUri(token, existingProject.id);
|
|
839
878
|
logger6.info("Neon project reused", {
|
|
840
879
|
projectId: existingProject.id,
|
|
841
880
|
projectName
|
|
842
881
|
});
|
|
843
|
-
return ok(buildNeonProvisionResult(existingProject.id, connectionUri2));
|
|
882
|
+
return ok(buildNeonProvisionResult(existingProject.id, connectionUri2, "reused"));
|
|
844
883
|
}
|
|
845
884
|
const data = await neonFetch(token, "/projects", {
|
|
846
885
|
method: "POST",
|
|
@@ -852,14 +891,23 @@ function createNeonProvisioner() {
|
|
|
852
891
|
})
|
|
853
892
|
});
|
|
854
893
|
const projectId = data.project?.id ?? "";
|
|
894
|
+
if (projectId)
|
|
895
|
+
resource = { resourceInfo: `neon-project:${projectId}`, resourceStatus: "created" };
|
|
855
896
|
const connectionUri = data.connection_uris?.[0]?.connection_uri ?? "";
|
|
856
897
|
if (!projectId || !connectionUri) {
|
|
857
898
|
throw new Error(deployM("deploy_provisionNoResult", { params: { service: "Neon" } }));
|
|
858
899
|
}
|
|
859
900
|
logger6.info("Neon database provisioned", { projectId });
|
|
860
|
-
return ok(buildNeonProvisionResult(projectId, connectionUri));
|
|
901
|
+
return ok(buildNeonProvisionResult(projectId, connectionUri, "created"));
|
|
861
902
|
} catch (error) {
|
|
862
|
-
logger6.error("Neon provisioning failed", { appName
|
|
903
|
+
logger6.error("Neon provisioning failed", { appName });
|
|
904
|
+
if (resource) {
|
|
905
|
+
return recoveryFailure({ ...HaiDeployError.PROVISION_FAILED}, {
|
|
906
|
+
projectName: appName,
|
|
907
|
+
stage: "provision:db",
|
|
908
|
+
resources: [{ serviceType: "db", provisionerName: "neon", ...resource }]
|
|
909
|
+
});
|
|
910
|
+
}
|
|
863
911
|
return err(
|
|
864
912
|
HaiDeployError.PROVISION_FAILED,
|
|
865
913
|
deployM("deploy_provisionFailed", {
|
|
@@ -879,6 +927,8 @@ var CF_API = "https://api.cloudflare.com/client/v4";
|
|
|
879
927
|
function createR2Provisioner() {
|
|
880
928
|
let token = null;
|
|
881
929
|
let accountId = null;
|
|
930
|
+
let accessKey = "";
|
|
931
|
+
let secretKey = "";
|
|
882
932
|
return {
|
|
883
933
|
name: "r2",
|
|
884
934
|
serviceType: "storage",
|
|
@@ -887,8 +937,8 @@ function createR2Provisioner() {
|
|
|
887
937
|
try {
|
|
888
938
|
const acctId = credentials.accountId ?? credentials.account_id ?? "";
|
|
889
939
|
const apiTok = credentials.apiToken ?? credentials.api_token ?? credentials.token ?? "";
|
|
890
|
-
if (!acctId || !apiTok) {
|
|
891
|
-
throw new Error(deployM("deploy_credentialMissing", { params: { fields: "
|
|
940
|
+
if (!acctId || !apiTok || !credentials.accessKeyId || !credentials.secretAccessKey) {
|
|
941
|
+
throw new Error(deployM("deploy_credentialMissing", { params: { fields: "accountId, apiToken, accessKeyId, secretAccessKey" } }));
|
|
892
942
|
}
|
|
893
943
|
const res = await fetch(`${CF_API}/accounts/${acctId}/r2/buckets`, {
|
|
894
944
|
headers: { Authorization: `Bearer ${apiTok}` }
|
|
@@ -898,6 +948,8 @@ function createR2Provisioner() {
|
|
|
898
948
|
}
|
|
899
949
|
accountId = acctId;
|
|
900
950
|
token = apiTok;
|
|
951
|
+
accessKey = credentials.accessKeyId;
|
|
952
|
+
secretKey = credentials.secretAccessKey;
|
|
901
953
|
logger7.info("Cloudflare R2 authenticated", { accountId: acctId });
|
|
902
954
|
return ok(acctId);
|
|
903
955
|
} catch (error) {
|
|
@@ -935,42 +987,20 @@ function createR2Provisioner() {
|
|
|
935
987
|
if (!createRes.ok && createRes.status !== 409) {
|
|
936
988
|
throw new Error(deployM("deploy_apiError", { params: { service: "Cloudflare", status: String(createRes.status) } }));
|
|
937
989
|
}
|
|
938
|
-
const tokenRes = await fetch(
|
|
939
|
-
`${CF_API}/user/tokens`,
|
|
940
|
-
{
|
|
941
|
-
method: "POST",
|
|
942
|
-
headers: {
|
|
943
|
-
"Authorization": `Bearer ${token}`,
|
|
944
|
-
"Content-Type": "application/json"
|
|
945
|
-
},
|
|
946
|
-
body: JSON.stringify({
|
|
947
|
-
name: `${appName}-r2-token`,
|
|
948
|
-
policies: [{
|
|
949
|
-
effect: "allow",
|
|
950
|
-
permission_groups: [{ id: "r2-read-write" }],
|
|
951
|
-
resources: { [`com.cloudflare.edge.r2.bucket.${accountId}_default_${bucketName}`]: "*" }
|
|
952
|
-
}]
|
|
953
|
-
})
|
|
954
|
-
}
|
|
955
|
-
);
|
|
956
|
-
if (!tokenRes.ok) {
|
|
957
|
-
throw new Error(deployM("deploy_apiError", { params: { service: "Cloudflare", status: String(tokenRes.status) } }));
|
|
958
|
-
}
|
|
959
|
-
const tokenData = await tokenRes.json();
|
|
960
|
-
const accessKey = tokenData.result?.id ?? "";
|
|
961
|
-
const secretKey = tokenData.result?.value ?? "";
|
|
962
|
-
if (!accessKey || !secretKey) {
|
|
963
|
-
throw new Error(deployM("deploy_provisionNoResult", { params: { service: "Cloudflare R2" } }));
|
|
964
|
-
}
|
|
965
990
|
logger7.info("R2 bucket provisioned", { bucketName });
|
|
966
991
|
return ok({
|
|
967
992
|
serviceType: "storage",
|
|
968
993
|
provisionerName: "r2",
|
|
994
|
+
resourceStatus: createRes.status === 409 ? "reused" : "created",
|
|
969
995
|
envVars: {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
996
|
+
HAI_STORAGE: JSON.stringify({
|
|
997
|
+
type: "s3",
|
|
998
|
+
endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
|
|
999
|
+
bucket: bucketName,
|
|
1000
|
+
region: "auto",
|
|
1001
|
+
accessKeyId: accessKey,
|
|
1002
|
+
secretAccessKey: secretKey
|
|
1003
|
+
})
|
|
974
1004
|
},
|
|
975
1005
|
resourceInfo: `r2-bucket:${bucketName}`
|
|
976
1006
|
});
|
|
@@ -994,6 +1024,7 @@ var logger8 = core.logger.child({ module: "deploy", scope: "provisioner-resend"
|
|
|
994
1024
|
var RESEND_API = "https://api.resend.com";
|
|
995
1025
|
function createResendProvisioner() {
|
|
996
1026
|
let token = null;
|
|
1027
|
+
let from = "";
|
|
997
1028
|
return {
|
|
998
1029
|
name: "resend",
|
|
999
1030
|
serviceType: "email",
|
|
@@ -1001,8 +1032,8 @@ function createResendProvisioner() {
|
|
|
1001
1032
|
logger8.debug("Authenticating with Resend");
|
|
1002
1033
|
try {
|
|
1003
1034
|
const apiToken = credentials.apiKey ?? credentials.api_key ?? credentials.token ?? "";
|
|
1004
|
-
if (!apiToken) {
|
|
1005
|
-
throw new Error(deployM("deploy_credentialMissing", { params: { fields: "
|
|
1035
|
+
if (!apiToken || !credentials.from) {
|
|
1036
|
+
throw new Error(deployM("deploy_credentialMissing", { params: { fields: "apiKey, from" } }));
|
|
1006
1037
|
}
|
|
1007
1038
|
const res = await fetch(`${RESEND_API}/domains`, {
|
|
1008
1039
|
headers: { Authorization: `Bearer ${apiToken}` }
|
|
@@ -1011,6 +1042,7 @@ function createResendProvisioner() {
|
|
|
1011
1042
|
throw new Error(deployM("deploy_apiError", { params: { service: "Resend", status: String(res.status) } }));
|
|
1012
1043
|
}
|
|
1013
1044
|
token = apiToken;
|
|
1045
|
+
from = credentials.from;
|
|
1014
1046
|
logger8.info("Resend authenticated");
|
|
1015
1047
|
return ok("resend-user");
|
|
1016
1048
|
} catch (error) {
|
|
@@ -1035,8 +1067,9 @@ function createResendProvisioner() {
|
|
|
1035
1067
|
return ok({
|
|
1036
1068
|
serviceType: "email",
|
|
1037
1069
|
provisionerName: "resend",
|
|
1070
|
+
resourceStatus: "reused",
|
|
1038
1071
|
envVars: {
|
|
1039
|
-
|
|
1072
|
+
HAI_REACH_PROVIDERS: JSON.stringify([{ name: "email", type: "smtp", host: "smtp.resend.com", port: 465, secure: true, user: "resend", pass: token, from }])
|
|
1040
1073
|
},
|
|
1041
1074
|
resourceInfo: "resend:verify-only"
|
|
1042
1075
|
});
|
|
@@ -1072,38 +1105,17 @@ async function findExistingUpstashDatabase(email, apiKey, databaseName) {
|
|
|
1072
1105
|
async function getUpstashDatabase(email, apiKey, databaseId) {
|
|
1073
1106
|
return upstashFetch(email, apiKey, `/v2/redis/database/${databaseId}`);
|
|
1074
1107
|
}
|
|
1075
|
-
function
|
|
1076
|
-
if (typeof database.rest_url === "string" && database.rest_url.length > 0) {
|
|
1077
|
-
return database.rest_url;
|
|
1078
|
-
}
|
|
1079
|
-
const endpoint = database.endpoint?.trim() ?? "";
|
|
1080
|
-
if (!endpoint) {
|
|
1081
|
-
return "";
|
|
1082
|
-
}
|
|
1083
|
-
if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
|
|
1084
|
-
return endpoint;
|
|
1085
|
-
}
|
|
1086
|
-
if (endpoint.includes(".")) {
|
|
1087
|
-
return `https://${endpoint}`;
|
|
1088
|
-
}
|
|
1089
|
-
return `https://${endpoint}.upstash.io`;
|
|
1090
|
-
}
|
|
1091
|
-
function resolveUpstashRestToken(database) {
|
|
1092
|
-
return database.rest_token ?? database.token ?? database.password ?? "";
|
|
1093
|
-
}
|
|
1094
|
-
function buildUpstashProvisionResult(database) {
|
|
1108
|
+
function buildUpstashProvisionResult(database, resourceStatus) {
|
|
1095
1109
|
const databaseId = database.database_id ?? "";
|
|
1096
|
-
|
|
1097
|
-
const restToken = resolveUpstashRestToken(database);
|
|
1098
|
-
if (!databaseId || !restUrl || !restToken) {
|
|
1110
|
+
if (!databaseId || !database.endpoint || !database.password || !database.port) {
|
|
1099
1111
|
throw new Error(deployM("deploy_provisionNoResult", { params: { service: "Upstash" } }));
|
|
1100
1112
|
}
|
|
1101
1113
|
return {
|
|
1102
1114
|
serviceType: "cache",
|
|
1103
1115
|
provisionerName: "upstash",
|
|
1116
|
+
resourceStatus,
|
|
1104
1117
|
envVars: {
|
|
1105
|
-
|
|
1106
|
-
HAI_CACHE_UPSTASH_TOKEN: restToken
|
|
1118
|
+
HAI_CACHE: JSON.stringify({ type: "redis", url: `rediss://default:${encodeURIComponent(database.password)}@${database.endpoint}:${database.port}` })
|
|
1107
1119
|
},
|
|
1108
1120
|
resourceInfo: `upstash-db:${databaseId}`
|
|
1109
1121
|
};
|
|
@@ -1146,6 +1158,7 @@ function createUpstashProvisioner() {
|
|
|
1146
1158
|
);
|
|
1147
1159
|
}
|
|
1148
1160
|
logger9.debug("Provisioning Upstash Redis", { appName });
|
|
1161
|
+
let resource;
|
|
1149
1162
|
try {
|
|
1150
1163
|
const databaseName = `${appName}-cache`;
|
|
1151
1164
|
const existingDatabase = await findExistingUpstashDatabase(email, apiKey, databaseName);
|
|
@@ -1154,9 +1167,10 @@ function createUpstashProvisioner() {
|
|
|
1154
1167
|
if (!databaseId) {
|
|
1155
1168
|
throw new Error(deployM("deploy_provisionNoResult", { params: { service: "Upstash" } }));
|
|
1156
1169
|
}
|
|
1170
|
+
resource = { resourceInfo: `upstash-db:${databaseId}`, resourceStatus: "reused" };
|
|
1157
1171
|
const detail = await getUpstashDatabase(email, apiKey, databaseId);
|
|
1158
1172
|
logger9.info("Upstash Redis reused", { databaseId, databaseName });
|
|
1159
|
-
return ok(buildUpstashProvisionResult({ ...existingDatabase, ...detail }));
|
|
1173
|
+
return ok(buildUpstashProvisionResult({ ...existingDatabase, ...detail }, "reused"));
|
|
1160
1174
|
}
|
|
1161
1175
|
const data = await upstashFetch(email, apiKey, "/v2/redis/database", {
|
|
1162
1176
|
method: "POST",
|
|
@@ -1166,10 +1180,19 @@ function createUpstashProvisioner() {
|
|
|
1166
1180
|
tls: true
|
|
1167
1181
|
})
|
|
1168
1182
|
});
|
|
1183
|
+
if (data.database_id)
|
|
1184
|
+
resource = { resourceInfo: `upstash-db:${data.database_id}`, resourceStatus: "created" };
|
|
1169
1185
|
logger9.info("Upstash Redis provisioned", { databaseId: data.database_id });
|
|
1170
|
-
return ok(buildUpstashProvisionResult(data));
|
|
1186
|
+
return ok(buildUpstashProvisionResult(data, "created"));
|
|
1171
1187
|
} catch (error) {
|
|
1172
|
-
logger9.error("Upstash provisioning failed", { appName
|
|
1188
|
+
logger9.error("Upstash provisioning failed", { appName });
|
|
1189
|
+
if (resource) {
|
|
1190
|
+
return recoveryFailure({ ...HaiDeployError.PROVISION_FAILED}, {
|
|
1191
|
+
projectName: appName,
|
|
1192
|
+
stage: "provision:cache",
|
|
1193
|
+
resources: [{ serviceType: "cache", provisionerName: "upstash", ...resource }]
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1173
1196
|
return err(
|
|
1174
1197
|
HaiDeployError.PROVISION_FAILED,
|
|
1175
1198
|
deployM("deploy_provisionFailed", {
|
|
@@ -1350,9 +1373,18 @@ var deploy = {
|
|
|
1350
1373
|
logger10.error("Service provisioning failed", {
|
|
1351
1374
|
serviceType,
|
|
1352
1375
|
provisioner: provisioner.name,
|
|
1353
|
-
|
|
1376
|
+
code: provResult.error.code
|
|
1377
|
+
});
|
|
1378
|
+
return recoveryFailure(provResult.error, {
|
|
1379
|
+
projectName,
|
|
1380
|
+
stage: `provision:${serviceType}`,
|
|
1381
|
+
resources: [
|
|
1382
|
+
...results.map(({ envVars: _envVars, ...resource }) => resource),
|
|
1383
|
+
...getDeployRecovery(provResult.error)?.resources ?? [
|
|
1384
|
+
{ serviceType, provisionerName: provisioner.name, resourceInfo: projectName, resourceStatus: "unknown" }
|
|
1385
|
+
]
|
|
1386
|
+
]
|
|
1354
1387
|
});
|
|
1355
|
-
return err(provResult.error);
|
|
1356
1388
|
}
|
|
1357
1389
|
results.push(provResult.data);
|
|
1358
1390
|
logger10.info("Service provisioned", { serviceType, provisioner: provisioner.name });
|
|
@@ -1379,36 +1411,44 @@ var deploy = {
|
|
|
1379
1411
|
);
|
|
1380
1412
|
}
|
|
1381
1413
|
let allEnvVars = {};
|
|
1414
|
+
const recovery = { projectName, stage: "provision", resources: [] };
|
|
1382
1415
|
if (!options?.skipProvision) {
|
|
1383
1416
|
const provResults = await deploy.provisionAll(projectName);
|
|
1384
1417
|
if (!provResults.success) {
|
|
1385
1418
|
return err(provResults.error);
|
|
1386
1419
|
}
|
|
1420
|
+
recovery.resources = provResults.data.map(({ envVars: _envVars, ...resource }) => resource);
|
|
1421
|
+
const reachProviders = [];
|
|
1387
1422
|
for (const prov of provResults.data) {
|
|
1423
|
+
if (prov.envVars.HAI_REACH_PROVIDERS)
|
|
1424
|
+
reachProviders.push(...JSON.parse(prov.envVars.HAI_REACH_PROVIDERS));
|
|
1388
1425
|
allEnvVars = { ...allEnvVars, ...prov.envVars };
|
|
1389
1426
|
}
|
|
1427
|
+
if (reachProviders.length > 0)
|
|
1428
|
+
allEnvVars.HAI_REACH_PROVIDERS = JSON.stringify(reachProviders);
|
|
1390
1429
|
}
|
|
1391
1430
|
const projectResult = await currentProvider.createProject(projectName);
|
|
1392
1431
|
if (!projectResult.success) {
|
|
1393
|
-
return
|
|
1432
|
+
return recoveryFailure(projectResult.error, { ...recovery, stage: "create-project" });
|
|
1394
1433
|
}
|
|
1395
1434
|
const projectId = projectResult.data;
|
|
1435
|
+
recovery.platformProjectId = projectId;
|
|
1396
1436
|
if (Object.keys(allEnvVars).length > 0) {
|
|
1397
1437
|
const envResult = await currentProvider.setEnvVars(projectId, allEnvVars);
|
|
1398
1438
|
if (!envResult.success) {
|
|
1399
|
-
return
|
|
1439
|
+
return recoveryFailure(envResult.error, { ...recovery, stage: "set-env" });
|
|
1400
1440
|
}
|
|
1401
1441
|
}
|
|
1402
1442
|
if (!options?.skipBuild) {
|
|
1403
|
-
const buildResult = buildApp(appDir, scan.buildCommand);
|
|
1443
|
+
const buildResult = buildApp(appDir, scan.buildCommand, allEnvVars);
|
|
1404
1444
|
if (!buildResult.success) {
|
|
1405
|
-
return
|
|
1445
|
+
return recoveryFailure(buildResult.error, { ...recovery, stage: "build" });
|
|
1406
1446
|
}
|
|
1407
1447
|
}
|
|
1408
1448
|
const outputDir = resolveOutputDir(appDir, currentConfig?.provider.type ?? "vercel");
|
|
1409
1449
|
const deployResult = await currentProvider.deploy(projectId, outputDir);
|
|
1410
1450
|
if (!deployResult.success) {
|
|
1411
|
-
return
|
|
1451
|
+
return recoveryFailure(deployResult.error, { ...recovery, stage: "deploy" });
|
|
1412
1452
|
}
|
|
1413
1453
|
const result = {
|
|
1414
1454
|
...deployResult.data,
|
|
@@ -1423,6 +1463,6 @@ var deploy = {
|
|
|
1423
1463
|
}
|
|
1424
1464
|
};
|
|
1425
1465
|
|
|
1426
|
-
export { DeployConfigSchema, HaiDeployError, ProviderConfigSchema, deploy };
|
|
1466
|
+
export { DeployConfigSchema, HaiDeployError, ProviderConfigSchema, deploy, getDeployRecovery };
|
|
1427
1467
|
//# sourceMappingURL=index.js.map
|
|
1428
1468
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/deploy-i18n.ts","../src/deploy-config.ts","../src/deploy-types.ts","../src/deploy-credentials.ts","../src/deploy-functions.ts","../src/deploy-scanner.ts","../src/providers/deploy-provider-vercel.ts","../src/provisioners/deploy-provisioner-aliyun.ts","../src/provisioners/deploy-provisioner-neon.ts","../src/provisioners/deploy-provisioner-r2.ts","../src/provisioners/deploy-provisioner-resend.ts","../src/provisioners/deploy-provisioner-upstash.ts","../src/deploy-main.ts"],"names":["core","logger","process","ok","err","join","existsSync","readFileSync","parse","readdirSync","connectionUri"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"deploy_notInitialized\": \"Deploy module not initialized, call deploy.init() first\",\n \"deploy_initFailed\": \"Deploy module initialization failed: {error}\",\n \"deploy_unsupportedProviderType\": \"Unsupported deploy provider type: {type}\",\n \"deploy_unsupportedProvisionerType\": \"Unsupported service provisioner type: {type}\",\n \"deploy_configTokenRequired\": \"Deploy provider token is required\",\n \"deploy_authRequired\": \"Authentication required\",\n \"deploy_authFailed\": \"Authentication failed: {error}\",\n \"deploy_projectCreateFailed\": \"Project creation failed: {error}\",\n \"deploy_buildFailed\": \"Application build failed: {error}\",\n \"deploy_uploadFailed\": \"Build output upload failed: {error}\",\n \"deploy_deployFailed\": \"Deployment failed: {error}\",\n \"deploy_provisionFailed\": \"Service provisioning failed: {service} - {error}\",\n \"deploy_adapterMissing\": \"Target platform adapter not found, please install {adapter}\",\n \"deploy_scanFailed\": \"Application scan failed: {error}\",\n \"deploy_envVarFailed\": \"Environment variable setup failed: {error}\",\n \"deploy_credentialError\": \"Credential read/write failed: {error}\",\n \"deploy_credentialInvalidKey\": \"Unsupported credential key: {key}. Only HAI_DEPLOY_* keys are allowed\",\n \"deploy_credentialSaved\": \"Credentials saved\",\n \"deploy_credentialLoaded\": \"Credentials loaded\",\n \"deploy_configError\": \"Deploy config error: {error}\",\n \"deploy_credentialMissing\": \"Missing credential fields: {fields}\",\n \"deploy_apiError\": \"{service} API error ({status})\",\n \"deploy_fileUploadFailed\": \"File upload failed ({status})\",\n \"deploy_provisionNoResult\": \"No connection info returned from {service}\"\n}\n","{\n \"deploy_notInitialized\": \"Deploy 模块尚未初始化,请先调用 deploy.init()\",\n \"deploy_initFailed\": \"Deploy 模块初始化失败:{error}\",\n \"deploy_unsupportedProviderType\": \"不支持的部署平台类型:{type}\",\n \"deploy_unsupportedProvisionerType\": \"不支持的服务 Provisioner 类型:{type}\",\n \"deploy_configTokenRequired\": \"部署平台 Token 不能为空\",\n \"deploy_authRequired\": \"请先完成认证\",\n \"deploy_authFailed\": \"认证失败:{error}\",\n \"deploy_projectCreateFailed\": \"项目创建失败:{error}\",\n \"deploy_buildFailed\": \"应用构建失败:{error}\",\n \"deploy_uploadFailed\": \"构建产物上传失败:{error}\",\n \"deploy_deployFailed\": \"部署失败:{error}\",\n \"deploy_provisionFailed\": \"基础设施开通失败:{service} - {error}\",\n \"deploy_adapterMissing\": \"未检测到目标平台 adapter,请安装 {adapter}\",\n \"deploy_scanFailed\": \"应用扫描失败:{error}\",\n \"deploy_envVarFailed\": \"环境变量设置失败:{error}\",\n \"deploy_credentialError\": \"凭证读写失败:{error}\",\n \"deploy_credentialInvalidKey\": \"不支持的凭证键名:{key}。仅允许 HAI_DEPLOY_*\",\n \"deploy_credentialSaved\": \"凭证已保存\",\n \"deploy_credentialLoaded\": \"凭证已加载\",\n \"deploy_configError\": \"部署配置错误:{error}\",\n \"deploy_credentialMissing\": \"缺少凭证字段:{fields}\",\n \"deploy_apiError\": \"{service} API 请求失败({status})\",\n \"deploy_fileUploadFailed\": \"文件上传失败({status})\",\n \"deploy_provisionNoResult\": \"{service} 未返回连接信息\"\n}\n","/**\n * @h-ai/deploy — i18n\n *\n * 本文件提供部署模块的 i18n 文案访问入口。\n * @module deploy-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n// ─── i18n ───\n\n/** 部署模块文案 Key 类型 */\ntype DeployMessageKey = keyof typeof messagesZhCN\n\n/**\n * 获取部署模块文案\n *\n * @param key - 文案 Key\n * @param options - 插值参数与格式化选项\n * @returns 本地化后的文案字符串\n *\n * @example\n * ```ts\n * const text = deployM('deploy_notInitialized')\n * ```\n */\nexport const deployM = core.i18n.createMessageGetter<DeployMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n})\n","/**\n * @h-ai/deploy — 部署配置 Schema\n *\n * 本文件定义部署模块的错误码、Zod Schema 和配置类型。\n * @module deploy-config\n */\n\nimport { z } from 'zod'\nimport { deployM } from './deploy-i18n.js'\n\n// ─── Provider 配置 Schema ───\n\n/** Vercel 部署平台配置 */\nconst VercelProviderConfigSchema = z.object({\n type: z.literal('vercel'),\n token: z.string().min(1, deployM('deploy_configTokenRequired')),\n})\n\n/** 部署平台配置联合类型(后续可扩展更多平台) */\nexport const ProviderConfigSchema = z.discriminatedUnion('type', [\n VercelProviderConfigSchema,\n])\n\n// ─── Provisioner 配置 Schema ───\n\n/** Neon PostgreSQL 服务配置 */\nconst NeonServiceSchema = z.object({\n provisioner: z.literal('neon'),\n apiKey: z.string().min(1),\n})\n\n/** Upstash Redis 服务配置 */\nconst UpstashServiceSchema = z.object({\n provisioner: z.literal('upstash'),\n email: z.string().email(),\n apiKey: z.string().min(1),\n})\n\n/** Cloudflare R2 存储服务配置 */\nconst R2ServiceSchema = z.object({\n provisioner: z.literal('cloudflare-r2'),\n accountId: z.string().min(1),\n apiToken: z.string().min(1),\n})\n\n/** Resend 邮件服务配置 */\nconst ResendServiceSchema = z.object({\n provisioner: z.literal('resend'),\n apiKey: z.string().min(1),\n})\n\n/** 阿里云短信服务配置 */\nconst AliyunSmsServiceSchema = z.object({\n provisioner: z.literal('aliyun'),\n accessKeyId: z.string().min(1),\n accessKeySecret: z.string().min(1),\n})\n\n/** 基础设施服务配置 */\nconst ServicesConfigSchema = z.object({\n db: z.discriminatedUnion('provisioner', [NeonServiceSchema]).optional(),\n cache: z.discriminatedUnion('provisioner', [UpstashServiceSchema]).optional(),\n storage: z.discriminatedUnion('provisioner', [R2ServiceSchema]).optional(),\n email: z.discriminatedUnion('provisioner', [ResendServiceSchema]).optional(),\n sms: z.discriminatedUnion('provisioner', [AliyunSmsServiceSchema]).optional(),\n}).optional()\n\n// ─── 完整配置 Schema ───\n\n/** 部署模块完整配置 Schema */\nexport const DeployConfigSchema = z.object({\n provider: ProviderConfigSchema,\n services: ServicesConfigSchema,\n})\n\n/** 部署配置类型(parse 后) */\nexport type DeployConfig = z.infer<typeof DeployConfigSchema>\n\n/** 部署配置输入类型(用户输入) */\nexport type DeployConfigInput = z.input<typeof DeployConfigSchema>\n","/**\n * @h-ai/deploy — 类型定义\n *\n * 本文件定义部署模块的核心接口和类型(非配置相关)。 配置相关类型请从 deploy-config.ts 导入。\n * @module deploy-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport type { DeployConfig, DeployConfigInput } from './deploy-config.js'\nimport { core } from '@h-ai/core'\n\n// ─── 错误定义(照 @h-ai/core 范式) ───\n\nconst DeployErrorInfo = {\n DEPLOY_FAILED: '001:500',\n PROJECT_CREATE_FAILED: '002:500',\n BUILD_FAILED: '003:500',\n UPLOAD_FAILED: '004:500',\n AUTH_REQUIRED: '005:401',\n AUTH_FAILED: '006:401',\n PROVISION_FAILED: '007:500',\n ADAPTER_MISSING: '008:500',\n SCAN_FAILED: '009:500',\n NOT_INITIALIZED: '010:500',\n ENV_VAR_FAILED: '011:500',\n UNSUPPORTED_TYPE: '012:400',\n CONFIG_ERROR: '013:500',\n CREDENTIAL_ERROR: '014:500',\n} as const satisfies ErrorInfo\n\nexport const HaiDeployError = core.error.buildHaiErrorsDef('deploy', DeployErrorInfo)\n\n/**\n * 部署错误接口\n *\n * 所有部署操作返回的错误都遵循此接口。\n *\n * @example\n * ```ts\n * const result = await deploy.deployApp('./apps/my-app')\n * if (!result.success) {\n * const error: DeployError = result.error\n * // 根据 error.code 处理\n * }\n * ```\n */\nexport interface DeployError {\n /** 错误定义 */\n def: (typeof HaiDeployError)[keyof typeof HaiDeployError]\n /** 错误消息 */\n message: string\n /** 原始错误(可选) */\n cause?: unknown\n}\n\n// ─── 服务类型 ───\n\n/** 基础设施服务类型 */\nexport type ServiceType = 'db' | 'cache' | 'storage' | 'email' | 'sms'\n\n// ─── 扫描结果 ───\n\n/**\n * 应用扫描结果\n *\n * 由 scanner 分析应用目录后返回,描述应用的框架类型、依赖和部署需求。\n */\nexport interface ScanResult {\n /** 应用名称(来自 package.json name) */\n appName: string\n /** 是否为 SvelteKit 项目 */\n isSvelteKit: boolean\n /** 目标平台 adapter 是否已安装(如 @sveltejs/adapter-vercel) */\n adapterInstalled: boolean\n /** 检测到的模块依赖需要的服务列表 */\n requiredServices: ServiceType[]\n /** 构建命令 */\n buildCommand: string\n}\n\n// ─── 部署结果 ───\n\n/**\n * 部署结果\n *\n * 包含部署后的访问 URL、状态和已设置的环境变量。\n */\nexport interface DeployResult {\n /** 部署后的访问 URL */\n url: string\n /** 部署 ID */\n deploymentId: string\n /** 部署状态 */\n status: 'ready' | 'building' | 'error'\n /** 已设置的环境变量名列表 */\n envVarsSet: string[]\n}\n\n// ─── 开通结果 ───\n\n/**\n * 基础设施开通结果\n *\n * 由 Provisioner 开通服务后返回,包含要注入到部署平台的环境变量。\n */\nexport interface ProvisionResult {\n /** 服务类型 */\n serviceType: ServiceType\n /** Provisioner 名称 */\n provisionerName: string\n /** 要注入到部署平台的环境变量 */\n envVars: Record<string, string>\n /** 资源标识信息(如项目名、数据库名等),用于日志和展示 */\n resourceInfo: string\n}\n\n// ─── 部署选项 ───\n\n/** 部署选项 */\nexport interface DeployAppOptions {\n /** 项目名称(默认从 package.json name 提取) */\n projectName?: string\n /** 是否跳过基础设施开通 */\n skipProvision?: boolean\n /** 是否跳过构建 */\n skipBuild?: boolean\n}\n\n// ─── 凭证子功能 ───\n\n/**\n * Deploy 凭证文件操作。\n *\n * 这些方法仅操作 `~/.hai/credentials.yml`,不依赖 `deploy.init()`。\n */\nexport interface DeployCredentialOperations {\n /** 获取凭证文件绝对路径。 */\n getPath: () => string\n /** 加载凭证文件并注入 `process.env`。 */\n load: () => HaiResult<string[]>\n /** 保存单个凭证。 */\n save: (key: string, value: string) => HaiResult<void>\n /** 批量保存凭证。 */\n saveAll: (entries: Record<string, string>) => HaiResult<void>\n}\n\n// ─── 模块功能接口 ───\n\n/**\n * Deploy 模块功能接口\n *\n * 提供自动化部署的完整 API:\n * - `deploy.credentials.*()` — 凭证文件读写(不依赖 init)\n * - `deploy.init()` — 初始化(加载配置、创建 Provider 和 Provisioner)\n * - `deploy.scan()` — 扫描应用依赖(纯文件系统能力,不依赖 init)\n * - `deploy.provisionAll()` — 开通所有已配置的基础设施\n * - `deploy.deployApp()` — 完整部署流程\n * - `deploy.close()` — 关闭模块\n *\n * @example\n * ```ts\n * import { deploy } from '@h-ai/deploy'\n *\n * await deploy.init({ provider: { type: 'vercel', token: 'xxx' } })\n * const result = await deploy.deployApp('./apps/my-app')\n * if (result.success) {\n * console.log(`Deployed: ${result.data.url}`)\n * }\n * await deploy.close()\n * ```\n */\nexport interface DeployFunctions {\n /** 全局部署凭证文件操作。 */\n readonly credentials: DeployCredentialOperations\n /** 初始化模块(加载配置、创建 Provider 和 Provisioner 实例) */\n init: (config: DeployConfigInput) => Promise<HaiResult<void>>\n /** 关闭模块 */\n close: () => Promise<void>\n /** 当前配置 */\n readonly config: DeployConfig | null\n /** 是否已初始化 */\n readonly isInitialized: boolean\n\n /**\n * 扫描应用目录,检测依赖和所需服务。\n *\n * 这是纯文件系统分析能力,不依赖云端认证状态,可在 `deploy.init()` 之前调用。\n *\n * @param appDir - 应用根目录路径\n */\n scan: (appDir: string) => Promise<HaiResult<ScanResult>>\n\n /**\n * 对所有已配置的 Provisioner 执行基础设施开通\n *\n * @param projectName - 用于资源命名的项目名\n * @returns 所有 Provisioner 的结果列表\n */\n provisionAll: (projectName: string) => Promise<HaiResult<ProvisionResult[]>>\n\n /**\n * 执行完整部署流程(provision → build → deploy)\n *\n * @param appDir - 应用根目录路径\n * @param options - 部署选项\n */\n deployApp: (appDir: string, options?: DeployAppOptions) => Promise<HaiResult<DeployResult>>\n}\n","/**\n * @h-ai/deploy — 凭证管理\n *\n * 管理全局凭证文件 `~/.hai/credentials.yml`。\n * 这些 helper 由 `deploy.credentials.*` 对外暴露,供 CLI 在加载 `_deploy.yml`\n * 之前注入 `HAI_DEPLOY_*` 环境变量。\n * @module deploy-credentials\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport process from 'node:process'\nimport { core, err, ok } from '@h-ai/core'\nimport { parse, stringify } from 'yaml'\nimport { deployM } from './deploy-i18n.js'\nimport { HaiDeployError } from './deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'credentials' })\n\n/** 仅允许写入 deploy 模块自有的环境变量前缀,避免把任意 YAML key 注入 process.env。 */\nconst DEPLOY_CREDENTIAL_KEY_PATTERN = /^HAI_DEPLOY_[A-Z0-9_]+$/\n\n// ─── 内部工具 ───\n\n/** 校验凭证键名是否属于 deploy 模块。 */\nfunction isAllowedCredentialKey(key: string): boolean {\n return DEPLOY_CREDENTIAL_KEY_PATTERN.test(key)\n}\n\n/**\n * 标准化凭证键值对。\n *\n * 仅保留 `HAI_DEPLOY_*` 键,且值必须是可安全序列化为字符串的标量。\n */\nfunction normalizeCredentialEntries(entries: Record<string, unknown>): Record<string, string> {\n const normalized: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(entries)) {\n if (!isAllowedCredentialKey(key)) {\n logger.warn('Ignoring unsupported deploy credential key', { key })\n continue\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n normalized[key] = String(value)\n continue\n }\n\n logger.warn('Ignoring deploy credential with non-scalar value', { key })\n }\n\n return normalized\n}\n\n/** 在写入前校验单个凭证键名。 */\nfunction assertAllowedCredentialKey(key: string): void {\n if (!isAllowedCredentialKey(key)) {\n throw new Error(deployM('deploy_credentialInvalidKey', { params: { key } }))\n }\n}\n\n/** 在写入前校验批量凭证键名。 */\nfunction assertAllowedCredentialEntries(entries: Record<string, string>): void {\n for (const key of Object.keys(entries)) {\n assertAllowedCredentialKey(key)\n }\n}\n\n/**\n * 获取凭证文件路径\n *\n * @returns `~/.hai/credentials.yml` 的绝对路径\n */\nexport function getCredentialsPath(): string {\n return join(homedir(), '.hai', 'credentials.yml')\n}\n\n/**\n * 确保凭证目录存在\n *\n * @param filePath - 凭证文件路径\n */\nfunction ensureDir(filePath: string): void {\n const dir = dirname(filePath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n}\n\n/**\n * 读取凭证文件内容\n *\n * @returns 解析后的键值对,文件不存在时返回空对象\n */\nfunction readCredentialsFile(): Record<string, string> {\n const filePath = getCredentialsPath()\n if (!existsSync(filePath)) {\n return {}\n }\n const content = readFileSync(filePath, 'utf-8')\n const parsed = parse(content)\n if (parsed === null || parsed === undefined || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return {}\n }\n return normalizeCredentialEntries(parsed as Record<string, unknown>)\n}\n\n/**\n * 写入凭证文件\n *\n * @param data - 凭证键值对\n */\nfunction writeCredentialsFile(data: Record<string, string>): void {\n const filePath = getCredentialsPath()\n ensureDir(filePath)\n const header = '# Managed by hai cli - do not edit manually\\n'\n const content = header + stringify(data)\n writeFileSync(filePath, content, { encoding: 'utf-8', mode: 0o600 })\n}\n\n// ─── 公共 API ───\n\n/**\n * 加载全局凭证文件并注入到 process.env\n *\n * 读取 `~/.hai/credentials.yml` 中的所有键值对,\n * 将每个 key-value 设置到 `process.env` 中,\n * 使后续 core 配置加载时自动解析 `${HAI_DEPLOY_*}` 变量。\n *\n * @returns 成功返回加载的凭证键名列表\n *\n * @example\n * ```ts\n * const result = loadCredentials()\n * if (result.success) {\n * console.log(`Loaded ${result.data.length} credentials`)\n * }\n * ```\n */\nexport function loadCredentials(): HaiResult<string[]> {\n try {\n const data = readCredentialsFile()\n const keys = Object.keys(data)\n for (const key of keys) {\n process.env[key] = String(data[key])\n }\n logger.debug('Credentials loaded', { count: keys.length })\n return ok(keys)\n }\n catch (error) {\n logger.error('Failed to load credentials', { error })\n return err(\n HaiDeployError.CREDENTIAL_ERROR,\n deployM('deploy_credentialError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 保存单个凭证到全局凭证文件\n *\n * 读取已有凭证 → 合并新凭证 → 写回文件。已有同名 key 会被覆盖。\n *\n * @param key - 环境变量名(如 HAI_DEPLOY_VERCEL_TOKEN)\n * @param value - 凭证值\n *\n * @example\n * ```ts\n * saveCredential('HAI_DEPLOY_VERCEL_TOKEN', 'vel_xxx')\n * ```\n */\nexport function saveCredential(key: string, value: string): HaiResult<void> {\n try {\n assertAllowedCredentialKey(key)\n const data = readCredentialsFile()\n data[key] = value\n writeCredentialsFile(data)\n process.env[key] = value\n logger.debug('Credential saved', { key })\n return ok(undefined)\n }\n catch (error) {\n logger.error('Failed to save credential', { key, error })\n return err(\n HaiDeployError.CREDENTIAL_ERROR,\n deployM('deploy_credentialError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 批量保存凭证到全局凭证文件\n *\n * @param entries - 凭证键值对\n *\n * @example\n * ```ts\n * saveCredentials({\n * HAI_DEPLOY_VERCEL_TOKEN: 'vel_xxx',\n * HAI_DEPLOY_NEON_API_KEY: 'neon_xxx',\n * })\n * ```\n */\nexport function saveCredentials(entries: Record<string, string>): HaiResult<void> {\n try {\n assertAllowedCredentialEntries(entries)\n const data = readCredentialsFile()\n for (const [key, value] of Object.entries(entries)) {\n data[key] = value\n process.env[key] = value\n }\n writeCredentialsFile(data)\n logger.debug('Credentials saved', { count: Object.keys(entries).length })\n return ok(undefined)\n }\n catch (error) {\n logger.error('Failed to save credentials', { error })\n return err(\n HaiDeployError.CREDENTIAL_ERROR,\n deployM('deploy_credentialError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n","/**\n * @h-ai/deploy — 部署辅助函数\n *\n * 包含构建、产物目录解析等与部署流程相关的辅助操作。 从 deploy-main.ts 中提取,遵循 main 仅做生命周期管理的规范。\n * @module deploy-functions\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport { execSync } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport process from 'node:process'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from './deploy-i18n.js'\nimport { HaiDeployError } from './deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'functions' })\n\n/**\n * 执行应用构建\n *\n * @param appDir - 应用根目录\n * @param buildCommand - 构建命令\n * @returns 构建结果\n */\nexport function buildApp(appDir: string, buildCommand: string): HaiResult<void> {\n logger.info('Building application', { appDir, buildCommand })\n try {\n execSync(buildCommand, {\n cwd: appDir,\n stdio: 'inherit',\n env: { ...process.env },\n })\n return ok(undefined)\n }\n catch (error) {\n return err(\n HaiDeployError.BUILD_FAILED,\n deployM('deploy_buildFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 解析构建产物目录\n *\n * @param appDir - 应用根目录\n * @param providerType - Provider 类型\n * @returns 产物目录路径\n */\nexport function resolveOutputDir(appDir: string, providerType: string): string {\n switch (providerType) {\n case 'vercel': {\n const vercelOutput = join(appDir, '.vercel', 'output')\n if (existsSync(vercelOutput)) {\n return vercelOutput\n }\n // 回退到标准 build 目录\n return join(appDir, 'build')\n }\n default:\n return join(appDir, 'build')\n }\n}\n","/**\n * @h-ai/deploy — 应用扫描器\n *\n * 扫描应用目录,检测框架类型、模块依赖和所需基础设施。\n * @module deploy-scanner\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ScanResult, ServiceType } from './deploy-types.js'\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { core, err, ok } from '@h-ai/core'\nimport { parse } from 'yaml'\nimport { deployM } from './deploy-i18n.js'\nimport { HaiDeployError } from './deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'scanner' })\n\n// ─── 内部工具 ───\n\n/**\n * 安全读取并解析 YAML 文件\n *\n * @param filePath - YAML 文件路径\n * @returns 解析结果,文件不存在或解析失败时返回 null\n */\nfunction readYaml(filePath: string): Record<string, unknown> | null {\n if (!existsSync(filePath)) {\n return null\n }\n try {\n const content = readFileSync(filePath, 'utf-8')\n const parsed = parse(content)\n if (parsed === null || parsed === undefined || typeof parsed !== 'object') {\n return null\n }\n return parsed as Record<string, unknown>\n }\n catch {\n return null\n }\n}\n\n/**\n * 安全读取 JSON 文件\n *\n * @param filePath - JSON 文件路径\n * @returns 解析结果,文件不存在或解析失败时返回 null\n */\nfunction readJson(filePath: string): Record<string, unknown> | null {\n if (!existsSync(filePath)) {\n return null\n }\n try {\n const content = readFileSync(filePath, 'utf-8')\n return JSON.parse(content) as Record<string, unknown>\n }\n catch {\n return null\n }\n}\n\n/**\n * 检测 package.json 的 dependencies + devDependencies 中是否包含指定包\n *\n * @param pkg - package.json 内容\n * @param name - 包名\n */\nfunction hasDependency(pkg: Record<string, unknown>, name: string): boolean {\n const deps = pkg.dependencies as Record<string, string> | undefined\n const devDeps = pkg.devDependencies as Record<string, string> | undefined\n return (deps !== undefined && name in deps) || (devDeps !== undefined && name in devDeps)\n}\n\n/**\n * 扫描 config/ 目录,推断所需基础设施服务\n *\n * @param configDir - 配置目录路径\n * @returns 需要的服务类型列表\n */\nfunction detectRequiredServices(configDir: string): ServiceType[] {\n const services: ServiceType[] = []\n\n if (!existsSync(configDir)) {\n return services\n }\n\n const files = readdirSync(configDir)\n\n // 检测数据库需求\n if (files.includes('_db.yml') || files.includes('_db.yaml')) {\n const dbConfig = readYaml(join(configDir, files.find(f => f.startsWith('_db.'))!))\n // sqlite 在云端也需要切换为 postgresql,标记为需要 db\n if (dbConfig !== null) {\n services.push('db')\n }\n }\n\n // 检测缓存需求\n if (files.includes('_cache.yml') || files.includes('_cache.yaml')) {\n const cacheConfig = readYaml(join(configDir, files.find(f => f.startsWith('_cache.'))!))\n if (cacheConfig !== null) {\n const cacheType = cacheConfig.type as string | undefined\n // memory 模式不需要外部服务,redis 需要\n if (cacheType === 'redis') {\n services.push('cache')\n }\n }\n }\n\n // 检测存储需求\n if (files.includes('_storage.yml') || files.includes('_storage.yaml')) {\n const storageConfig = readYaml(join(configDir, files.find(f => f.startsWith('_storage.'))!))\n if (storageConfig !== null) {\n detectStorageServices(storageConfig, services)\n }\n }\n\n // 检测 reach(邮件 / 短信)需求\n if (files.includes('_reach.yml') || files.includes('_reach.yaml')) {\n const reachConfig = readYaml(join(configDir, files.find(f => f.startsWith('_reach.'))!))\n if (reachConfig !== null) {\n detectReachServices(reachConfig, services)\n }\n }\n\n return services\n}\n\n/**\n * 检测存储配置中的 S3 需求\n *\n * @param config - 存储配置内容\n * @param services - 服务列表(原地修改)\n */\nfunction detectStorageServices(config: Record<string, unknown>, services: ServiceType[]): void {\n // 直接配置\n if (config.type === 's3') {\n services.push('storage')\n return\n }\n // 多 provider 配置\n const providers = config.providers as Record<string, unknown> | undefined\n if (providers === undefined) {\n return\n }\n for (const providerConfig of Object.values(providers)) {\n const typed = providerConfig as Record<string, unknown> | undefined\n if (typed?.type === 's3') {\n services.push('storage')\n return\n }\n }\n}\n\n/**\n * 检测 reach 配置中的邮件和短信需求\n *\n * @param config - reach 配置内容\n * @param services - 服务列表(原地修改)\n */\nfunction detectReachServices(config: Record<string, unknown>, services: ServiceType[]): void {\n const providers = config.providers as Array<Record<string, unknown>> | undefined\n if (!Array.isArray(providers)) {\n return\n }\n\n let hasEmail = false\n let hasSms = false\n\n for (const provider of providers) {\n const providerType = provider.type as string | undefined\n // smtp / api / resend 类型视为邮件需求\n if (!hasEmail && (providerType === 'smtp' || providerType === 'api')) {\n hasEmail = true\n services.push('email')\n }\n // aliyun-sms 类型视为短信需求\n if (!hasSms && providerType === 'aliyun-sms') {\n hasSms = true\n services.push('sms')\n }\n }\n}\n\n// ─── 公共 API ───\n\n/**\n * 扫描应用目录,检测框架类型、模块依赖和所需基础设施\n *\n * @param appDir - 应用根目录绝对路径\n * @returns 扫描结果(ScanResult)\n *\n * @example\n * ```ts\n * const result = await scanApp('/path/to/my-app')\n * if (result.success) {\n * const { appName, isSvelteKit, requiredServices } = result.data\n * }\n * ```\n */\nexport async function scanApp(appDir: string): Promise<HaiResult<ScanResult>> {\n logger.debug('Scanning application', { appDir })\n\n try {\n // 读取 package.json\n const pkg = readJson(join(appDir, 'package.json'))\n if (pkg === null) {\n return err(\n HaiDeployError.SCAN_FAILED,\n deployM('deploy_scanFailed', { params: { error: 'package.json not found' } }),\n )\n }\n\n const appName = extractAppName(pkg)\n const isSvelteKit = existsSync(join(appDir, 'svelte.config.js'))\n || existsSync(join(appDir, 'svelte.config.ts'))\n const adapterInstalled = hasDependency(pkg, '@sveltejs/adapter-vercel')\n const configDir = join(appDir, 'config')\n const configServices = detectRequiredServices(configDir)\n const depServices = detectServicesFromDependencies(pkg)\n // 合并去重:config 检测优先,依赖检测补充\n const requiredServices = Array.from(new Set([...configServices, ...depServices]))\n const scripts = pkg.scripts as Record<string, string> | undefined\n const buildCommand = scripts?.build ?? 'pnpm build'\n\n const scanResult: ScanResult = {\n appName,\n isSvelteKit,\n adapterInstalled,\n requiredServices,\n buildCommand,\n }\n\n logger.info('Application scanned', {\n appName,\n isSvelteKit,\n adapterInstalled,\n requiredServices,\n })\n\n return ok(scanResult)\n }\n catch (error) {\n logger.error('Application scan failed', { appDir, error })\n return err(\n HaiDeployError.SCAN_FAILED,\n deployM('deploy_scanFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 从 package.json 的 @h-ai/* 依赖推断所需服务\n *\n * 依赖映射规则:\n * - @h-ai/reldb → 'db'\n * - @h-ai/cache → 'cache'\n * - @h-ai/storage → 'storage'\n *\n * @param pkg - package.json 内容\n * @returns 需要的服务类型列表\n */\nfunction detectServicesFromDependencies(pkg: Record<string, unknown>): ServiceType[] {\n const depMap: Record<string, ServiceType> = {\n '@h-ai/reldb': 'db',\n '@h-ai/cache': 'cache',\n '@h-ai/storage': 'storage',\n }\n const services: ServiceType[] = []\n for (const [depName, serviceType] of Object.entries(depMap)) {\n if (hasDependency(pkg, depName)) {\n services.push(serviceType)\n }\n }\n return services\n}\n\n/**\n * 从 package.json 提取应用名称\n *\n * 移除 scope 前缀(如 @h-ai/admin-console → admin-console)\n *\n * @param pkg - package.json 内容\n * @returns 应用名称\n */\nfunction extractAppName(pkg: Record<string, unknown>): string {\n const name = (pkg.name as string) ?? 'app'\n // 移除 scope 前缀\n const slashIndex = name.indexOf('/')\n if (slashIndex >= 0) {\n return name.slice(slashIndex + 1)\n }\n return name\n}\n","/**\n * @h-ai/deploy — Vercel 部署 Provider\n *\n * 封装 Vercel REST API,实现 DeployProvider 接口。 使用原生 fetch 调用,零外部 SDK 依赖。\n * @module deploy-provider-vercel\n */\n\nimport type { HaiError, HaiErrorDef, HaiResult } from '@h-ai/core'\nimport type { DeployProvider } from '../deploy-internal-types.js'\nimport type { DeployResult } from '../deploy-types.js'\nimport { createHash } from 'node:crypto'\nimport { readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, relative, sep } from 'node:path'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provider-vercel' })\n\n/** Vercel API 基址 */\nconst VERCEL_API = 'https://api.vercel.com'\n\n/** 部署状态轮询间隔(毫秒) */\nconst POLL_INTERVAL = 3000\n\n/** 部署状态轮询最大次数 */\nconst MAX_POLL_ATTEMPTS = 60\n\n// ─── 内部工具 ───\n\n/** Vercel API 错误,保留状态码用于区分 404 与真实失败 */\nclass VercelApiError extends Error {\n constructor(readonly status: number) {\n super(deployM('deploy_apiError', { params: { service: 'Vercel', status: String(status) } }))\n }\n}\n\n/** 构造标准错误对象 */\nfunction toDeployError(codeDef: HaiErrorDef, messageKey: string, error: unknown): HaiError {\n return {\n ...codeDef,\n message: deployM(messageKey as Parameters<typeof deployM>[0], {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n cause: error,\n }\n}\n\n/**\n * 发送 Vercel API 请求\n *\n * @param token - API Token\n * @param path - API 路径(如 /v2/user)\n * @param options - fetch 选项\n * @returns 解析后的 JSON 响应\n */\nasync function vercelFetch<T>(token: string, path: string, options?: RequestInit): Promise<T> {\n const url = `${VERCEL_API}${path}`\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n ...options?.headers,\n },\n })\n\n if (!response.ok) {\n throw new VercelApiError(response.status)\n }\n\n return response.json() as Promise<T>\n}\n\n/**\n * 递归收集目录中的所有文件\n *\n * @param dir - 目录路径\n * @param baseDir - 基础目录(用于计算相对路径)\n * @returns 文件相对路径列表\n */\nfunction collectFiles(dir: string, baseDir: string): string[] {\n const results: string[] = []\n const entries = readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...collectFiles(fullPath, baseDir))\n }\n else {\n results.push(relative(baseDir, fullPath).split(sep).join('/'))\n }\n }\n\n return results\n}\n\n// ─── Provider 工厂 ───\n\n/**\n * 创建 Vercel 部署 Provider\n *\n * @returns DeployProvider 实例\n *\n * @example\n * ```ts\n * const provider = createVercelProvider()\n * await provider.authenticate('vel_xxx')\n * const projectId = await provider.createProject('my-app')\n * ```\n */\nexport function createVercelProvider(): DeployProvider {\n let token: string | null = null\n\n return {\n name: 'vercel',\n\n async authenticate(apiToken: string): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Vercel')\n try {\n const user = await vercelFetch<{ user: { username: string, email: string } }>(\n apiToken,\n '/v2/user',\n )\n token = apiToken\n const username = user.user.username || user.user.email\n logger.info('Vercel authenticated', { user: username })\n return ok(username)\n }\n catch (error) {\n logger.error('Vercel authentication failed', { error })\n return err(toDeployError(HaiDeployError.AUTH_FAILED, 'deploy_authFailed', error))\n }\n },\n\n async createProject(projectName: string): Promise<HaiResult<string>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Creating Vercel project', { projectName })\n try {\n // 先查找已有项目\n const existingId = await findExistingProject(token, projectName)\n if (existingId !== null) {\n logger.info('Vercel project found', { projectName, projectId: existingId })\n return ok(existingId)\n }\n\n try {\n const project = await vercelFetch<{ id: string }>(\n token,\n '/v11/projects',\n {\n method: 'POST',\n body: JSON.stringify({\n name: projectName,\n framework: 'sveltekit',\n }),\n },\n )\n logger.info('Vercel project created', { projectName, projectId: project.id })\n return ok(project.id)\n }\n catch (error) {\n // 官方文档说明同名项目创建会返回 409;遇到并发竞争时回查现有项目即可实现幂等。\n if (error instanceof VercelApiError && error.status === 409) {\n const concurrentProjectId = await findExistingProject(token, projectName)\n if (concurrentProjectId !== null) {\n logger.info('Vercel project reused after create conflict', {\n projectName,\n projectId: concurrentProjectId,\n })\n return ok(concurrentProjectId)\n }\n }\n throw error\n }\n }\n catch (error) {\n logger.error('Vercel project creation failed', { projectName, error })\n return err(toDeployError(HaiDeployError.PROJECT_CREATE_FAILED, 'deploy_projectCreateFailed', error))\n }\n },\n\n async setEnvVars(projectId: string, envVars: Record<string, string>): Promise<HaiResult<void>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Setting Vercel env vars', { projectId, count: Object.keys(envVars).length })\n try {\n const envEntries = Object.entries(envVars).map(([key, value]) => ({\n key,\n value,\n type: 'encrypted' as const,\n target: ['production', 'preview', 'development'],\n }))\n\n // Vercel 官方 `upsert=true` 支持按 key 覆盖已有环境变量,避免重复部署时报“已存在”。\n await vercelFetch(\n token,\n `/v10/projects/${projectId}/env?upsert=true`,\n {\n method: 'POST',\n body: JSON.stringify(envEntries),\n },\n )\n logger.info('Vercel env vars set', { projectId, count: envEntries.length })\n return ok(undefined)\n }\n catch (error) {\n logger.error('Vercel env vars setup failed', { projectId, error })\n return err(toDeployError(HaiDeployError.ENV_VAR_FAILED, 'deploy_envVarFailed', error))\n }\n },\n\n async deploy(projectId: string, outputDir: string): Promise<HaiResult<DeployResult>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Deploying to Vercel', { projectId, outputDir })\n try {\n // 收集所有文件\n const filePaths = collectFiles(outputDir, outputDir)\n const files: Array<{ file: string, sha: string, size: number }> = []\n\n // 上传每个文件\n for (const filePath of filePaths) {\n const fullPath = join(outputDir, filePath)\n const content = readFileSync(fullPath)\n const sha = createHash('sha1').update(content).digest('hex')\n const size = statSync(fullPath).size\n\n await uploadFile(token, content, sha)\n files.push({ file: filePath, sha, size })\n }\n\n logger.debug('Files uploaded', { count: files.length })\n\n // 创建部署\n const deployment = await vercelFetch<{ id: string, url: string }>(\n token,\n '/v13/deployments',\n {\n method: 'POST',\n body: JSON.stringify({\n name: projectId,\n files,\n projectSettings: { framework: 'sveltekit' },\n }),\n },\n )\n\n // 轮询部署状态\n const finalStatus = await pollDeploymentStatus(token, deployment.id)\n\n const result: DeployResult = {\n url: `https://${deployment.url}`,\n deploymentId: deployment.id,\n status: finalStatus,\n envVarsSet: [],\n }\n\n logger.info('Vercel deployment complete', {\n deploymentId: deployment.id,\n url: result.url,\n status: finalStatus,\n })\n\n return ok(result)\n }\n catch (error) {\n logger.error('Vercel deployment failed', { projectId, error })\n return err(toDeployError(HaiDeployError.UPLOAD_FAILED, 'deploy_uploadFailed', error))\n }\n },\n }\n}\n\n// ─── 内部辅助 ───\n\n/**\n * 查找已有的 Vercel 项目\n *\n * @param token - API Token\n * @param projectName - 项目名称\n * @returns 项目 ID,不存在时返回 null\n */\nasync function findExistingProject(token: string, projectName: string): Promise<string | null> {\n try {\n const project = await vercelFetch<{ id: string }>(token, `/v10/projects/${projectName}`)\n return project.id\n }\n catch (error) {\n if (error instanceof VercelApiError && error.status === 404) {\n return null\n }\n throw error\n }\n}\n\n/**\n * 上传单个文件到 Vercel\n *\n * @param token - API Token\n * @param content - 文件内容\n * @param sha - 文件 SHA1 哈希\n */\nasync function uploadFile(token: string, content: Uint8Array, sha: string): Promise<void> {\n const url = `${VERCEL_API}/v2/files`\n const uploadContent = new Uint8Array(content)\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/octet-stream',\n 'x-vercel-digest': sha,\n },\n body: new Blob([uploadContent]),\n })\n\n if (!response.ok && response.status !== 409) {\n // 409 表示文件已存在,可忽略\n throw new Error(deployM('deploy_fileUploadFailed', { params: { status: String(response.status) } }))\n }\n}\n\n/**\n * 轮询部署状态直到完成\n *\n * @param token - API Token\n * @param deploymentId - 部署 ID\n * @returns 最终状态\n */\nasync function pollDeploymentStatus(\n token: string,\n deploymentId: string,\n): Promise<'ready' | 'building' | 'error'> {\n for (let i = 0; i < MAX_POLL_ATTEMPTS; i++) {\n const deployment = await vercelFetch<{ readyState: string }>(\n token,\n `/v13/deployments/${deploymentId}`,\n )\n\n if (deployment.readyState === 'READY') {\n return 'ready'\n }\n if (deployment.readyState === 'ERROR' || deployment.readyState === 'CANCELED') {\n return 'error'\n }\n\n // 等待后重试\n await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL))\n }\n\n // 超时仍在构建\n return 'building'\n}\n","/**\n * @h-ai/deploy — Aliyun SMS Provisioner\n *\n * 验证阿里云 API 凭证用于短信服务。 阿里云短信资源(签名/模板)通常在控制台预配置,此 Provisioner 仅验证凭证。\n * @module deploy-provisioner-aliyun\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-aliyun' })\n\n/**\n * 创建 Aliyun SMS Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createAliyunProvisioner(): ServiceProvisioner {\n let accessKey: string | null = null\n let secretKey: string | null = null\n\n return {\n name: 'aliyun',\n serviceType: 'sms',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Aliyun')\n try {\n const akId = credentials.accessKeyId ?? credentials.access_key_id ?? credentials.access_key ?? ''\n const akSecret = credentials.accessKeySecret ?? credentials.access_key_secret ?? credentials.secret_key ?? ''\n\n if (!akId || !akSecret) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'access_key_id, access_key_secret' } }))\n }\n\n accessKey = akId\n secretKey = akSecret\n logger.info('Aliyun authenticated', { accessKeyId: `${akId.slice(0, 6)}***` })\n return ok(akId)\n }\n catch (error) {\n logger.error('Aliyun authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(_appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!accessKey || !secretKey) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Aliyun SMS service')\n\n // 阿里云短信不支持 API 创建资源,仅返回凭证作为环境变量\n return ok({\n serviceType: 'sms',\n provisionerName: 'aliyun',\n envVars: {\n HAI_REACH_SMS_ACCESS_KEY: accessKey,\n HAI_REACH_SMS_SECRET_KEY: secretKey,\n },\n resourceInfo: 'aliyun:verify-only',\n })\n },\n }\n}\n","/**\n * @h-ai/deploy — Neon PostgreSQL Provisioner\n *\n * 通过 Neon REST API 自动创建 PostgreSQL 数据库。\n * @module deploy-provisioner-neon\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-neon' })\n\n/** Neon API 基址 */\nconst NEON_API = 'https://console.neon.tech/api/v2'\n\n/** Neon 新建项目默认生成的数据库名。 */\nconst DEFAULT_NEON_DATABASE_NAME = 'neondb'\n\n/** Neon 新建项目默认生成的角色名。 */\nconst DEFAULT_NEON_ROLE_NAME = 'neondb_owner'\n\ninterface NeonProjectSummary {\n id: string\n name: string\n}\n\ninterface NeonProjectsResponse {\n projects?: NeonProjectSummary[]\n}\n\ninterface NeonCreateProjectResponse {\n connection_uris?: Array<{ connection_uri?: string }>\n project?: { id?: string }\n}\n\ninterface NeonConnectionUriResponse {\n uri?: string\n}\n\n/** 统一发起 Neon API 请求。 */\nasync function neonFetch<T>(token: string, path: string, options?: RequestInit): Promise<T> {\n const response = await fetch(`${NEON_API}${path}`, {\n ...options,\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n ...options?.headers,\n },\n })\n\n if (!response.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Neon', status: String(response.status) } }))\n }\n\n return response.json() as Promise<T>\n}\n\n/** 列出当前账号下的 Neon 项目。 */\nasync function listNeonProjects(token: string): Promise<NeonProjectSummary[]> {\n const data = await neonFetch<NeonProjectsResponse>(token, '/projects')\n return data.projects ?? []\n}\n\n/** 按名称查找已有的 Neon 项目。 */\nasync function findExistingNeonProject(token: string, projectName: string): Promise<NeonProjectSummary | null> {\n const projects = await listNeonProjects(token)\n return projects.find(project => project.name === projectName) ?? null\n}\n\n/**\n * 获取现有项目的连接串。\n *\n * Neon 官方 OpenAPI 提供 `GET /projects/{project_id}/connection_uri`。\n * 这里使用创建项目时的默认数据库/角色名,保证本模块创建的项目可被幂等复用。\n */\nasync function getNeonConnectionUri(token: string, projectId: string): Promise<string> {\n const query = new URLSearchParams({\n database_name: DEFAULT_NEON_DATABASE_NAME,\n role_name: DEFAULT_NEON_ROLE_NAME,\n })\n const data = await neonFetch<NeonConnectionUriResponse>(\n token,\n `/projects/${projectId}/connection_uri?${query.toString()}`,\n { headers: { 'Content-Type': 'application/json' } },\n )\n\n if (!data.uri) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Neon' } }))\n }\n\n return data.uri\n}\n\n/** 构建统一的 Neon 开通结果。 */\nfunction buildNeonProvisionResult(projectId: string, connectionUri: string): ProvisionResult {\n return {\n serviceType: 'db',\n provisionerName: 'neon',\n envVars: {\n HAI_RELDB_URL: connectionUri,\n },\n resourceInfo: `neon-project:${projectId}`,\n }\n}\n\n/**\n * 创建 Neon PostgreSQL Provisioner\n *\n * @returns ServiceProvisioner 实例\n *\n * @example\n * ```ts\n * const neon = createNeonProvisioner()\n * await neon.authenticate({ apiKey: 'neon_xxx' })\n * const result = await neon.provision('my-app')\n * ```\n */\nexport function createNeonProvisioner(): ServiceProvisioner {\n let token: string | null = null\n\n return {\n name: 'neon',\n serviceType: 'db',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Neon')\n try {\n const apiToken = credentials.apiKey ?? credentials.token ?? credentials.api_key ?? ''\n if (!apiToken) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'token' } }))\n }\n\n await listNeonProjects(apiToken)\n token = apiToken\n logger.info('Neon authenticated')\n return ok('neon-user')\n }\n catch (error) {\n logger.error('Neon authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Neon database', { appName })\n try {\n const projectName = `${appName}-db`\n\n const existingProject = await findExistingNeonProject(token, projectName)\n if (existingProject !== null) {\n const connectionUri = await getNeonConnectionUri(token, existingProject.id)\n logger.info('Neon project reused', {\n projectId: existingProject.id,\n projectName,\n })\n return ok(buildNeonProvisionResult(existingProject.id, connectionUri))\n }\n\n const data = await neonFetch<NeonCreateProjectResponse>(token, '/projects', {\n method: 'POST',\n body: JSON.stringify({\n project: {\n name: projectName,\n pg_version: 16,\n },\n }),\n })\n\n const projectId = data.project?.id ?? ''\n const connectionUri = data.connection_uris?.[0]?.connection_uri ?? ''\n if (!projectId || !connectionUri) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Neon' } }))\n }\n\n logger.info('Neon database provisioned', { projectId })\n\n return ok(buildNeonProvisionResult(projectId, connectionUri))\n }\n catch (error) {\n logger.error('Neon provisioning failed', { appName, error })\n return err(\n HaiDeployError.PROVISION_FAILED,\n deployM('deploy_provisionFailed', {\n params: {\n service: 'neon',\n error: error instanceof Error ? error.message : String(error),\n },\n }),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/deploy — Cloudflare R2 Provisioner\n *\n * 通过 Cloudflare API 自动创建 R2 存储桶。\n * @module deploy-provisioner-r2\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-r2' })\n\n/** Cloudflare API 基址 */\nconst CF_API = 'https://api.cloudflare.com/client/v4'\n\n/**\n * 创建 Cloudflare R2 Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createR2Provisioner(): ServiceProvisioner {\n let token: string | null = null\n let accountId: string | null = null\n\n return {\n name: 'r2',\n serviceType: 'storage',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Cloudflare')\n try {\n const acctId = credentials.accountId ?? credentials.account_id ?? ''\n const apiTok = credentials.apiToken ?? credentials.api_token ?? credentials.token ?? ''\n if (!acctId || !apiTok) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'account_id, api_token' } }))\n }\n\n const res = await fetch(`${CF_API}/accounts/${acctId}/r2/buckets`, {\n headers: { Authorization: `Bearer ${apiTok}` },\n })\n if (!res.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Cloudflare', status: String(res.status) } }))\n }\n\n accountId = acctId\n token = apiTok\n logger.info('Cloudflare R2 authenticated', { accountId: acctId })\n return ok(acctId)\n }\n catch (error) {\n logger.error('Cloudflare R2 authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!token || !accountId) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n const bucketName = `${appName}-storage`.toLowerCase().replace(/[^a-z0-9-]/g, '-')\n\n logger.debug('Provisioning R2 bucket', { appName, bucketName })\n try {\n // 创建桶\n const createRes = await fetch(\n `${CF_API}/accounts/${accountId}/r2/buckets`,\n {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ name: bucketName }),\n },\n )\n\n // 409 表示桶已存在,可继续\n if (!createRes.ok && createRes.status !== 409) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Cloudflare', status: String(createRes.status) } }))\n }\n\n // 创建 API Token(S3 兼容访问)\n const tokenRes = await fetch(\n `${CF_API}/user/tokens`,\n {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n name: `${appName}-r2-token`,\n policies: [{\n effect: 'allow',\n permission_groups: [{ id: 'r2-read-write' }],\n resources: { [`com.cloudflare.edge.r2.bucket.${accountId}_default_${bucketName}`]: '*' },\n }],\n }),\n },\n )\n\n if (!tokenRes.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Cloudflare', status: String(tokenRes.status) } }))\n }\n\n const tokenData = await tokenRes.json() as {\n result?: { id?: string, value?: string }\n }\n const accessKey = tokenData.result?.id ?? ''\n const secretKey = tokenData.result?.value ?? ''\n if (!accessKey || !secretKey) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Cloudflare R2' } }))\n }\n\n logger.info('R2 bucket provisioned', { bucketName })\n\n return ok({\n serviceType: 'storage',\n provisionerName: 'r2',\n envVars: {\n HAI_STORAGE_S3_ENDPOINT: `https://${accountId}.r2.cloudflarestorage.com`,\n HAI_STORAGE_S3_BUCKET: bucketName,\n HAI_STORAGE_S3_ACCESS_KEY: accessKey,\n HAI_STORAGE_S3_SECRET_KEY: secretKey,\n },\n resourceInfo: `r2-bucket:${bucketName}`,\n })\n }\n catch (error) {\n logger.error('R2 provisioning failed', { appName, error })\n return err(\n HaiDeployError.PROVISION_FAILED,\n deployM('deploy_provisionFailed', {\n params: {\n service: 'r2',\n error: error instanceof Error ? error.message : String(error),\n },\n }),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/deploy — Resend Email Provisioner\n *\n * 通过 Resend REST API 验证 API Key 并获取域信息。 Resend 不支持通过 API 创建账户,此 Provisioner 仅验证已有凭证。\n * @module deploy-provisioner-resend\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\n\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-resend' })\n\n/** Resend API 基址 */\nconst RESEND_API = 'https://api.resend.com'\n\n/**\n * 创建 Resend Email Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createResendProvisioner(): ServiceProvisioner {\n let token: string | null = null\n\n return {\n name: 'resend',\n serviceType: 'email',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Resend')\n try {\n const apiToken = credentials.apiKey ?? credentials.api_key ?? credentials.token ?? ''\n if (!apiToken) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'api_key' } }))\n }\n\n const res = await fetch(`${RESEND_API}/domains`, {\n headers: { Authorization: `Bearer ${apiToken}` },\n })\n if (!res.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Resend', status: String(res.status) } }))\n }\n token = apiToken\n logger.info('Resend authenticated')\n return ok('resend-user')\n }\n catch (error) {\n logger.error('Resend authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(_appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Resend email service')\n\n // Resend 不支持 API 创建资源,仅返回凭证作为环境变量\n return ok({\n serviceType: 'email',\n provisionerName: 'resend',\n envVars: {\n HAI_REACH_RESEND_KEY: token,\n },\n resourceInfo: 'resend:verify-only',\n })\n },\n }\n}\n","/**\n * @h-ai/deploy — Upstash Redis Provisioner\n *\n * 通过 Upstash REST API 自动创建 Redis 数据库。\n * @module deploy-provisioner-upstash\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { Buffer } from 'node:buffer'\nimport { core, err, ok } from '@h-ai/core'\n\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-upstash' })\n\n/** Upstash API 基址 */\nconst UPSTASH_API = 'https://api.upstash.com'\n\ninterface UpstashDatabase {\n database_id?: string\n database_name?: string\n endpoint?: string\n rest_url?: string\n rest_token?: string\n password?: string\n token?: string\n}\n\n/** 构建 Upstash Developer API 的 Basic Auth 请求头。 */\nfunction createUpstashAuthHeader(email: string, apiKey: string): string {\n return `Basic ${Buffer.from(`${email}:${apiKey}`).toString('base64')}`\n}\n\n/** 统一发起 Upstash Developer API 请求。 */\nasync function upstashFetch<T>(\n email: string,\n apiKey: string,\n path: string,\n options?: RequestInit,\n): Promise<T> {\n const response = await fetch(`${UPSTASH_API}${path}`, {\n ...options,\n headers: {\n 'Authorization': createUpstashAuthHeader(email, apiKey),\n 'Content-Type': 'application/json',\n ...options?.headers,\n },\n })\n\n if (!response.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Upstash', status: String(response.status) } }))\n }\n\n return response.json() as Promise<T>\n}\n\n/** 列出当前账号下的所有 Upstash 数据库。 */\nasync function listUpstashDatabases(email: string, apiKey: string): Promise<UpstashDatabase[]> {\n return upstashFetch<UpstashDatabase[]>(email, apiKey, '/v2/redis/databases')\n}\n\n/** 按数据库名查找已有资源。 */\nasync function findExistingUpstashDatabase(\n email: string,\n apiKey: string,\n databaseName: string,\n): Promise<UpstashDatabase | null> {\n const databases = await listUpstashDatabases(email, apiKey)\n return databases.find(database => database.database_name === databaseName) ?? null\n}\n\n/** 获取单个数据库详情。 */\nasync function getUpstashDatabase(email: string, apiKey: string, databaseId: string): Promise<UpstashDatabase> {\n return upstashFetch<UpstashDatabase>(email, apiKey, `/v2/redis/database/${databaseId}`)\n}\n\n/**\n * 解析 REST URL。\n *\n * Upstash 文档中的 Developer API 详情页可能返回 `endpoint` 或 `rest_url`,\n * 因此这里兼容两种字段形态。\n */\nfunction resolveUpstashRestUrl(database: UpstashDatabase): string {\n if (typeof database.rest_url === 'string' && database.rest_url.length > 0) {\n return database.rest_url\n }\n\n const endpoint = database.endpoint?.trim() ?? ''\n if (!endpoint) {\n return ''\n }\n if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {\n return endpoint\n }\n if (endpoint.includes('.')) {\n return `https://${endpoint}`\n }\n return `https://${endpoint}.upstash.io`\n}\n\n/**\n * 解析 REST Token。\n *\n * 某些响应会返回 `rest_token`,旧字段则可能仍使用 `password` / `token`。\n */\nfunction resolveUpstashRestToken(database: UpstashDatabase): string {\n return database.rest_token ?? database.token ?? database.password ?? ''\n}\n\n/** 将 Upstash 响应转换为 deploy 统一结果。 */\nfunction buildUpstashProvisionResult(database: UpstashDatabase): ProvisionResult {\n const databaseId = database.database_id ?? ''\n const restUrl = resolveUpstashRestUrl(database)\n const restToken = resolveUpstashRestToken(database)\n\n if (!databaseId || !restUrl || !restToken) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Upstash' } }))\n }\n\n return {\n serviceType: 'cache',\n provisionerName: 'upstash',\n envVars: {\n HAI_CACHE_UPSTASH_URL: restUrl,\n HAI_CACHE_UPSTASH_TOKEN: restToken,\n },\n resourceInfo: `upstash-db:${databaseId}`,\n }\n}\n\n/**\n * 创建 Upstash Redis Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createUpstashProvisioner(): ServiceProvisioner {\n let apiKey: string | null = null\n let email: string | null = null\n\n return {\n name: 'upstash',\n serviceType: 'cache',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Upstash')\n try {\n const userEmail = credentials.email ?? ''\n const userKey = credentials.apiKey ?? credentials.api_key ?? credentials.token ?? ''\n if (!userEmail || !userKey) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'email, api_key' } }))\n }\n\n await listUpstashDatabases(userEmail, userKey)\n\n email = userEmail\n apiKey = userKey\n logger.info('Upstash authenticated', { email: userEmail })\n return ok(userEmail)\n }\n catch (error) {\n logger.error('Upstash authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!apiKey || !email) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Upstash Redis', { appName })\n try {\n const databaseName = `${appName}-cache`\n\n const existingDatabase = await findExistingUpstashDatabase(email, apiKey, databaseName)\n if (existingDatabase !== null) {\n const databaseId = existingDatabase.database_id ?? ''\n if (!databaseId) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Upstash' } }))\n }\n\n const detail = await getUpstashDatabase(email, apiKey, databaseId)\n logger.info('Upstash Redis reused', { databaseId, databaseName })\n return ok(buildUpstashProvisionResult({ ...existingDatabase, ...detail }))\n }\n\n const data = await upstashFetch<UpstashDatabase>(email, apiKey, '/v2/redis/database', {\n method: 'POST',\n body: JSON.stringify({\n name: databaseName,\n region: 'global',\n tls: true,\n }),\n })\n\n logger.info('Upstash Redis provisioned', { databaseId: data.database_id })\n\n return ok(buildUpstashProvisionResult(data))\n }\n catch (error) {\n logger.error('Upstash provisioning failed', { appName, error })\n return err(\n HaiDeployError.PROVISION_FAILED,\n deployM('deploy_provisionFailed', {\n params: {\n service: 'upstash',\n error: error instanceof Error ? error.message : String(error),\n },\n }),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/deploy — 模块主入口\n *\n * 提供 deploy 单例对象,暴露完整的自动化部署 API。\n * @module deploy-main\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { DeployConfig, DeployConfigInput } from './deploy-config.js'\nimport type { DeployProvider, ServiceProvisioner } from './deploy-internal-types.js'\nimport type {\n DeployAppOptions,\n DeployCredentialOperations,\n DeployFunctions,\n DeployResult,\n ProvisionResult,\n ScanResult,\n ServiceType,\n} from './deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { DeployConfigSchema } from './deploy-config.js'\nimport {\n getCredentialsPath,\n loadCredentials,\n saveCredential,\n saveCredentials,\n} from './deploy-credentials.js'\nimport { buildApp, resolveOutputDir } from './deploy-functions.js'\nimport { deployM } from './deploy-i18n.js'\nimport { scanApp } from './deploy-scanner.js'\nimport { HaiDeployError } from './deploy-types.js'\nimport { createVercelProvider } from './providers/deploy-provider-vercel.js'\nimport { createAliyunProvisioner } from './provisioners/deploy-provisioner-aliyun.js'\nimport { createNeonProvisioner } from './provisioners/deploy-provisioner-neon.js'\nimport { createR2Provisioner } from './provisioners/deploy-provisioner-r2.js'\nimport { createResendProvisioner } from './provisioners/deploy-provisioner-resend.js'\nimport { createUpstashProvisioner } from './provisioners/deploy-provisioner-upstash.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'main' })\n\n// ─── 内部状态 ───\n\nlet currentConfig: DeployConfig | null = null\nlet currentProvider: DeployProvider | null = null\nconst currentProvisioners: Map<ServiceType, ServiceProvisioner> = new Map()\n\n/** 并发初始化防护标志 */\nlet initInProgress = false\n\n// ─── 未初始化占位 ───\n\nconst notInitialized = core.module.createNotInitializedKit(\n HaiDeployError.NOT_INITIALIZED,\n () => deployM('deploy_notInitialized'),\n)\n\n// ─── Provider 工厂 ───\n\n/**\n * 根据配置类型创建对应的 DeployProvider\n *\n * @param type - Provider 类型\n * @returns DeployProvider 实例\n */\nfunction createProviderByType(type: string): DeployProvider {\n switch (type) {\n case 'vercel':\n return createVercelProvider()\n default:\n throw new Error(deployM('deploy_unsupportedProviderType', { params: { type } }))\n }\n}\n\n// ─── Provisioner 工厂 ───\n\n/**\n * 根据 provisioner 名称创建对应的 ServiceProvisioner\n *\n * @param provisioner - Provisioner 标识\n * @returns ServiceProvisioner 实例\n */\nfunction createProvisionerByName(provisioner: string): ServiceProvisioner {\n switch (provisioner) {\n case 'neon':\n return createNeonProvisioner()\n case 'upstash':\n return createUpstashProvisioner()\n case 'cloudflare-r2':\n return createR2Provisioner()\n case 'resend':\n return createResendProvisioner()\n case 'aliyun':\n return createAliyunProvisioner()\n default:\n throw new Error(deployM('deploy_unsupportedProvisionerType', { params: { type: provisioner } }))\n }\n}\n\n/**\n * 从配置中提取 provisioner 凭证并转为 Record<string, string>\n *\n * @param serviceConfig - 服务配置对象\n * @returns 凭证键值对\n */\nfunction extractCredentials(serviceConfig: Record<string, unknown>): Record<string, string> {\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(serviceConfig)) {\n if (key !== 'provisioner' && typeof value === 'string') {\n result[key] = value\n }\n }\n return result\n}\n\n/**\n * Deploy 凭证子功能。\n *\n * 这些操作仅处理本地 `~/.hai/credentials.yml`,供 CLI 在读取 `_deploy.yml`\n * 之前注入 `HAI_DEPLOY_*` 环境变量,因此不依赖 `deploy.init()`。\n */\nconst deployCredentials: DeployCredentialOperations = {\n getPath: () => getCredentialsPath(),\n load: () => loadCredentials(),\n save: (key: string, value: string) => saveCredential(key, value),\n saveAll: (entries: Record<string, string>) => saveCredentials(entries),\n}\n\n// ─── 模块单例 ───\n\n/**\n * Deploy 模块单例\n *\n * @example\n * ```ts\n * import { deploy } from '@h-ai/deploy'\n *\n * await deploy.init({ provider: { type: 'vercel', token: 'xxx' } })\n * const result = await deploy.deployApp('./apps/my-app')\n * await deploy.close()\n * ```\n */\nexport const deploy: DeployFunctions = {\n credentials: deployCredentials,\n\n async init(config: DeployConfigInput): Promise<HaiResult<void>> {\n // 并发初始化防护:避免多次 init 同时执行导致资源泄漏\n if (initInProgress) {\n logger.warn('Deploy init already in progress, skipping concurrent call')\n return err(\n HaiDeployError.CONFIG_ERROR,\n deployM('deploy_configError', { params: { error: 'init already in progress' } }),\n )\n }\n initInProgress = true\n\n try {\n if (currentProvider) {\n logger.warn('Deploy module is already initialized, reinitializing')\n await deploy.close()\n }\n\n logger.info('Initializing deploy module')\n\n const parseResult = DeployConfigSchema.safeParse(config)\n if (!parseResult.success) {\n logger.error('Deploy config validation failed', { error: parseResult.error.message })\n return err(\n HaiDeployError.CONFIG_ERROR,\n deployM('deploy_configError', { params: { error: parseResult.error.message } }),\n parseResult.error,\n )\n }\n const parsed = parseResult.data\n\n try {\n // 创建 Provider\n const provider = createProviderByType(parsed.provider.type)\n const authResult = await provider.authenticate(parsed.provider.token)\n if (!authResult.success) {\n return err(authResult.error)\n }\n logger.info('Provider authenticated', { provider: parsed.provider.type, user: authResult.data })\n\n // 创建 Provisioners\n currentProvisioners.clear()\n if (parsed.services) {\n const serviceEntries = Object.entries(parsed.services) as Array<[ServiceType, Record<string, unknown> | undefined]>\n for (const [serviceType, serviceConfig] of serviceEntries) {\n if (!serviceConfig)\n continue\n\n const provisioner = createProvisionerByName(serviceConfig.provisioner as string)\n const credentials = extractCredentials(serviceConfig as Record<string, unknown>)\n const provAuthResult = await provisioner.authenticate(credentials)\n if (!provAuthResult.success) {\n logger.error('Provisioner authentication failed', {\n service: serviceType,\n provisioner: (serviceConfig as Record<string, unknown>).provisioner,\n })\n currentProvisioners.clear()\n return err(provAuthResult.error)\n }\n logger.info('Provisioner authenticated', {\n service: serviceType,\n user: provAuthResult.data,\n })\n currentProvisioners.set(serviceType, provisioner)\n }\n }\n\n currentProvider = provider\n currentConfig = parsed\n logger.info('Deploy module initialized', {\n provider: parsed.provider.type,\n provisioners: [...currentProvisioners.keys()],\n })\n return ok(undefined)\n }\n catch (error) {\n // 清理部分赋值的状态\n currentProvider = null\n currentConfig = null\n currentProvisioners.clear()\n logger.error('Deploy module initialization failed', { error })\n return err(\n HaiDeployError.CONFIG_ERROR,\n deployM('deploy_configError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n }\n finally {\n initInProgress = false\n }\n },\n\n async close(): Promise<void> {\n if (!currentProvider) {\n logger.info('Deploy module already closed, skipping')\n return\n }\n\n logger.info('Closing deploy module')\n currentProvider = null\n currentConfig = null\n currentProvisioners.clear()\n logger.info('Deploy module closed')\n },\n\n get config(): DeployConfig | null {\n return currentConfig\n },\n\n get isInitialized(): boolean {\n return currentProvider !== null\n },\n\n async scan(appDir: string): Promise<HaiResult<ScanResult>> {\n // scan 仅做本地文件分析,不依赖 Provider / Provisioner 初始化状态。\n logger.debug('Scanning application', { appDir })\n return scanApp(appDir)\n },\n\n async provisionAll(projectName: string): Promise<HaiResult<ProvisionResult[]>> {\n if (!currentProvider) {\n return notInitialized.result()\n }\n\n logger.info('Provisioning all services', { projectName, count: currentProvisioners.size })\n const results: ProvisionResult[] = []\n\n for (const [serviceType, provisioner] of currentProvisioners) {\n logger.debug('Provisioning service', { serviceType, provisioner: provisioner.name })\n const provResult = await provisioner.provision(projectName)\n if (!provResult.success) {\n logger.error('Service provisioning failed', {\n serviceType,\n provisioner: provisioner.name,\n error: provResult.error,\n })\n return err(provResult.error)\n }\n results.push(provResult.data)\n logger.info('Service provisioned', { serviceType, provisioner: provisioner.name })\n }\n\n return ok(results)\n },\n\n async deployApp(\n appDir: string,\n options?: DeployAppOptions,\n ): Promise<HaiResult<DeployResult>> {\n if (!currentProvider) {\n return notInitialized.result()\n }\n\n logger.info('Starting deployment', { appDir, options })\n\n // 1. 扫描应用\n const scanResult = await scanApp(appDir)\n if (!scanResult.success) {\n return err(scanResult.error)\n }\n const scan = scanResult.data\n const projectName = options?.projectName ?? scan.appName\n\n // 2. 检查 adapter\n if (scan.isSvelteKit && !scan.adapterInstalled) {\n return err(\n HaiDeployError.ADAPTER_MISSING,\n deployM('deploy_adapterMissing', {\n params: { adapter: '@sveltejs/adapter-vercel' },\n }),\n )\n }\n\n // 3. 开通基础设施\n let allEnvVars: Record<string, string> = {}\n if (!options?.skipProvision) {\n const provResults = await deploy.provisionAll(projectName)\n if (!provResults.success) {\n return err(provResults.error)\n }\n for (const prov of provResults.data) {\n allEnvVars = { ...allEnvVars, ...prov.envVars }\n }\n }\n\n // 4. 创建平台项目\n const projectResult = await currentProvider.createProject(projectName)\n if (!projectResult.success) {\n return err(projectResult.error)\n }\n const projectId = projectResult.data\n\n // 5. 设置环境变量\n if (Object.keys(allEnvVars).length > 0) {\n const envResult = await currentProvider.setEnvVars(projectId, allEnvVars)\n if (!envResult.success) {\n return err(envResult.error)\n }\n }\n\n // 6. 构建应用\n if (!options?.skipBuild) {\n const buildResult = buildApp(appDir, scan.buildCommand)\n if (!buildResult.success) {\n return err(buildResult.error)\n }\n }\n\n // 7. 部署\n const outputDir = resolveOutputDir(appDir, currentConfig?.provider.type ?? 'vercel')\n const deployResult = await currentProvider.deploy(projectId, outputDir)\n if (!deployResult.success) {\n return err(deployResult.error)\n }\n\n // 补充环境变量列表到结果中\n const result: DeployResult = {\n ...deployResult.data,\n envVarsSet: Object.keys(allEnvVars),\n }\n\n logger.info('Deployment completed', {\n url: result.url,\n deploymentId: result.deploymentId,\n status: result.status,\n })\n\n return ok(result)\n },\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/deploy-i18n.ts","../src/deploy-config.ts","../src/deploy-types.ts","../src/deploy-credentials.ts","../src/deploy-functions.ts","../src/deploy-recovery.ts","../src/deploy-scanner.ts","../src/providers/deploy-provider-vercel.ts","../src/provisioners/deploy-provisioner-aliyun.ts","../src/provisioners/deploy-provisioner-neon.ts","../src/provisioners/deploy-provisioner-r2.ts","../src/provisioners/deploy-provisioner-resend.ts","../src/provisioners/deploy-provisioner-upstash.ts","../src/deploy-main.ts"],"names":["core","logger","process","ok","err","join","existsSync","z","readFileSync","parse","readdirSync","connectionUri"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"deploy_notInitialized\": \"Deploy module not initialized, call deploy.init() first\",\n \"deploy_initFailed\": \"Deploy module initialization failed: {error}\",\n \"deploy_unsupportedProviderType\": \"Unsupported deploy provider type: {type}\",\n \"deploy_unsupportedProvisionerType\": \"Unsupported service provisioner type: {type}\",\n \"deploy_configTokenRequired\": \"Deploy provider token is required\",\n \"deploy_authRequired\": \"Authentication required\",\n \"deploy_authFailed\": \"Authentication failed: {error}\",\n \"deploy_projectCreateFailed\": \"Project creation failed: {error}\",\n \"deploy_buildFailed\": \"Application build failed: {error}\",\n \"deploy_uploadFailed\": \"Build output upload failed: {error}\",\n \"deploy_deployFailed\": \"Deployment failed: {error}\",\n \"deploy_provisionFailed\": \"Service provisioning failed: {service} - {error}\",\n \"deploy_adapterMissing\": \"Target platform adapter not found, please install {adapter}\",\n \"deploy_scanFailed\": \"Application scan failed: {error}\",\n \"deploy_envVarFailed\": \"Environment variable setup failed: {error}\",\n \"deploy_credentialError\": \"Credential read/write failed: {error}\",\n \"deploy_credentialInvalidKey\": \"Unsupported credential key: {key}. Only HAI_DEPLOY_* keys are allowed\",\n \"deploy_credentialSaved\": \"Credentials saved\",\n \"deploy_credentialLoaded\": \"Credentials loaded\",\n \"deploy_configError\": \"Deploy config error: {error}\",\n \"deploy_credentialMissing\": \"Missing credential fields: {fields}\",\n \"deploy_apiError\": \"{service} API error ({status})\",\n \"deploy_fileUploadFailed\": \"File upload failed ({status})\",\n \"deploy_provisionNoResult\": \"No connection info returned from {service}\",\n \"deploy_recoveryFailure\": \"Deployment stopped at {stage}; inspect the recovery details.\",\n \"deploy_recoverySuggestion\": \"Inspect listed resources in the provider console before retrying with the same project name. Unknown means the request may have created a resource. Reused resources are never deleted automatically; remove newly created resources manually only after checking their use.\"\n}\n","{\n \"deploy_notInitialized\": \"Deploy 模块尚未初始化,请先调用 deploy.init()\",\n \"deploy_initFailed\": \"Deploy 模块初始化失败:{error}\",\n \"deploy_unsupportedProviderType\": \"不支持的部署平台类型:{type}\",\n \"deploy_unsupportedProvisionerType\": \"不支持的服务 Provisioner 类型:{type}\",\n \"deploy_configTokenRequired\": \"部署平台 Token 不能为空\",\n \"deploy_authRequired\": \"请先完成认证\",\n \"deploy_authFailed\": \"认证失败:{error}\",\n \"deploy_projectCreateFailed\": \"项目创建失败:{error}\",\n \"deploy_buildFailed\": \"应用构建失败:{error}\",\n \"deploy_uploadFailed\": \"构建产物上传失败:{error}\",\n \"deploy_deployFailed\": \"部署失败:{error}\",\n \"deploy_provisionFailed\": \"基础设施开通失败:{service} - {error}\",\n \"deploy_adapterMissing\": \"未检测到目标平台 adapter,请安装 {adapter}\",\n \"deploy_scanFailed\": \"应用扫描失败:{error}\",\n \"deploy_envVarFailed\": \"环境变量设置失败:{error}\",\n \"deploy_credentialError\": \"凭证读写失败:{error}\",\n \"deploy_credentialInvalidKey\": \"不支持的凭证键名:{key}。仅允许 HAI_DEPLOY_*\",\n \"deploy_credentialSaved\": \"凭证已保存\",\n \"deploy_credentialLoaded\": \"凭证已加载\",\n \"deploy_configError\": \"部署配置错误:{error}\",\n \"deploy_credentialMissing\": \"缺少凭证字段:{fields}\",\n \"deploy_apiError\": \"{service} API 请求失败({status})\",\n \"deploy_fileUploadFailed\": \"文件上传失败({status})\",\n \"deploy_provisionNoResult\": \"{service} 未返回连接信息\",\n \"deploy_recoveryFailure\": \"部署在 {stage} 阶段停止,请查看恢复清单。\",\n \"deploy_recoverySuggestion\": \"重试前在服务商控制台核对清单,并使用相同项目名。unknown 表示请求可能已创建资源。复用资源不会自动删除;新建资源仅在确认未被使用后人工清理。\"\n}\n","/**\n * @h-ai/deploy — i18n\n *\n * 本文件提供部署模块的 i18n 文案访问入口。\n * @module deploy-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n// ─── i18n ───\n\n/** 部署模块文案 Key 类型 */\ntype DeployMessageKey = keyof typeof messagesZhCN\n\n/**\n * 获取部署模块文案\n *\n * @param key - 文案 Key\n * @param options - 插值参数与格式化选项\n * @returns 本地化后的文案字符串\n *\n * @example\n * ```ts\n * const text = deployM('deploy_notInitialized')\n * ```\n */\nexport const deployM = core.i18n.createMessageGetter<DeployMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n})\n","/**\n * @h-ai/deploy — 部署配置 Schema\n *\n * 本文件定义部署模块的错误码、Zod Schema 和配置类型。\n * @module deploy-config\n */\n\nimport { z } from 'zod'\nimport { deployM } from './deploy-i18n.js'\n\n// ─── Provider 配置 Schema ───\n\n/** Vercel 部署平台配置 */\nconst VercelProviderConfigSchema = z.object({\n type: z.literal('vercel'),\n token: z.string().min(1, deployM('deploy_configTokenRequired')),\n})\n\n/** 部署平台配置联合类型(后续可扩展更多平台) */\nexport const ProviderConfigSchema = z.discriminatedUnion('type', [\n VercelProviderConfigSchema,\n])\n\n// ─── Provisioner 配置 Schema ───\n\n/** Neon PostgreSQL 服务配置 */\nconst NeonServiceSchema = z.object({\n provisioner: z.literal('neon'),\n apiKey: z.string().min(1),\n})\n\n/** Upstash Redis 服务配置 */\nconst UpstashServiceSchema = z.object({\n provisioner: z.literal('upstash'),\n email: z.string().email(),\n apiKey: z.string().min(1),\n})\n\n/** Cloudflare R2 存储服务配置 */\nconst R2ServiceSchema = z.object({\n provisioner: z.literal('cloudflare-r2'),\n accessKeyId: z.string().min(1),\n secretAccessKey: z.string().min(1),\n accountId: z.string().min(1),\n apiToken: z.string().min(1),\n})\n\n/** Resend 邮件服务配置 */\nconst ResendServiceSchema = z.object({\n provisioner: z.literal('resend'),\n from: z.string().email(),\n apiKey: z.string().min(1),\n})\n\n/** 阿里云短信服务配置 */\nconst AliyunSmsServiceSchema = z.object({\n provisioner: z.literal('aliyun'),\n signName: z.string().min(1),\n accessKeyId: z.string().min(1),\n accessKeySecret: z.string().min(1),\n})\n\n/** 基础设施服务配置 */\nconst ServicesConfigSchema = z.object({\n db: z.discriminatedUnion('provisioner', [NeonServiceSchema]).optional(),\n cache: z.discriminatedUnion('provisioner', [UpstashServiceSchema]).optional(),\n storage: z.discriminatedUnion('provisioner', [R2ServiceSchema]).optional(),\n email: z.discriminatedUnion('provisioner', [ResendServiceSchema]).optional(),\n sms: z.discriminatedUnion('provisioner', [AliyunSmsServiceSchema]).optional(),\n}).optional()\n\n// ─── 完整配置 Schema ───\n\n/** 部署模块完整配置 Schema */\nexport const DeployConfigSchema = z.object({\n provider: ProviderConfigSchema,\n services: ServicesConfigSchema,\n})\n\n/** 部署配置类型(parse 后) */\nexport type DeployConfig = z.infer<typeof DeployConfigSchema>\n\n/** 部署配置输入类型(用户输入) */\nexport type DeployConfigInput = z.input<typeof DeployConfigSchema>\n","/**\n * @h-ai/deploy — 类型定义\n *\n * 本文件定义部署模块的核心接口和类型(非配置相关)。 配置相关类型请从 deploy-config.ts 导入。\n * @module deploy-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport type { DeployConfig, DeployConfigInput } from './deploy-config.js'\nimport { core } from '@h-ai/core'\n\n// ─── 错误定义(照 @h-ai/core 范式) ───\n\nconst DeployErrorInfo = {\n DEPLOY_FAILED: '001:500',\n PROJECT_CREATE_FAILED: '002:500',\n BUILD_FAILED: '003:500',\n UPLOAD_FAILED: '004:500',\n AUTH_REQUIRED: '005:401',\n AUTH_FAILED: '006:401',\n PROVISION_FAILED: '007:500',\n ADAPTER_MISSING: '008:500',\n SCAN_FAILED: '009:500',\n NOT_INITIALIZED: '010:500',\n ENV_VAR_FAILED: '011:500',\n UNSUPPORTED_TYPE: '012:400',\n CONFIG_ERROR: '013:500',\n CREDENTIAL_ERROR: '014:500',\n} as const satisfies ErrorInfo\n\nexport const HaiDeployError = core.error.buildHaiErrorsDef('deploy', DeployErrorInfo)\n\n/**\n * 部署错误接口\n *\n * 所有部署操作返回的错误都遵循此接口。\n *\n * @example\n * ```ts\n * const result = await deploy.deployApp('./apps/my-app')\n * if (!result.success) {\n * const error: DeployError = result.error\n * // 根据 error.code 处理\n * }\n * ```\n */\nexport interface DeployError {\n /** 错误定义 */\n def: (typeof HaiDeployError)[keyof typeof HaiDeployError]\n /** 错误消息 */\n message: string\n /** 原始错误(可选) */\n cause?: unknown\n}\n\n// ─── 服务类型 ───\n\n/** 基础设施服务类型 */\nexport type ServiceType = 'db' | 'cache' | 'storage' | 'email' | 'sms'\n\n// ─── 扫描结果 ───\n\n/**\n * 应用扫描结果\n *\n * 由 scanner 分析应用目录后返回,描述应用的框架类型、依赖和部署需求。\n */\nexport interface ScanResult {\n /** 应用名称(来自 package.json name) */\n appName: string\n /** 是否为 SvelteKit 项目 */\n isSvelteKit: boolean\n /** 目标平台 adapter 是否已安装(如 @sveltejs/adapter-vercel) */\n adapterInstalled: boolean\n /** 检测到的模块依赖需要的服务列表 */\n requiredServices: ServiceType[]\n /** 构建命令 */\n buildCommand: string\n}\n\n// ─── 部署结果 ───\n\n/**\n * 部署结果\n *\n * 包含部署后的访问 URL、状态和已设置的环境变量。\n */\nexport interface DeployResult {\n /** 部署后的访问 URL */\n url: string\n /** 部署 ID */\n deploymentId: string\n /** 部署状态 */\n status: 'ready' | 'building' | 'error'\n /** 已设置的环境变量名列表 */\n envVarsSet: string[]\n}\n\n// ─── 开通结果 ───\n\n/**\n * 基础设施开通结果\n *\n * 由 Provisioner 开通服务后返回,包含要注入到部署平台的环境变量。\n */\nexport interface ProvisionResult {\n /** 本次新建或复用;凭证型服务始终为 reused */\n resourceStatus: 'created' | 'reused'\n /** 服务类型 */\n serviceType: ServiceType\n /** Provisioner 名称 */\n provisionerName: string\n /** 要注入到部署平台的环境变量 */\n envVars: Record<string, string>\n /** 资源标识信息(如项目名、数据库名等),用于日志和展示 */\n resourceInfo: string\n}\n\n/** 部署失败后的安全恢复信息,不含环境变量值或原始异常。 */\nexport interface DeployRecoveryInfo {\n projectName: string\n stage: string\n platformProjectId?: string\n resources: Array<{\n serviceType: ServiceType\n provisionerName: string\n resourceInfo: string\n resourceStatus: 'created' | 'reused' | 'unknown'\n }>\n}\n\n// ─── 部署选项 ───\n\n/** 部署选项 */\nexport interface DeployAppOptions {\n /** 项目名称(默认从 package.json name 提取) */\n projectName?: string\n /** 是否跳过基础设施开通 */\n skipProvision?: boolean\n /** 是否跳过构建 */\n skipBuild?: boolean\n}\n\n// ─── 凭证子功能 ───\n\n/**\n * Deploy 凭证文件操作。\n *\n * 这些方法仅操作 `~/.hai/credentials.yml`,不依赖 `deploy.init()`。\n */\nexport interface DeployCredentialOperations {\n /** 获取凭证文件绝对路径。 */\n getPath: () => string\n /** 加载凭证文件并注入 `process.env`。 */\n load: () => HaiResult<string[]>\n /** 保存单个凭证。 */\n save: (key: string, value: string) => HaiResult<void>\n /** 批量保存凭证。 */\n saveAll: (entries: Record<string, string>) => HaiResult<void>\n}\n\n// ─── 模块功能接口 ───\n\n/**\n * Deploy 模块功能接口\n *\n * 提供自动化部署的完整 API:\n * - `deploy.credentials.*()` — 凭证文件读写(不依赖 init)\n * - `deploy.init()` — 初始化(加载配置、创建 Provider 和 Provisioner)\n * - `deploy.scan()` — 扫描应用依赖(纯文件系统能力,不依赖 init)\n * - `deploy.provisionAll()` — 开通所有已配置的基础设施\n * - `deploy.deployApp()` — 完整部署流程\n * - `deploy.close()` — 关闭模块\n *\n * @example\n * ```ts\n * import { deploy } from '@h-ai/deploy'\n *\n * await deploy.init({ provider: { type: 'vercel', token: 'xxx' } })\n * const result = await deploy.deployApp('./apps/my-app')\n * if (result.success) {\n * console.log(`Deployed: ${result.data.url}`)\n * }\n * await deploy.close()\n * ```\n */\nexport interface DeployFunctions {\n /** 全局部署凭证文件操作。 */\n readonly credentials: DeployCredentialOperations\n /** 初始化模块(加载配置、创建 Provider 和 Provisioner 实例) */\n init: (config: DeployConfigInput) => Promise<HaiResult<void>>\n /** 关闭模块 */\n close: () => Promise<void>\n /** 当前配置 */\n readonly config: DeployConfig | null\n /** 是否已初始化 */\n readonly isInitialized: boolean\n\n /**\n * 扫描应用目录,检测依赖和所需服务。\n *\n * 这是纯文件系统分析能力,不依赖云端认证状态,可在 `deploy.init()` 之前调用。\n *\n * @param appDir - 应用根目录路径\n */\n scan: (appDir: string) => Promise<HaiResult<ScanResult>>\n\n /**\n * 对所有已配置的 Provisioner 执行基础设施开通\n *\n * @param projectName - 用于资源命名的项目名\n * @returns 所有 Provisioner 的结果列表\n */\n provisionAll: (projectName: string) => Promise<HaiResult<ProvisionResult[]>>\n\n /**\n * 执行完整部署流程(provision → build → deploy)\n *\n * @param appDir - 应用根目录路径\n * @param options - 部署选项\n */\n deployApp: (appDir: string, options?: DeployAppOptions) => Promise<HaiResult<DeployResult>>\n}\n","/**\n * @h-ai/deploy — 凭证管理\n *\n * 管理全局凭证文件 `~/.hai/credentials.yml`。\n * 这些 helper 由 `deploy.credentials.*` 对外暴露,供 CLI 在加载 `_deploy.yml`\n * 之前注入 `HAI_DEPLOY_*` 环境变量。\n * @module deploy-credentials\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport process from 'node:process'\nimport { core, err, ok } from '@h-ai/core'\nimport { parse, stringify } from 'yaml'\nimport { deployM } from './deploy-i18n.js'\nimport { HaiDeployError } from './deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'credentials' })\n\n/** 仅允许写入 deploy 模块自有的环境变量前缀,避免把任意 YAML key 注入 process.env。 */\nconst DEPLOY_CREDENTIAL_KEY_PATTERN = /^HAI_DEPLOY_[A-Z0-9_]+$/\n\n// ─── 内部工具 ───\n\n/** 校验凭证键名是否属于 deploy 模块。 */\nfunction isAllowedCredentialKey(key: string): boolean {\n return DEPLOY_CREDENTIAL_KEY_PATTERN.test(key)\n}\n\n/**\n * 标准化凭证键值对。\n *\n * 仅保留 `HAI_DEPLOY_*` 键,且值必须是可安全序列化为字符串的标量。\n */\nfunction normalizeCredentialEntries(entries: Record<string, unknown>): Record<string, string> {\n const normalized: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(entries)) {\n if (!isAllowedCredentialKey(key)) {\n logger.warn('Ignoring unsupported deploy credential key', { key })\n continue\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n normalized[key] = String(value)\n continue\n }\n\n logger.warn('Ignoring deploy credential with non-scalar value', { key })\n }\n\n return normalized\n}\n\n/** 在写入前校验单个凭证键名。 */\nfunction assertAllowedCredentialKey(key: string): void {\n if (!isAllowedCredentialKey(key)) {\n throw new Error(deployM('deploy_credentialInvalidKey', { params: { key } }))\n }\n}\n\n/** 在写入前校验批量凭证键名。 */\nfunction assertAllowedCredentialEntries(entries: Record<string, string>): void {\n for (const key of Object.keys(entries)) {\n assertAllowedCredentialKey(key)\n }\n}\n\n/**\n * 获取凭证文件路径\n *\n * @returns `~/.hai/credentials.yml` 的绝对路径\n */\nexport function getCredentialsPath(): string {\n return join(homedir(), '.hai', 'credentials.yml')\n}\n\n/**\n * 确保凭证目录存在\n *\n * @param filePath - 凭证文件路径\n */\nfunction ensureDir(filePath: string): void {\n const dir = dirname(filePath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n}\n\n/**\n * 读取凭证文件内容\n *\n * @returns 解析后的键值对,文件不存在时返回空对象\n */\nfunction readCredentialsFile(): Record<string, string> {\n const filePath = getCredentialsPath()\n if (!existsSync(filePath)) {\n return {}\n }\n const content = readFileSync(filePath, 'utf-8')\n const parsed = parse(content)\n if (parsed === null || parsed === undefined || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return {}\n }\n return normalizeCredentialEntries(parsed as Record<string, unknown>)\n}\n\n/**\n * 写入凭证文件\n *\n * @param data - 凭证键值对\n */\nfunction writeCredentialsFile(data: Record<string, string>): void {\n const filePath = getCredentialsPath()\n ensureDir(filePath)\n const header = '# Managed by hai cli - do not edit manually\\n'\n const content = header + stringify(data)\n writeFileSync(filePath, content, { encoding: 'utf-8', mode: 0o600 })\n}\n\n// ─── 公共 API ───\n\n/**\n * 加载全局凭证文件并注入到 process.env\n *\n * 读取 `~/.hai/credentials.yml` 中的所有键值对,\n * 将每个 key-value 设置到 `process.env` 中,\n * 使后续 core 配置加载时自动解析 `${HAI_DEPLOY_*}` 变量。\n *\n * @returns 成功返回加载的凭证键名列表\n *\n * @example\n * ```ts\n * const result = loadCredentials()\n * if (result.success) {\n * console.log(`Loaded ${result.data.length} credentials`)\n * }\n * ```\n */\nexport function loadCredentials(): HaiResult<string[]> {\n try {\n const data = readCredentialsFile()\n const keys = Object.keys(data)\n for (const key of keys) {\n process.env[key] = String(data[key])\n }\n logger.debug('Credentials loaded', { count: keys.length })\n return ok(keys)\n }\n catch (error) {\n logger.error('Failed to load credentials', { error })\n return err(\n HaiDeployError.CREDENTIAL_ERROR,\n deployM('deploy_credentialError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 保存单个凭证到全局凭证文件\n *\n * 读取已有凭证 → 合并新凭证 → 写回文件。已有同名 key 会被覆盖。\n *\n * @param key - 环境变量名(如 HAI_DEPLOY_VERCEL_TOKEN)\n * @param value - 凭证值\n *\n * @example\n * ```ts\n * saveCredential('HAI_DEPLOY_VERCEL_TOKEN', 'vel_xxx')\n * ```\n */\nexport function saveCredential(key: string, value: string): HaiResult<void> {\n try {\n assertAllowedCredentialKey(key)\n const data = readCredentialsFile()\n data[key] = value\n writeCredentialsFile(data)\n process.env[key] = value\n logger.debug('Credential saved', { key })\n return ok(undefined)\n }\n catch (error) {\n logger.error('Failed to save credential', { key, error })\n return err(\n HaiDeployError.CREDENTIAL_ERROR,\n deployM('deploy_credentialError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 批量保存凭证到全局凭证文件\n *\n * @param entries - 凭证键值对\n *\n * @example\n * ```ts\n * saveCredentials({\n * HAI_DEPLOY_VERCEL_TOKEN: 'vel_xxx',\n * HAI_DEPLOY_NEON_API_KEY: 'neon_xxx',\n * })\n * ```\n */\nexport function saveCredentials(entries: Record<string, string>): HaiResult<void> {\n try {\n assertAllowedCredentialEntries(entries)\n const data = readCredentialsFile()\n for (const [key, value] of Object.entries(entries)) {\n data[key] = value\n process.env[key] = value\n }\n writeCredentialsFile(data)\n logger.debug('Credentials saved', { count: Object.keys(entries).length })\n return ok(undefined)\n }\n catch (error) {\n logger.error('Failed to save credentials', { error })\n return err(\n HaiDeployError.CREDENTIAL_ERROR,\n deployM('deploy_credentialError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n","/**\n * @h-ai/deploy — 部署辅助函数\n *\n * 包含构建、产物目录解析等与部署流程相关的辅助操作。 从 deploy-main.ts 中提取,遵循 main 仅做生命周期管理的规范。\n * @module deploy-functions\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport { execSync } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport process from 'node:process'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from './deploy-i18n.js'\nimport { HaiDeployError } from './deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'functions' })\n\n/**\n * 执行应用构建\n *\n * @param appDir - 应用根目录\n * @param buildCommand - 构建命令\n * @param envVars - 当前部署开通结果,确保构建与运行使用同一配置\n * @returns 构建结果\n */\nexport function buildApp(appDir: string, buildCommand: string, envVars: Record<string, string> = {}): HaiResult<void> {\n logger.info('Building application', { appDir, buildCommand })\n try {\n execSync(buildCommand, {\n cwd: appDir,\n stdio: 'inherit',\n env: { ...process.env, ...envVars },\n })\n return ok(undefined)\n }\n catch (error) {\n return err(\n HaiDeployError.BUILD_FAILED,\n deployM('deploy_buildFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 解析构建产物目录\n *\n * @param appDir - 应用根目录\n * @param providerType - Provider 类型\n * @returns 产物目录路径\n */\nexport function resolveOutputDir(appDir: string, providerType: string): string {\n switch (providerType) {\n case 'vercel': {\n const vercelOutput = join(appDir, '.vercel', 'output')\n if (existsSync(vercelOutput)) {\n return vercelOutput\n }\n // 回退到标准 build 目录\n return join(appDir, 'build')\n }\n default:\n return join(appDir, 'build')\n }\n}\n","import type { HaiError, HaiResult } from '@h-ai/core'\nimport type { DeployRecoveryInfo } from './deploy-types.js'\nimport { err } from '@h-ai/core'\nimport { z } from 'zod'\nimport { deployM } from './deploy-i18n.js'\n\nconst RecoverySchema = z.object({\n projectName: z.string(),\n stage: z.string(),\n platformProjectId: z.string().optional(),\n resources: z.array(z.object({\n serviceType: z.enum(['db', 'cache', 'storage', 'email', 'sms']),\n provisionerName: z.string(),\n resourceInfo: z.string(),\n resourceStatus: z.enum(['created', 'reused', 'unknown']),\n })),\n})\n\n/** 读取错误中的恢复清单;仅返回明确允许展示的字段。 */\nexport function getDeployRecovery(error: HaiError): DeployRecoveryInfo | undefined {\n const parsed = RecoverySchema.safeParse(error.ext?.recovery)\n return parsed.success ? parsed.data : undefined\n}\n\n/** 在错误中保留可展示的恢复信息,避免异常 cause/命令/URL 泄漏凭证。 */\nexport function recoveryFailure(error: HaiError, recovery: DeployRecoveryInfo): HaiResult<never> {\n return err({\n code: error.code,\n httpStatus: error.httpStatus,\n system: error.system,\n module: error.module,\n message: deployM('deploy_recoveryFailure', { params: { stage: recovery.stage } }),\n suggestion: deployM('deploy_recoverySuggestion'),\n ext: { recovery },\n })\n}\n","/**\n * @h-ai/deploy — 应用扫描器\n *\n * 扫描应用目录,检测框架类型、模块依赖和所需基础设施。\n * @module deploy-scanner\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ScanResult, ServiceType } from './deploy-types.js'\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { core, err, ok } from '@h-ai/core'\nimport { parse } from 'yaml'\nimport { deployM } from './deploy-i18n.js'\nimport { HaiDeployError } from './deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'scanner' })\n\n// ─── 内部工具 ───\n\n/**\n * 安全读取并解析 YAML 文件\n *\n * @param filePath - YAML 文件路径\n * @returns 解析结果,文件不存在或解析失败时返回 null\n */\nfunction readYaml(filePath: string): Record<string, unknown> | null {\n if (!existsSync(filePath)) {\n return null\n }\n try {\n const content = readFileSync(filePath, 'utf-8')\n const parsed = parse(content)\n if (parsed === null || parsed === undefined || typeof parsed !== 'object') {\n return null\n }\n return parsed as Record<string, unknown>\n }\n catch {\n return null\n }\n}\n\n/**\n * 安全读取 JSON 文件\n *\n * @param filePath - JSON 文件路径\n * @returns 解析结果,文件不存在或解析失败时返回 null\n */\nfunction readJson(filePath: string): Record<string, unknown> | null {\n if (!existsSync(filePath)) {\n return null\n }\n try {\n const content = readFileSync(filePath, 'utf-8')\n return JSON.parse(content) as Record<string, unknown>\n }\n catch {\n return null\n }\n}\n\n/**\n * 检测 package.json 的 dependencies + devDependencies 中是否包含指定包\n *\n * @param pkg - package.json 内容\n * @param name - 包名\n */\nfunction hasDependency(pkg: Record<string, unknown>, name: string): boolean {\n const deps = pkg.dependencies as Record<string, string> | undefined\n const devDeps = pkg.devDependencies as Record<string, string> | undefined\n return (deps !== undefined && name in deps) || (devDeps !== undefined && name in devDeps)\n}\n\n/**\n * 扫描 config/ 目录,推断所需基础设施服务\n *\n * @param configDir - 配置目录路径\n * @returns 需要的服务类型列表\n */\nfunction detectRequiredServices(configDir: string): ServiceType[] {\n const services: ServiceType[] = []\n\n if (!existsSync(configDir)) {\n return services\n }\n\n const files = readdirSync(configDir)\n\n // 检测数据库需求\n if (files.includes('_db.yml') || files.includes('_db.yaml')) {\n const dbConfig = readYaml(join(configDir, files.find(f => f.startsWith('_db.'))!))\n // sqlite 在云端也需要切换为 postgresql,标记为需要 db\n if (dbConfig !== null) {\n services.push('db')\n }\n }\n\n // 检测缓存需求\n if (files.includes('_cache.yml') || files.includes('_cache.yaml')) {\n const cacheConfig = readYaml(join(configDir, files.find(f => f.startsWith('_cache.'))!))\n if (cacheConfig !== null) {\n const cacheType = cacheConfig.type as string | undefined\n // memory 模式不需要外部服务,redis 需要\n if (cacheType === 'redis') {\n services.push('cache')\n }\n }\n }\n\n // 检测存储需求\n if (files.includes('_storage.yml') || files.includes('_storage.yaml')) {\n const storageConfig = readYaml(join(configDir, files.find(f => f.startsWith('_storage.'))!))\n if (storageConfig !== null) {\n detectStorageServices(storageConfig, services)\n }\n }\n\n // 检测 reach(邮件 / 短信)需求\n if (files.includes('_reach.yml') || files.includes('_reach.yaml')) {\n const reachConfig = readYaml(join(configDir, files.find(f => f.startsWith('_reach.'))!))\n if (reachConfig !== null) {\n detectReachServices(reachConfig, services)\n }\n }\n\n return services\n}\n\n/**\n * 检测存储配置中的 S3 需求\n *\n * @param config - 存储配置内容\n * @param services - 服务列表(原地修改)\n */\nfunction detectStorageServices(config: Record<string, unknown>, services: ServiceType[]): void {\n // 直接配置\n if (config.type === 's3') {\n services.push('storage')\n return\n }\n // 多 provider 配置\n const providers = config.providers as Record<string, unknown> | undefined\n if (providers === undefined) {\n return\n }\n for (const providerConfig of Object.values(providers)) {\n const typed = providerConfig as Record<string, unknown> | undefined\n if (typed?.type === 's3') {\n services.push('storage')\n return\n }\n }\n}\n\n/**\n * 检测 reach 配置中的邮件和短信需求\n *\n * @param config - reach 配置内容\n * @param services - 服务列表(原地修改)\n */\nfunction detectReachServices(config: Record<string, unknown>, services: ServiceType[]): void {\n const providers = config.providers as Array<Record<string, unknown>> | undefined\n if (!Array.isArray(providers)) {\n return\n }\n\n let hasEmail = false\n let hasSms = false\n\n for (const provider of providers) {\n const providerType = provider.type as string | undefined\n // smtp / api / resend 类型视为邮件需求\n if (!hasEmail && (providerType === 'smtp' || providerType === 'api')) {\n hasEmail = true\n services.push('email')\n }\n // aliyun-sms 类型视为短信需求\n if (!hasSms && providerType === 'aliyun-sms') {\n hasSms = true\n services.push('sms')\n }\n }\n}\n\n// ─── 公共 API ───\n\n/**\n * 扫描应用目录,检测框架类型、模块依赖和所需基础设施\n *\n * @param appDir - 应用根目录绝对路径\n * @returns 扫描结果(ScanResult)\n *\n * @example\n * ```ts\n * const result = await scanApp('/path/to/my-app')\n * if (result.success) {\n * const { appName, isSvelteKit, requiredServices } = result.data\n * }\n * ```\n */\nexport async function scanApp(appDir: string): Promise<HaiResult<ScanResult>> {\n logger.debug('Scanning application', { appDir })\n\n try {\n // 读取 package.json\n const pkg = readJson(join(appDir, 'package.json'))\n if (pkg === null) {\n return err(\n HaiDeployError.SCAN_FAILED,\n deployM('deploy_scanFailed', { params: { error: 'package.json not found' } }),\n )\n }\n\n const appName = extractAppName(pkg)\n const isSvelteKit = existsSync(join(appDir, 'svelte.config.js'))\n || existsSync(join(appDir, 'svelte.config.ts'))\n const adapterInstalled = hasDependency(pkg, '@sveltejs/adapter-vercel')\n const configDir = join(appDir, 'config')\n const configServices = detectRequiredServices(configDir)\n const depServices = detectServicesFromDependencies(pkg)\n // 合并去重:config 检测优先,依赖检测补充\n const requiredServices = Array.from(new Set([...configServices, ...depServices]))\n const scripts = pkg.scripts as Record<string, string> | undefined\n const buildCommand = scripts?.build ?? 'pnpm build'\n\n const scanResult: ScanResult = {\n appName,\n isSvelteKit,\n adapterInstalled,\n requiredServices,\n buildCommand,\n }\n\n logger.info('Application scanned', {\n appName,\n isSvelteKit,\n adapterInstalled,\n requiredServices,\n })\n\n return ok(scanResult)\n }\n catch (error) {\n logger.error('Application scan failed', { appDir, error })\n return err(\n HaiDeployError.SCAN_FAILED,\n deployM('deploy_scanFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n}\n\n/**\n * 从 package.json 的 @h-ai/* 依赖推断所需服务\n *\n * 依赖映射规则:\n * - @h-ai/reldb → 'db'\n * - @h-ai/cache → 'cache'\n * - @h-ai/storage → 'storage'\n *\n * @param pkg - package.json 内容\n * @returns 需要的服务类型列表\n */\nfunction detectServicesFromDependencies(pkg: Record<string, unknown>): ServiceType[] {\n const depMap: Record<string, ServiceType> = {\n '@h-ai/reldb': 'db',\n '@h-ai/cache': 'cache',\n '@h-ai/storage': 'storage',\n }\n const services: ServiceType[] = []\n for (const [depName, serviceType] of Object.entries(depMap)) {\n if (hasDependency(pkg, depName)) {\n services.push(serviceType)\n }\n }\n return services\n}\n\n/**\n * 从 package.json 提取应用名称\n *\n * 移除 scope 前缀(如 @h-ai/admin-console → admin-console)\n *\n * @param pkg - package.json 内容\n * @returns 应用名称\n */\nfunction extractAppName(pkg: Record<string, unknown>): string {\n const name = (pkg.name as string) ?? 'app'\n // 移除 scope 前缀\n const slashIndex = name.indexOf('/')\n if (slashIndex >= 0) {\n return name.slice(slashIndex + 1)\n }\n return name\n}\n","/**\n * @h-ai/deploy — Vercel 部署 Provider\n *\n * 封装 Vercel REST API,实现 DeployProvider 接口。 使用原生 fetch 调用,零外部 SDK 依赖。\n * @module deploy-provider-vercel\n */\n\nimport type { HaiError, HaiErrorDef, HaiResult } from '@h-ai/core'\nimport type { DeployProvider } from '../deploy-internal-types.js'\nimport type { DeployResult } from '../deploy-types.js'\nimport { createHash } from 'node:crypto'\nimport { readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, relative, sep } from 'node:path'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provider-vercel' })\n\n/** Vercel API 基址 */\nconst VERCEL_API = 'https://api.vercel.com'\n\n/** 部署状态轮询间隔(毫秒) */\nconst POLL_INTERVAL = 3000\n\n/** 部署状态轮询最大次数 */\nconst MAX_POLL_ATTEMPTS = 60\n\n// ─── 内部工具 ───\n\n/** Vercel API 错误,保留状态码用于区分 404 与真实失败 */\nclass VercelApiError extends Error {\n constructor(readonly status: number) {\n super(deployM('deploy_apiError', { params: { service: 'Vercel', status: String(status) } }))\n }\n}\n\n/** 构造标准错误对象 */\nfunction toDeployError(codeDef: HaiErrorDef, messageKey: string, error: unknown): HaiError {\n return {\n ...codeDef,\n message: deployM(messageKey as Parameters<typeof deployM>[0], {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n cause: error,\n }\n}\n\n/**\n * 发送 Vercel API 请求\n *\n * @param token - API Token\n * @param path - API 路径(如 /v2/user)\n * @param options - fetch 选项\n * @returns 解析后的 JSON 响应\n */\nasync function vercelFetch<T>(token: string, path: string, options?: RequestInit): Promise<T> {\n const url = `${VERCEL_API}${path}`\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n ...options?.headers,\n },\n })\n\n if (!response.ok) {\n throw new VercelApiError(response.status)\n }\n\n return response.json() as Promise<T>\n}\n\n/**\n * 递归收集目录中的所有文件\n *\n * @param dir - 目录路径\n * @param baseDir - 基础目录(用于计算相对路径)\n * @returns 文件相对路径列表\n */\nfunction collectFiles(dir: string, baseDir: string): string[] {\n const results: string[] = []\n const entries = readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...collectFiles(fullPath, baseDir))\n }\n else {\n results.push(relative(baseDir, fullPath).split(sep).join('/'))\n }\n }\n\n return results\n}\n\n// ─── Provider 工厂 ───\n\n/**\n * 创建 Vercel 部署 Provider\n *\n * @returns DeployProvider 实例\n *\n * @example\n * ```ts\n * const provider = createVercelProvider()\n * await provider.authenticate('vel_xxx')\n * const projectId = await provider.createProject('my-app')\n * ```\n */\nexport function createVercelProvider(): DeployProvider {\n let token: string | null = null\n\n return {\n name: 'vercel',\n\n async authenticate(apiToken: string): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Vercel')\n try {\n const user = await vercelFetch<{ user: { username: string, email: string } }>(\n apiToken,\n '/v2/user',\n )\n token = apiToken\n const username = user.user.username || user.user.email\n logger.info('Vercel authenticated', { user: username })\n return ok(username)\n }\n catch (error) {\n logger.error('Vercel authentication failed', { error })\n return err(toDeployError(HaiDeployError.AUTH_FAILED, 'deploy_authFailed', error))\n }\n },\n\n async createProject(projectName: string): Promise<HaiResult<string>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Creating Vercel project', { projectName })\n try {\n // 先查找已有项目\n const existingId = await findExistingProject(token, projectName)\n if (existingId !== null) {\n logger.info('Vercel project found', { projectName, projectId: existingId })\n return ok(existingId)\n }\n\n try {\n const project = await vercelFetch<{ id: string }>(\n token,\n '/v11/projects',\n {\n method: 'POST',\n body: JSON.stringify({\n name: projectName,\n framework: 'sveltekit',\n }),\n },\n )\n logger.info('Vercel project created', { projectName, projectId: project.id })\n return ok(project.id)\n }\n catch (error) {\n // 官方文档说明同名项目创建会返回 409;遇到并发竞争时回查现有项目即可实现幂等。\n if (error instanceof VercelApiError && error.status === 409) {\n const concurrentProjectId = await findExistingProject(token, projectName)\n if (concurrentProjectId !== null) {\n logger.info('Vercel project reused after create conflict', {\n projectName,\n projectId: concurrentProjectId,\n })\n return ok(concurrentProjectId)\n }\n }\n throw error\n }\n }\n catch (error) {\n logger.error('Vercel project creation failed', { projectName, error })\n return err(toDeployError(HaiDeployError.PROJECT_CREATE_FAILED, 'deploy_projectCreateFailed', error))\n }\n },\n\n async setEnvVars(projectId: string, envVars: Record<string, string>): Promise<HaiResult<void>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Setting Vercel env vars', { projectId, count: Object.keys(envVars).length })\n try {\n const envEntries = Object.entries(envVars).map(([key, value]) => ({\n key,\n value,\n type: 'encrypted' as const,\n target: ['production', 'preview', 'development'],\n }))\n\n // Vercel 官方 `upsert=true` 支持按 key 覆盖已有环境变量,避免重复部署时报“已存在”。\n await vercelFetch(\n token,\n `/v10/projects/${projectId}/env?upsert=true`,\n {\n method: 'POST',\n body: JSON.stringify(envEntries),\n },\n )\n logger.info('Vercel env vars set', { projectId, count: envEntries.length })\n return ok(undefined)\n }\n catch (error) {\n logger.error('Vercel env vars setup failed', { projectId, error })\n return err(toDeployError(HaiDeployError.ENV_VAR_FAILED, 'deploy_envVarFailed', error))\n }\n },\n\n async deploy(projectId: string, outputDir: string): Promise<HaiResult<DeployResult>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Deploying to Vercel', { projectId, outputDir })\n try {\n // 收集所有文件\n const filePaths = collectFiles(outputDir, outputDir)\n const files: Array<{ file: string, sha: string, size: number }> = []\n\n // 上传每个文件\n for (const filePath of filePaths) {\n const fullPath = join(outputDir, filePath)\n const content = readFileSync(fullPath)\n const sha = createHash('sha1').update(content).digest('hex')\n const size = statSync(fullPath).size\n\n await uploadFile(token, content, sha)\n files.push({ file: filePath, sha, size })\n }\n\n logger.debug('Files uploaded', { count: files.length })\n\n // 创建部署\n const deployment = await vercelFetch<{ id: string, url: string }>(\n token,\n '/v13/deployments',\n {\n method: 'POST',\n body: JSON.stringify({\n name: projectId,\n files,\n projectSettings: { framework: 'sveltekit' },\n }),\n },\n )\n\n // 轮询部署状态\n const finalStatus = await pollDeploymentStatus(token, deployment.id)\n\n const result: DeployResult = {\n url: `https://${deployment.url}`,\n deploymentId: deployment.id,\n status: finalStatus,\n envVarsSet: [],\n }\n\n logger.info('Vercel deployment complete', {\n deploymentId: deployment.id,\n url: result.url,\n status: finalStatus,\n })\n\n return ok(result)\n }\n catch (error) {\n logger.error('Vercel deployment failed', { projectId, error })\n return err(toDeployError(HaiDeployError.UPLOAD_FAILED, 'deploy_uploadFailed', error))\n }\n },\n }\n}\n\n// ─── 内部辅助 ───\n\n/**\n * 查找已有的 Vercel 项目\n *\n * @param token - API Token\n * @param projectName - 项目名称\n * @returns 项目 ID,不存在时返回 null\n */\nasync function findExistingProject(token: string, projectName: string): Promise<string | null> {\n try {\n const project = await vercelFetch<{ id: string }>(token, `/v10/projects/${projectName}`)\n return project.id\n }\n catch (error) {\n if (error instanceof VercelApiError && error.status === 404) {\n return null\n }\n throw error\n }\n}\n\n/**\n * 上传单个文件到 Vercel\n *\n * @param token - API Token\n * @param content - 文件内容\n * @param sha - 文件 SHA1 哈希\n */\nasync function uploadFile(token: string, content: Uint8Array, sha: string): Promise<void> {\n const url = `${VERCEL_API}/v2/files`\n const uploadContent = new Uint8Array(content)\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/octet-stream',\n 'x-vercel-digest': sha,\n },\n body: new Blob([uploadContent]),\n })\n\n if (!response.ok && response.status !== 409) {\n // 409 表示文件已存在,可忽略\n throw new Error(deployM('deploy_fileUploadFailed', { params: { status: String(response.status) } }))\n }\n}\n\n/**\n * 轮询部署状态直到完成\n *\n * @param token - API Token\n * @param deploymentId - 部署 ID\n * @returns 最终状态\n */\nasync function pollDeploymentStatus(\n token: string,\n deploymentId: string,\n): Promise<'ready' | 'building' | 'error'> {\n for (let i = 0; i < MAX_POLL_ATTEMPTS; i++) {\n const deployment = await vercelFetch<{ readyState: string }>(\n token,\n `/v13/deployments/${deploymentId}`,\n )\n\n if (deployment.readyState === 'READY') {\n return 'ready'\n }\n if (deployment.readyState === 'ERROR' || deployment.readyState === 'CANCELED') {\n return 'error'\n }\n\n // 等待后重试\n await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL))\n }\n\n // 超时仍在构建\n return 'building'\n}\n","/**\n * @h-ai/deploy — Aliyun SMS Provisioner\n *\n * 验证阿里云 API 凭证用于短信服务。 阿里云短信资源(签名/模板)通常在控制台预配置,此 Provisioner 仅验证凭证。\n * @module deploy-provisioner-aliyun\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-aliyun' })\n\n/**\n * 创建 Aliyun SMS Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createAliyunProvisioner(): ServiceProvisioner {\n let accessKey: string | null = null\n let secretKey: string | null = null\n let signName = ''\n\n return {\n name: 'aliyun',\n serviceType: 'sms',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Aliyun')\n try {\n const akId = credentials.accessKeyId ?? credentials.access_key_id ?? credentials.access_key ?? ''\n const akSecret = credentials.accessKeySecret ?? credentials.access_key_secret ?? credentials.secret_key ?? ''\n\n if (!akId || !akSecret || !credentials.signName) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'accessKeyId, accessKeySecret, signName' } }))\n }\n\n accessKey = akId\n secretKey = akSecret\n signName = credentials.signName\n logger.info('Aliyun authenticated', { accessKeyId: `${akId.slice(0, 6)}***` })\n return ok(akId)\n }\n catch (error) {\n logger.error('Aliyun authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(_appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!accessKey || !secretKey) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Aliyun SMS service')\n\n // 阿里云短信不支持 API 创建资源,仅返回凭证作为环境变量\n return ok({\n serviceType: 'sms',\n provisionerName: 'aliyun',\n resourceStatus: 'reused',\n envVars: {\n HAI_REACH_PROVIDERS: JSON.stringify([{ name: 'sms', type: 'aliyun-sms', accessKeyId: accessKey, accessKeySecret: secretKey, signName }]),\n },\n resourceInfo: 'aliyun:verify-only',\n })\n },\n }\n}\n","/**\n * @h-ai/deploy — Neon PostgreSQL Provisioner\n *\n * 通过 Neon REST API 自动创建 PostgreSQL 数据库。\n * @module deploy-provisioner-neon\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { recoveryFailure } from '../deploy-recovery.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-neon' })\n\n/** Neon API 基址 */\nconst NEON_API = 'https://console.neon.tech/api/v2'\n\n/** Neon 新建项目默认生成的数据库名。 */\nconst DEFAULT_NEON_DATABASE_NAME = 'neondb'\n\n/** Neon 新建项目默认生成的角色名。 */\nconst DEFAULT_NEON_ROLE_NAME = 'neondb_owner'\n\ninterface NeonProjectSummary {\n id: string\n name: string\n}\n\ninterface NeonProjectsResponse {\n projects?: NeonProjectSummary[]\n}\n\ninterface NeonCreateProjectResponse {\n connection_uris?: Array<{ connection_uri?: string }>\n project?: { id?: string }\n}\n\ninterface NeonConnectionUriResponse {\n uri?: string\n}\n\n/** 统一发起 Neon API 请求。 */\nasync function neonFetch<T>(token: string, path: string, options?: RequestInit): Promise<T> {\n const response = await fetch(`${NEON_API}${path}`, {\n ...options,\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n ...options?.headers,\n },\n })\n\n if (!response.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Neon', status: String(response.status) } }))\n }\n\n return response.json() as Promise<T>\n}\n\n/** 列出当前账号下的 Neon 项目。 */\nasync function listNeonProjects(token: string): Promise<NeonProjectSummary[]> {\n const data = await neonFetch<NeonProjectsResponse>(token, '/projects')\n return data.projects ?? []\n}\n\n/** 按名称查找已有的 Neon 项目。 */\nasync function findExistingNeonProject(token: string, projectName: string): Promise<NeonProjectSummary | null> {\n const projects = await listNeonProjects(token)\n return projects.find(project => project.name === projectName) ?? null\n}\n\n/**\n * 获取现有项目的连接串。\n *\n * Neon 官方 OpenAPI 提供 `GET /projects/{project_id}/connection_uri`。\n * 这里使用创建项目时的默认数据库/角色名,保证本模块创建的项目可被幂等复用。\n */\nasync function getNeonConnectionUri(token: string, projectId: string): Promise<string> {\n const query = new URLSearchParams({\n database_name: DEFAULT_NEON_DATABASE_NAME,\n role_name: DEFAULT_NEON_ROLE_NAME,\n })\n const data = await neonFetch<NeonConnectionUriResponse>(\n token,\n `/projects/${projectId}/connection_uri?${query.toString()}`,\n { headers: { 'Content-Type': 'application/json' } },\n )\n\n if (!data.uri) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Neon' } }))\n }\n\n return data.uri\n}\n\n/** 构建统一的 Neon 开通结果。 */\nfunction buildNeonProvisionResult(projectId: string, connectionUri: string, resourceStatus: 'created' | 'reused'): ProvisionResult {\n return {\n serviceType: 'db',\n provisionerName: 'neon',\n resourceStatus,\n envVars: {\n HAI_DB: JSON.stringify({ type: 'postgresql', url: connectionUri, database: decodeURIComponent(new URL(connectionUri).pathname.slice(1)) }),\n },\n resourceInfo: `neon-project:${projectId}`,\n }\n}\n\n/**\n * 创建 Neon PostgreSQL Provisioner\n *\n * @returns ServiceProvisioner 实例\n *\n * @example\n * ```ts\n * const neon = createNeonProvisioner()\n * await neon.authenticate({ apiKey: 'neon_xxx' })\n * const result = await neon.provision('my-app')\n * ```\n */\nexport function createNeonProvisioner(): ServiceProvisioner {\n let token: string | null = null\n\n return {\n name: 'neon',\n serviceType: 'db',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Neon')\n try {\n const apiToken = credentials.apiKey ?? credentials.token ?? credentials.api_key ?? ''\n if (!apiToken) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'token' } }))\n }\n\n await listNeonProjects(apiToken)\n token = apiToken\n logger.info('Neon authenticated')\n return ok('neon-user')\n }\n catch (error) {\n logger.error('Neon authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Neon database', { appName })\n let resource: { resourceInfo: string, resourceStatus: 'created' | 'reused' } | undefined\n try {\n const projectName = `${appName}-db`\n\n const existingProject = await findExistingNeonProject(token, projectName)\n if (existingProject !== null) {\n resource = { resourceInfo: `neon-project:${existingProject.id}`, resourceStatus: 'reused' }\n const connectionUri = await getNeonConnectionUri(token, existingProject.id)\n logger.info('Neon project reused', {\n projectId: existingProject.id,\n projectName,\n })\n return ok(buildNeonProvisionResult(existingProject.id, connectionUri, 'reused'))\n }\n\n const data = await neonFetch<NeonCreateProjectResponse>(token, '/projects', {\n method: 'POST',\n body: JSON.stringify({\n project: {\n name: projectName,\n pg_version: 16,\n },\n }),\n })\n\n const projectId = data.project?.id ?? ''\n if (projectId)\n resource = { resourceInfo: `neon-project:${projectId}`, resourceStatus: 'created' }\n const connectionUri = data.connection_uris?.[0]?.connection_uri ?? ''\n if (!projectId || !connectionUri) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Neon' } }))\n }\n\n logger.info('Neon database provisioned', { projectId })\n\n return ok(buildNeonProvisionResult(projectId, connectionUri, 'created'))\n }\n catch (error) {\n logger.error('Neon provisioning failed', { appName })\n if (resource) {\n return recoveryFailure({ ...HaiDeployError.PROVISION_FAILED, message: '' }, {\n projectName: appName,\n stage: 'provision:db',\n resources: [{ serviceType: 'db', provisionerName: 'neon', ...resource }],\n })\n }\n return err(\n HaiDeployError.PROVISION_FAILED,\n deployM('deploy_provisionFailed', {\n params: {\n service: 'neon',\n error: error instanceof Error ? error.message : String(error),\n },\n }),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/deploy — Cloudflare R2 Provisioner\n *\n * 通过 Cloudflare API 自动创建 R2 存储桶。\n * @module deploy-provisioner-r2\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-r2' })\n\n/** Cloudflare API 基址 */\nconst CF_API = 'https://api.cloudflare.com/client/v4'\n\n/**\n * 创建 Cloudflare R2 Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createR2Provisioner(): ServiceProvisioner {\n let token: string | null = null\n let accountId: string | null = null\n let accessKey = ''\n let secretKey = ''\n\n return {\n name: 'r2',\n serviceType: 'storage',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Cloudflare')\n try {\n const acctId = credentials.accountId ?? credentials.account_id ?? ''\n const apiTok = credentials.apiToken ?? credentials.api_token ?? credentials.token ?? ''\n if (!acctId || !apiTok || !credentials.accessKeyId || !credentials.secretAccessKey) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'accountId, apiToken, accessKeyId, secretAccessKey' } }))\n }\n\n const res = await fetch(`${CF_API}/accounts/${acctId}/r2/buckets`, {\n headers: { Authorization: `Bearer ${apiTok}` },\n })\n if (!res.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Cloudflare', status: String(res.status) } }))\n }\n\n accountId = acctId\n token = apiTok\n accessKey = credentials.accessKeyId\n secretKey = credentials.secretAccessKey\n logger.info('Cloudflare R2 authenticated', { accountId: acctId })\n return ok(acctId)\n }\n catch (error) {\n logger.error('Cloudflare R2 authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!token || !accountId) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n const bucketName = `${appName}-storage`.toLowerCase().replace(/[^a-z0-9-]/g, '-')\n\n logger.debug('Provisioning R2 bucket', { appName, bucketName })\n try {\n // 创建桶\n const createRes = await fetch(\n `${CF_API}/accounts/${accountId}/r2/buckets`,\n {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ name: bucketName }),\n },\n )\n\n // 409 表示桶已存在,可继续\n if (!createRes.ok && createRes.status !== 409) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Cloudflare', status: String(createRes.status) } }))\n }\n\n logger.info('R2 bucket provisioned', { bucketName })\n\n return ok({\n serviceType: 'storage',\n provisionerName: 'r2',\n resourceStatus: createRes.status === 409 ? 'reused' : 'created',\n envVars: {\n HAI_STORAGE: JSON.stringify({\n type: 's3',\n endpoint: `https://${accountId}.r2.cloudflarestorage.com`,\n bucket: bucketName,\n region: 'auto',\n accessKeyId: accessKey,\n secretAccessKey: secretKey,\n }),\n },\n resourceInfo: `r2-bucket:${bucketName}`,\n })\n }\n catch (error) {\n logger.error('R2 provisioning failed', { appName, error })\n return err(\n HaiDeployError.PROVISION_FAILED,\n deployM('deploy_provisionFailed', {\n params: {\n service: 'r2',\n error: error instanceof Error ? error.message : String(error),\n },\n }),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/deploy — Resend Email Provisioner\n *\n * 通过 Resend REST API 验证 API Key 并获取域信息。 Resend 不支持通过 API 创建账户,此 Provisioner 仅验证已有凭证。\n * @module deploy-provisioner-resend\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\n\nimport { deployM } from '../deploy-i18n.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-resend' })\n\n/** Resend API 基址 */\nconst RESEND_API = 'https://api.resend.com'\n\n/**\n * 创建 Resend Email Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createResendProvisioner(): ServiceProvisioner {\n let token: string | null = null\n let from = ''\n\n return {\n name: 'resend',\n serviceType: 'email',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Resend')\n try {\n const apiToken = credentials.apiKey ?? credentials.api_key ?? credentials.token ?? ''\n if (!apiToken || !credentials.from) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'apiKey, from' } }))\n }\n\n const res = await fetch(`${RESEND_API}/domains`, {\n headers: { Authorization: `Bearer ${apiToken}` },\n })\n if (!res.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Resend', status: String(res.status) } }))\n }\n token = apiToken\n from = credentials.from\n logger.info('Resend authenticated')\n return ok('resend-user')\n }\n catch (error) {\n logger.error('Resend authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(_appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!token) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Resend email service')\n\n // Resend 不支持 API 创建资源,仅返回凭证作为环境变量\n return ok({\n serviceType: 'email',\n provisionerName: 'resend',\n resourceStatus: 'reused',\n envVars: {\n HAI_REACH_PROVIDERS: JSON.stringify([{ name: 'email', type: 'smtp', host: 'smtp.resend.com', port: 465, secure: true, user: 'resend', pass: token, from }]),\n },\n resourceInfo: 'resend:verify-only',\n })\n },\n }\n}\n","/**\n * @h-ai/deploy — Upstash Redis Provisioner\n *\n * 通过 Upstash REST API 自动创建 Redis 数据库。\n * @module deploy-provisioner-upstash\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ServiceProvisioner } from '../deploy-internal-types.js'\nimport type { ProvisionResult } from '../deploy-types.js'\nimport { Buffer } from 'node:buffer'\nimport { core, err, ok } from '@h-ai/core'\n\nimport { deployM } from '../deploy-i18n.js'\nimport { recoveryFailure } from '../deploy-recovery.js'\nimport { HaiDeployError } from '../deploy-types.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'provisioner-upstash' })\n\n/** Upstash API 基址 */\nconst UPSTASH_API = 'https://api.upstash.com'\n\ninterface UpstashDatabase {\n database_id?: string\n database_name?: string\n endpoint?: string\n port?: number\n password?: string\n}\n\n/** 构建 Upstash Developer API 的 Basic Auth 请求头。 */\nfunction createUpstashAuthHeader(email: string, apiKey: string): string {\n return `Basic ${Buffer.from(`${email}:${apiKey}`).toString('base64')}`\n}\n\n/** 统一发起 Upstash Developer API 请求。 */\nasync function upstashFetch<T>(\n email: string,\n apiKey: string,\n path: string,\n options?: RequestInit,\n): Promise<T> {\n const response = await fetch(`${UPSTASH_API}${path}`, {\n ...options,\n headers: {\n 'Authorization': createUpstashAuthHeader(email, apiKey),\n 'Content-Type': 'application/json',\n ...options?.headers,\n },\n })\n\n if (!response.ok) {\n throw new Error(deployM('deploy_apiError', { params: { service: 'Upstash', status: String(response.status) } }))\n }\n\n return response.json() as Promise<T>\n}\n\n/** 列出当前账号下的所有 Upstash 数据库。 */\nasync function listUpstashDatabases(email: string, apiKey: string): Promise<UpstashDatabase[]> {\n return upstashFetch<UpstashDatabase[]>(email, apiKey, '/v2/redis/databases')\n}\n\n/** 按数据库名查找已有资源。 */\nasync function findExistingUpstashDatabase(\n email: string,\n apiKey: string,\n databaseName: string,\n): Promise<UpstashDatabase | null> {\n const databases = await listUpstashDatabases(email, apiKey)\n return databases.find(database => database.database_name === databaseName) ?? null\n}\n\n/** 获取单个数据库详情。 */\nasync function getUpstashDatabase(email: string, apiKey: string, databaseId: string): Promise<UpstashDatabase> {\n return upstashFetch<UpstashDatabase>(email, apiKey, `/v2/redis/database/${databaseId}`)\n}\n\n/** 将 Upstash 响应转换为 deploy 统一结果。 */\nfunction buildUpstashProvisionResult(database: UpstashDatabase, resourceStatus: 'created' | 'reused'): ProvisionResult {\n const databaseId = database.database_id ?? ''\n\n if (!databaseId || !database.endpoint || !database.password || !database.port) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Upstash' } }))\n }\n\n return {\n serviceType: 'cache',\n provisionerName: 'upstash',\n resourceStatus,\n envVars: {\n HAI_CACHE: JSON.stringify({ type: 'redis', url: `rediss://default:${encodeURIComponent(database.password)}@${database.endpoint}:${database.port}` }),\n },\n resourceInfo: `upstash-db:${databaseId}`,\n }\n}\n\n/**\n * 创建 Upstash Redis Provisioner\n *\n * @returns ServiceProvisioner 实例\n */\nexport function createUpstashProvisioner(): ServiceProvisioner {\n let apiKey: string | null = null\n let email: string | null = null\n\n return {\n name: 'upstash',\n serviceType: 'cache',\n\n async authenticate(credentials: Record<string, string>): Promise<HaiResult<string>> {\n logger.debug('Authenticating with Upstash')\n try {\n const userEmail = credentials.email ?? ''\n const userKey = credentials.apiKey ?? credentials.api_key ?? credentials.token ?? ''\n if (!userEmail || !userKey) {\n throw new Error(deployM('deploy_credentialMissing', { params: { fields: 'email, api_key' } }))\n }\n\n await listUpstashDatabases(userEmail, userKey)\n\n email = userEmail\n apiKey = userKey\n logger.info('Upstash authenticated', { email: userEmail })\n return ok(userEmail)\n }\n catch (error) {\n logger.error('Upstash authentication failed', { error })\n return err(\n HaiDeployError.AUTH_FAILED,\n deployM('deploy_authFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n },\n\n async provision(appName: string): Promise<HaiResult<ProvisionResult>> {\n if (!apiKey || !email) {\n return err(\n HaiDeployError.AUTH_REQUIRED,\n deployM('deploy_authRequired'),\n )\n }\n\n logger.debug('Provisioning Upstash Redis', { appName })\n let resource: { resourceInfo: string, resourceStatus: 'created' | 'reused' } | undefined\n try {\n const databaseName = `${appName}-cache`\n\n const existingDatabase = await findExistingUpstashDatabase(email, apiKey, databaseName)\n if (existingDatabase !== null) {\n const databaseId = existingDatabase.database_id ?? ''\n if (!databaseId) {\n throw new Error(deployM('deploy_provisionNoResult', { params: { service: 'Upstash' } }))\n }\n\n resource = { resourceInfo: `upstash-db:${databaseId}`, resourceStatus: 'reused' }\n const detail = await getUpstashDatabase(email, apiKey, databaseId)\n logger.info('Upstash Redis reused', { databaseId, databaseName })\n return ok(buildUpstashProvisionResult({ ...existingDatabase, ...detail }, 'reused'))\n }\n\n const data = await upstashFetch<UpstashDatabase>(email, apiKey, '/v2/redis/database', {\n method: 'POST',\n body: JSON.stringify({\n name: databaseName,\n region: 'global',\n tls: true,\n }),\n })\n\n if (data.database_id)\n resource = { resourceInfo: `upstash-db:${data.database_id}`, resourceStatus: 'created' }\n logger.info('Upstash Redis provisioned', { databaseId: data.database_id })\n\n return ok(buildUpstashProvisionResult(data, 'created'))\n }\n catch (error) {\n logger.error('Upstash provisioning failed', { appName })\n if (resource) {\n return recoveryFailure({ ...HaiDeployError.PROVISION_FAILED, message: '' }, {\n projectName: appName,\n stage: 'provision:cache',\n resources: [{ serviceType: 'cache', provisionerName: 'upstash', ...resource }],\n })\n }\n return err(\n HaiDeployError.PROVISION_FAILED,\n deployM('deploy_provisionFailed', {\n params: {\n service: 'upstash',\n error: error instanceof Error ? error.message : String(error),\n },\n }),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/deploy — 模块主入口\n *\n * 提供 deploy 单例对象,暴露完整的自动化部署 API。\n * @module deploy-main\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { DeployConfig, DeployConfigInput } from './deploy-config.js'\nimport type { DeployProvider, ServiceProvisioner } from './deploy-internal-types.js'\nimport type {\n DeployAppOptions,\n DeployCredentialOperations,\n DeployFunctions,\n DeployRecoveryInfo,\n DeployResult,\n ProvisionResult,\n ScanResult,\n ServiceType,\n} from './deploy-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { DeployConfigSchema } from './deploy-config.js'\nimport {\n getCredentialsPath,\n loadCredentials,\n saveCredential,\n saveCredentials,\n} from './deploy-credentials.js'\nimport { buildApp, resolveOutputDir } from './deploy-functions.js'\nimport { deployM } from './deploy-i18n.js'\nimport { getDeployRecovery, recoveryFailure } from './deploy-recovery.js'\nimport { scanApp } from './deploy-scanner.js'\nimport { HaiDeployError } from './deploy-types.js'\nimport { createVercelProvider } from './providers/deploy-provider-vercel.js'\nimport { createAliyunProvisioner } from './provisioners/deploy-provisioner-aliyun.js'\nimport { createNeonProvisioner } from './provisioners/deploy-provisioner-neon.js'\nimport { createR2Provisioner } from './provisioners/deploy-provisioner-r2.js'\nimport { createResendProvisioner } from './provisioners/deploy-provisioner-resend.js'\nimport { createUpstashProvisioner } from './provisioners/deploy-provisioner-upstash.js'\n\nconst logger = core.logger.child({ module: 'deploy', scope: 'main' })\n\n// ─── 内部状态 ───\n\nlet currentConfig: DeployConfig | null = null\nlet currentProvider: DeployProvider | null = null\nconst currentProvisioners: Map<ServiceType, ServiceProvisioner> = new Map()\n\n/** 并发初始化防护标志 */\nlet initInProgress = false\n\n// ─── 未初始化占位 ───\n\nconst notInitialized = core.module.createNotInitializedKit(\n HaiDeployError.NOT_INITIALIZED,\n () => deployM('deploy_notInitialized'),\n)\n\n// ─── Provider 工厂 ───\n\n/**\n * 根据配置类型创建对应的 DeployProvider\n *\n * @param type - Provider 类型\n * @returns DeployProvider 实例\n */\nfunction createProviderByType(type: string): DeployProvider {\n switch (type) {\n case 'vercel':\n return createVercelProvider()\n default:\n throw new Error(deployM('deploy_unsupportedProviderType', { params: { type } }))\n }\n}\n\n// ─── Provisioner 工厂 ───\n\n/**\n * 根据 provisioner 名称创建对应的 ServiceProvisioner\n *\n * @param provisioner - Provisioner 标识\n * @returns ServiceProvisioner 实例\n */\nfunction createProvisionerByName(provisioner: string): ServiceProvisioner {\n switch (provisioner) {\n case 'neon':\n return createNeonProvisioner()\n case 'upstash':\n return createUpstashProvisioner()\n case 'cloudflare-r2':\n return createR2Provisioner()\n case 'resend':\n return createResendProvisioner()\n case 'aliyun':\n return createAliyunProvisioner()\n default:\n throw new Error(deployM('deploy_unsupportedProvisionerType', { params: { type: provisioner } }))\n }\n}\n\n/**\n * 从配置中提取 provisioner 凭证并转为 Record<string, string>\n *\n * @param serviceConfig - 服务配置对象\n * @returns 凭证键值对\n */\nfunction extractCredentials(serviceConfig: Record<string, unknown>): Record<string, string> {\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(serviceConfig)) {\n if (key !== 'provisioner' && typeof value === 'string') {\n result[key] = value\n }\n }\n return result\n}\n\n/**\n * Deploy 凭证子功能。\n *\n * 这些操作仅处理本地 `~/.hai/credentials.yml`,供 CLI 在读取 `_deploy.yml`\n * 之前注入 `HAI_DEPLOY_*` 环境变量,因此不依赖 `deploy.init()`。\n */\nconst deployCredentials: DeployCredentialOperations = {\n getPath: () => getCredentialsPath(),\n load: () => loadCredentials(),\n save: (key: string, value: string) => saveCredential(key, value),\n saveAll: (entries: Record<string, string>) => saveCredentials(entries),\n}\n\n// ─── 模块单例 ───\n\n/**\n * Deploy 模块单例\n *\n * @example\n * ```ts\n * import { deploy } from '@h-ai/deploy'\n *\n * await deploy.init({ provider: { type: 'vercel', token: 'xxx' } })\n * const result = await deploy.deployApp('./apps/my-app')\n * await deploy.close()\n * ```\n */\nexport const deploy: DeployFunctions = {\n credentials: deployCredentials,\n\n async init(config: DeployConfigInput): Promise<HaiResult<void>> {\n // 并发初始化防护:避免多次 init 同时执行导致资源泄漏\n if (initInProgress) {\n logger.warn('Deploy init already in progress, skipping concurrent call')\n return err(\n HaiDeployError.CONFIG_ERROR,\n deployM('deploy_configError', { params: { error: 'init already in progress' } }),\n )\n }\n initInProgress = true\n\n try {\n if (currentProvider) {\n logger.warn('Deploy module is already initialized, reinitializing')\n await deploy.close()\n }\n\n logger.info('Initializing deploy module')\n\n const parseResult = DeployConfigSchema.safeParse(config)\n if (!parseResult.success) {\n logger.error('Deploy config validation failed', { error: parseResult.error.message })\n return err(\n HaiDeployError.CONFIG_ERROR,\n deployM('deploy_configError', { params: { error: parseResult.error.message } }),\n parseResult.error,\n )\n }\n const parsed = parseResult.data\n\n try {\n // 创建 Provider\n const provider = createProviderByType(parsed.provider.type)\n const authResult = await provider.authenticate(parsed.provider.token)\n if (!authResult.success) {\n return err(authResult.error)\n }\n logger.info('Provider authenticated', { provider: parsed.provider.type, user: authResult.data })\n\n // 创建 Provisioners\n currentProvisioners.clear()\n if (parsed.services) {\n const serviceEntries = Object.entries(parsed.services) as Array<[ServiceType, Record<string, unknown> | undefined]>\n for (const [serviceType, serviceConfig] of serviceEntries) {\n if (!serviceConfig)\n continue\n\n const provisioner = createProvisionerByName(serviceConfig.provisioner as string)\n const credentials = extractCredentials(serviceConfig as Record<string, unknown>)\n const provAuthResult = await provisioner.authenticate(credentials)\n if (!provAuthResult.success) {\n logger.error('Provisioner authentication failed', {\n service: serviceType,\n provisioner: (serviceConfig as Record<string, unknown>).provisioner,\n })\n currentProvisioners.clear()\n return err(provAuthResult.error)\n }\n logger.info('Provisioner authenticated', {\n service: serviceType,\n user: provAuthResult.data,\n })\n currentProvisioners.set(serviceType, provisioner)\n }\n }\n\n currentProvider = provider\n currentConfig = parsed\n logger.info('Deploy module initialized', {\n provider: parsed.provider.type,\n provisioners: [...currentProvisioners.keys()],\n })\n return ok(undefined)\n }\n catch (error) {\n // 清理部分赋值的状态\n currentProvider = null\n currentConfig = null\n currentProvisioners.clear()\n logger.error('Deploy module initialization failed', { error })\n return err(\n HaiDeployError.CONFIG_ERROR,\n deployM('deploy_configError', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n }\n finally {\n initInProgress = false\n }\n },\n\n async close(): Promise<void> {\n if (!currentProvider) {\n logger.info('Deploy module already closed, skipping')\n return\n }\n\n logger.info('Closing deploy module')\n currentProvider = null\n currentConfig = null\n currentProvisioners.clear()\n logger.info('Deploy module closed')\n },\n\n get config(): DeployConfig | null {\n return currentConfig\n },\n\n get isInitialized(): boolean {\n return currentProvider !== null\n },\n\n async scan(appDir: string): Promise<HaiResult<ScanResult>> {\n // scan 仅做本地文件分析,不依赖 Provider / Provisioner 初始化状态。\n logger.debug('Scanning application', { appDir })\n return scanApp(appDir)\n },\n\n async provisionAll(projectName: string): Promise<HaiResult<ProvisionResult[]>> {\n if (!currentProvider) {\n return notInitialized.result()\n }\n\n logger.info('Provisioning all services', { projectName, count: currentProvisioners.size })\n const results: ProvisionResult[] = []\n\n for (const [serviceType, provisioner] of currentProvisioners) {\n logger.debug('Provisioning service', { serviceType, provisioner: provisioner.name })\n const provResult = await provisioner.provision(projectName)\n if (!provResult.success) {\n logger.error('Service provisioning failed', {\n serviceType,\n provisioner: provisioner.name,\n code: provResult.error.code,\n })\n return recoveryFailure(provResult.error, {\n projectName,\n stage: `provision:${serviceType}`,\n resources: [\n ...results.map(({ envVars: _envVars, ...resource }) => resource),\n ...(getDeployRecovery(provResult.error)?.resources ?? [\n { serviceType, provisionerName: provisioner.name, resourceInfo: projectName, resourceStatus: 'unknown' as const },\n ]),\n ],\n })\n }\n results.push(provResult.data)\n logger.info('Service provisioned', { serviceType, provisioner: provisioner.name })\n }\n\n return ok(results)\n },\n\n async deployApp(\n appDir: string,\n options?: DeployAppOptions,\n ): Promise<HaiResult<DeployResult>> {\n if (!currentProvider) {\n return notInitialized.result()\n }\n\n logger.info('Starting deployment', { appDir, options })\n\n // 1. 扫描应用\n const scanResult = await scanApp(appDir)\n if (!scanResult.success) {\n return err(scanResult.error)\n }\n const scan = scanResult.data\n const projectName = options?.projectName ?? scan.appName\n\n // 2. 检查 adapter\n if (scan.isSvelteKit && !scan.adapterInstalled) {\n return err(\n HaiDeployError.ADAPTER_MISSING,\n deployM('deploy_adapterMissing', {\n params: { adapter: '@sveltejs/adapter-vercel' },\n }),\n )\n }\n\n // 3. 开通基础设施\n let allEnvVars: Record<string, string> = {}\n const recovery: DeployRecoveryInfo = { projectName, stage: 'provision', resources: [] }\n if (!options?.skipProvision) {\n const provResults = await deploy.provisionAll(projectName)\n if (!provResults.success) {\n return err(provResults.error)\n }\n recovery.resources = provResults.data.map(({ envVars: _envVars, ...resource }) => resource)\n const reachProviders: unknown[] = []\n for (const prov of provResults.data) {\n if (prov.envVars.HAI_REACH_PROVIDERS)\n reachProviders.push(...JSON.parse(prov.envVars.HAI_REACH_PROVIDERS) as unknown[])\n allEnvVars = { ...allEnvVars, ...prov.envVars }\n }\n if (reachProviders.length > 0)\n allEnvVars.HAI_REACH_PROVIDERS = JSON.stringify(reachProviders)\n }\n\n // 4. 创建平台项目\n const projectResult = await currentProvider.createProject(projectName)\n if (!projectResult.success) {\n return recoveryFailure(projectResult.error, { ...recovery, stage: 'create-project' })\n }\n const projectId = projectResult.data\n recovery.platformProjectId = projectId\n\n // 5. 设置环境变量\n if (Object.keys(allEnvVars).length > 0) {\n const envResult = await currentProvider.setEnvVars(projectId, allEnvVars)\n if (!envResult.success) {\n return recoveryFailure(envResult.error, { ...recovery, stage: 'set-env' })\n }\n }\n\n // 6. 构建应用\n if (!options?.skipBuild) {\n const buildResult = buildApp(appDir, scan.buildCommand, allEnvVars)\n if (!buildResult.success) {\n return recoveryFailure(buildResult.error, { ...recovery, stage: 'build' })\n }\n }\n\n // 7. 部署\n const outputDir = resolveOutputDir(appDir, currentConfig?.provider.type ?? 'vercel')\n const deployResult = await currentProvider.deploy(projectId, outputDir)\n if (!deployResult.success) {\n return recoveryFailure(deployResult.error, { ...recovery, stage: 'deploy' })\n }\n\n // 补充环境变量列表到结果中\n const result: DeployResult = {\n ...deployResult.data,\n envVarsSet: Object.keys(allEnvVars),\n }\n\n logger.info('Deployment completed', {\n url: result.url,\n deploymentId: result.deploymentId,\n status: result.status,\n })\n\n return ok(result)\n },\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/deploy",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.55",
|
|
5
5
|
"description": "Hai Framework deployment automation module.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"exports": {
|
|
@@ -19,10 +19,13 @@
|
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22.12.0"
|
|
24
|
+
},
|
|
22
25
|
"dependencies": {
|
|
23
26
|
"yaml": "^2.7.0",
|
|
24
27
|
"zod": "^4.4.3",
|
|
25
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
28
|
+
"@h-ai/core": "0.1.0-alpha.55"
|
|
26
29
|
},
|
|
27
30
|
"devDependencies": {
|
|
28
31
|
"@types/node": "^25.9.1",
|
|
@@ -39,6 +42,7 @@
|
|
|
39
42
|
"typecheck": "tsc --noEmit",
|
|
40
43
|
"lint": "eslint .",
|
|
41
44
|
"lint:fix": "eslint . --fix",
|
|
42
|
-
"clean": "rimraf dist .turbo"
|
|
45
|
+
"clean": "rimraf dist .turbo",
|
|
46
|
+
"build:clean": "rimraf dist"
|
|
43
47
|
}
|
|
44
48
|
}
|