@cloudbase/manager-node 5.6.8 → 5.7.0-beta.0

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.
Files changed (62) hide show
  1. package/lib/cloudApp/index.js +12 -3
  2. package/lib/cloudrun/index.js +0 -18
  3. package/lib/deploy/DatabaseDeployer.js +238 -0
  4. package/lib/deploy/DeployOrchestrator.js +564 -0
  5. package/lib/deploy/FunctionDeployer.js +611 -0
  6. package/lib/deploy/GatewayDeployer.js +522 -0
  7. package/lib/deploy/StateStore.js +327 -0
  8. package/lib/deploy/StaticDeployer.js +289 -0
  9. package/lib/deploy/domain.js +39 -0
  10. package/lib/deploy/framework.js +105 -0
  11. package/lib/deploy/function/artifact.js +207 -0
  12. package/lib/deploy/function/builders/cloud.js +454 -0
  13. package/lib/deploy/function/cam-preflight.js +157 -0
  14. package/lib/deploy/function/cloud-build-service.js +170 -0
  15. package/lib/deploy/function/config-guard.js +588 -0
  16. package/lib/deploy/function/docker-preflight.js +87 -0
  17. package/lib/deploy/function/image-preflight.js +164 -0
  18. package/lib/deploy/function/local-builder.js +110 -0
  19. package/lib/deploy/function/planner.js +282 -0
  20. package/lib/deploy/function/preflight.js +264 -0
  21. package/lib/deploy/types.js +99 -0
  22. package/lib/environment.js +11 -0
  23. package/lib/hosting/index.js +4 -1
  24. package/lib/index.js +31 -0
  25. package/lib/projectValidator/index.js +375 -0
  26. package/lib/projectValidator/types.js +2 -0
  27. package/lib/storage/index.js +6 -7
  28. package/lib/utils/index.js +41 -1
  29. package/package.json +2 -1
  30. package/types/cloudApp/index.d.ts +4 -0
  31. package/types/cloudApp/types.d.ts +87 -6
  32. package/types/cloudrun/index.d.ts +1 -7
  33. package/types/cloudrun/type.d.ts +0 -22
  34. package/types/deploy/DatabaseDeployer.d.ts +70 -0
  35. package/types/deploy/DeployOrchestrator.d.ts +150 -0
  36. package/types/deploy/FunctionDeployer.d.ts +158 -0
  37. package/types/deploy/GatewayDeployer.d.ts +175 -0
  38. package/types/deploy/StateStore.d.ts +170 -0
  39. package/types/deploy/StaticDeployer.d.ts +104 -0
  40. package/types/deploy/domain.d.ts +17 -0
  41. package/types/deploy/framework.d.ts +23 -0
  42. package/types/deploy/function/artifact.d.ts +40 -0
  43. package/types/deploy/function/builders/cloud.d.ts +110 -0
  44. package/types/deploy/function/cam-preflight.d.ts +51 -0
  45. package/types/deploy/function/cloud-build-service.d.ts +10 -0
  46. package/types/deploy/function/config-guard.d.ts +41 -0
  47. package/types/deploy/function/docker-preflight.d.ts +17 -0
  48. package/types/deploy/function/image-preflight.d.ts +21 -0
  49. package/types/deploy/function/local-builder.d.ts +26 -0
  50. package/types/deploy/function/planner.d.ts +15 -0
  51. package/types/deploy/function/preflight.d.ts +9 -0
  52. package/types/deploy/types.d.ts +429 -0
  53. package/types/env/type.d.ts +4 -4
  54. package/types/environment.d.ts +7 -0
  55. package/types/function/types.d.ts +15 -0
  56. package/types/hosting/index.d.ts +6 -0
  57. package/types/index.d.ts +18 -0
  58. package/types/interfaces/function.interface.d.ts +1 -1
  59. package/types/projectValidator/index.d.ts +24 -0
  60. package/types/projectValidator/types.d.ts +26 -0
  61. package/types/storage/index.d.ts +6 -0
  62. package/types/utils/index.d.ts +13 -0
@@ -123,10 +123,14 @@ class CloudAppService {
123
123
  * 注意:此方法不依赖应用是否已创建,可在创建应用前调用
124
124
  * 返回的 cosTimestamp 用于 createApp 时传入 staticConfig.cosTimestamp
125
125
  *
126
+ * 内置默认忽略:.git 目录、.DS_Store(含任意层级);node_modules 仅在
127
+ * excludeNodeModules 为 true(默认)时排除——云端构建(需云端 install)场景应传
128
+ * excludeNodeModules: false 允许私有/离线依赖随源码包上传。
129
+ *
126
130
  * @param params 上传参数
127
131
  */
128
132
  async uploadCode(params) {
129
- const { serviceName, localPath, ignore = [], onPhase } = params;
133
+ const { serviceName, localPath, ignore = [], excludeNodeModules = true, onPhase } = params;
130
134
  // 1. 验证本地路径
131
135
  if (!fs_1.default.existsSync(localPath)) {
132
136
  throw new error_1.CloudBaseError(`本地路径不存在: ${localPath}`);
@@ -135,9 +139,14 @@ class CloudAppService {
135
139
  if (!stat.isDirectory()) {
136
140
  throw new error_1.CloudBaseError(`localPath 必须是目录: ${localPath}`);
137
141
  }
138
- // 2. 打包本地文件为 ZIP
142
+ // 2. 打包本地文件为 ZIP(node_modules 按场景决定是否排除)
139
143
  const tmpZipPath = path_1.default.join(os_1.default.tmpdir(), `cloudapp-${Date.now()}-${Math.random().toString(36).slice(2)}.zip`);
140
- const defaultIgnore = ['node_modules/**', '.git/**', '.DS_Store', '**/.DS_Store'];
144
+ const defaultIgnore = [
145
+ ...(excludeNodeModules ? ['node_modules/**'] : []),
146
+ '.git/**',
147
+ '.DS_Store',
148
+ '**/.DS_Store'
149
+ ];
141
150
  const packStart = Date.now();
142
151
  await (0, utils_1.compressToZip)({
143
152
  dirPath: localPath,
@@ -101,21 +101,6 @@ class CloudRunService {
101
101
  const envConfig = this.environment.lazyEnvironmentConfig;
102
102
  return this.tcbrService.request('DescribeServerManageTask', Object.assign({ EnvId: envConfig.EnvId, ServerName: params.serverName, TaskId: (_a = params.taskId) !== null && _a !== void 0 ? _a : 0 }, (params.operatorRemark ? { OperatorRemark: params.operatorRemark } : {})));
103
103
  }
104
- /**
105
- * 查询发布单信息(DescribeReleaseOrder)
106
- * @param {IDescribeReleaseOrderParams} params 查询参数
107
- * @returns {Promise<IDescribeReleaseOrderResponse>} 发布单详情
108
- */
109
- async describeReleaseOrder(params) {
110
- var _a, _b;
111
- const envConfig = this.environment.lazyEnvironmentConfig;
112
- const serverName = (_a = params === null || params === void 0 ? void 0 : params.ServerName) === null || _a === void 0 ? void 0 : _a.trim();
113
- const status = (_b = params === null || params === void 0 ? void 0 : params.Status) === null || _b === void 0 ? void 0 : _b.trim();
114
- if (!serverName) {
115
- throw new Error('Missing required parameters: ServerName');
116
- }
117
- return this.tcbrService.request('DescribeReleaseOrder', Object.assign({ EnvId: envConfig.EnvId, ServerName: serverName }, (status ? { Status: status } : {})));
118
- }
119
104
  /**
120
105
  * 获取云托管服务列表
121
106
  * @param {Object} [params] 查询参数
@@ -536,9 +521,6 @@ __decorate([
536
521
  __decorate([
537
522
  (0, utils_1.preLazy)()
538
523
  ], CloudRunService.prototype, "describeServerManageTask", null);
539
- __decorate([
540
- (0, utils_1.preLazy)()
541
- ], CloudRunService.prototype, "describeReleaseOrder", null);
542
524
  __decorate([
543
525
  (0, utils_1.preLazy)()
544
526
  ], CloudRunService.prototype, "list", null);
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DatabaseDeployer = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const error_1 = require("../error");
10
+ /** migration 文件名正则:14位数字 + 下划线 + 小写字母下划线名称 + .sql */
11
+ const MIGRATION_FILE_PATTERN = /^(\d{14})_([a-z_]+)\.sql$/;
12
+ /** 轮询间隔(毫秒) */
13
+ const POLL_INTERVAL_MS = 2000;
14
+ /** 默认超时(毫秒) */
15
+ const DEFAULT_TIMEOUT_MS = 3000000;
16
+ class DatabaseDeployer {
17
+ constructor(environment) {
18
+ this.environment = environment;
19
+ }
20
+ /**
21
+ * 从本地目录解析 migration 文件列表
22
+ *
23
+ * 文件名格式:{14位时间戳}_{小写下划线名称}.sql
24
+ * 例如:20260526000000_create_users.sql
25
+ *
26
+ * 按文件名升序排列(即按版本号从早到晚)
27
+ */
28
+ parseMigrationFiles(migrationsDir) {
29
+ if (!fs_1.default.existsSync(migrationsDir)) {
30
+ throw new error_1.CloudBaseError(`数据库迁移目录不存在: ${migrationsDir}`);
31
+ }
32
+ const files = fs_1.default.readdirSync(migrationsDir)
33
+ .filter(f => f.endsWith('.sql'))
34
+ .sort();
35
+ const migrations = [];
36
+ for (const file of files) {
37
+ const match = file.match(MIGRATION_FILE_PATTERN);
38
+ if (!match) {
39
+ throw new error_1.CloudBaseError(`migration 文件名格式错误: ${file},应为 {14位时间戳}_{小写下划线名称}.sql`);
40
+ }
41
+ const [, version, name] = match;
42
+ const filePath = path_1.default.join(migrationsDir, file);
43
+ const query = fs_1.default.readFileSync(filePath, 'utf-8');
44
+ if (!query.trim()) {
45
+ throw new error_1.CloudBaseError(`migration 文件内容为空: ${file}`);
46
+ }
47
+ migrations.push({ Version: version, Name: name, Query: query });
48
+ }
49
+ return migrations;
50
+ }
51
+ /**
52
+ * 生成部署计划
53
+ *
54
+ * 调用 previewPGUserMigrations 获取云端对比结果,
55
+ * 返回每条migration 的状态(pending / applied / conflict)
56
+ */
57
+ async plan(config, cwd, envId) {
58
+ this.assertDatabaseType(config);
59
+ const migrationsDir = this.resolveMigrationsDir(cwd, config.migrations);
60
+ const migrations = this.parseMigrationFiles(migrationsDir);
61
+ if (migrations.length === 0) {
62
+ return [];
63
+ }
64
+ const dbService = this.environment.getDatabaseService();
65
+ let preview;
66
+ try {
67
+ preview = await dbService.previewPGUserMigrations({
68
+ EnvId: envId,
69
+ Migrations: migrations
70
+ });
71
+ }
72
+ catch (error) {
73
+ const err = error;
74
+ throw new error_1.CloudBaseError(`数据库迁移预览失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
75
+ requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
76
+ original: err instanceof Error ? err : undefined
77
+ });
78
+ }
79
+ const items = [];
80
+ // pending:将要执行的
81
+ for (const p of preview.Pending || []) {
82
+ items.push({ version: p.Version, name: p.Name, status: 'pending' });
83
+ }
84
+ // applied:已经执行过的
85
+ for (const a of preview.Applied || []) {
86
+ items.push({ version: a.Version, name: a.Name, status: 'applied' });
87
+ }
88
+ // conflict:有冲突的
89
+ for (const c of preview.Conflicts || []) {
90
+ items.push({
91
+ version: c.Version,
92
+ name: c.Name || '',
93
+ status: 'conflict',
94
+ reason: c.Reason || c.Message || 'checksum mismatch'
95
+ });
96
+ }
97
+ return items;
98
+ }
99
+ /**
100
+ * 执行数据库迁移
101
+ *
102
+ * 流程:
103
+ * 1. 解析本地 migration 文件
104
+ * 2. 预览确认无冲突(有冲突直接 throw,中断整个部署)
105
+ * 3. 无 pending 则跳过
106
+ * 4. 提交 pushPGUserMigrations
107
+ * 5. 轮询describeTaskResult 等待完成
108
+ */
109
+ async deploy(config, cwd, envId) {
110
+ this.assertDatabaseType(config);
111
+ const migrationsDir = this.resolveMigrationsDir(cwd, config.migrations);
112
+ const migrations = this.parseMigrationFiles(migrationsDir);
113
+ if (migrations.length === 0) {
114
+ return { taskId: '' };
115
+ }
116
+ const dbService = this.environment.getDatabaseService();
117
+ // 1. 预览:确认无冲突
118
+ let preview;
119
+ try {
120
+ preview = await dbService.previewPGUserMigrations({
121
+ EnvId: envId,
122
+ Migrations: migrations
123
+ });
124
+ }
125
+ catch (error) {
126
+ const err = error;
127
+ throw new error_1.CloudBaseError(`数据库迁移预览失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
128
+ requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
129
+ original: err instanceof Error ? err : undefined
130
+ });
131
+ }
132
+ if (!preview.Executable) {
133
+ const conflictDetails = (preview.Conflicts || [])
134
+ .map((c) => ` - ${c.Version}_${c.Name || '?'}: ${c.Reason || c.Message || 'unknown'}`)
135
+ .join('\n');
136
+ throw new error_1.CloudBaseError(`数据库迁移存在冲突,中断部署。请先解决以下冲突:\n${conflictDetails}`, {
137
+ requestId: preview.RequestId
138
+ });
139
+ }
140
+ // 2. 无 pending → 全部已applied,跳过
141
+ if (!preview.Pending || preview.Pending.length === 0) {
142
+ return { taskId: '' };
143
+ }
144
+ // 3. 提交执行
145
+ let result;
146
+ try {
147
+ result = await dbService.pushPGUserMigrations({
148
+ EnvId: envId,
149
+ Migrations: migrations
150
+ });
151
+ }
152
+ catch (error) {
153
+ const err = error;
154
+ throw new error_1.CloudBaseError(`数据库迁移提交失败 [EnvId=${envId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
155
+ requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
156
+ original: err instanceof Error ? err : undefined
157
+ });
158
+ }
159
+ // 4. 轮询等待完成
160
+ try {
161
+ await this.waitForTask(envId, result.TaskId, DEFAULT_TIMEOUT_MS);
162
+ }
163
+ catch (error) {
164
+ if (error instanceof error_1.CloudBaseError) {
165
+ throw error;
166
+ }
167
+ const err = error;
168
+ throw new error_1.CloudBaseError(`数据库迁移任务等待失败 [TaskId=${result.TaskId}]:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
169
+ requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
170
+ original: err instanceof Error ? err : undefined
171
+ });
172
+ }
173
+ return { taskId: result.TaskId };
174
+ }
175
+ /**
176
+ * 解析 migrations 目录路径
177
+ * - 未配置:默认 ./cloudbase/migrations
178
+ * - 仅允许相对路径(禁止 / 开头)
179
+ */
180
+ resolveMigrationsDir(cwd, migrations) {
181
+ const raw = migrations || './cloudbase/migrations';
182
+ if (path_1.default.isAbsolute(raw) || raw.startsWith('/')) {
183
+ throw new error_1.CloudBaseError('database.migrations 仅支持相对路径(例如 ./cloudbase/migrations)');
184
+ }
185
+ return path_1.default.resolve(cwd, raw);
186
+ }
187
+ /**
188
+ * 校验 database.type(当前仅支持 postgresql)
189
+ */
190
+ assertDatabaseType(config) {
191
+ if (config.type !== 'postgresql') {
192
+ throw new error_1.CloudBaseError(`database.type 仅支持 postgresql,当前为: ${String(config.type)}`);
193
+ }
194
+ }
195
+ /**
196
+ * 轮询等待异步任务完成
197
+ */
198
+ async waitForTask(envId, taskId, timeoutMs) {
199
+ const dbService = this.environment.getDatabaseService();
200
+ const startTime = Date.now();
201
+ while (true) {
202
+ let task;
203
+ try {
204
+ task = await dbService.describeTaskResult({ EnvId: envId, TaskId: taskId });
205
+ }
206
+ catch (error) {
207
+ if (Date.now() - startTime > timeoutMs) {
208
+ const err = error;
209
+ throw new error_1.CloudBaseError(`数据库迁移任务状态查询超时(${timeoutMs / 1000}s),TaskId: ${taskId},最后错误:${(err === null || err === void 0 ? void 0 : err.message) || String(error)}`, {
210
+ requestId: (err === null || err === void 0 ? void 0 : err.RequestId) || (err === null || err === void 0 ? void 0 : err.requestId),
211
+ original: err instanceof Error ? err : undefined
212
+ });
213
+ }
214
+ await new Promise(resolve => {
215
+ setTimeout(resolve, POLL_INTERVAL_MS);
216
+ });
217
+ continue;
218
+ }
219
+ if (task.Status === 'Succeed') {
220
+ return;
221
+ }
222
+ if (task.Status === 'Failed') {
223
+ throw new error_1.CloudBaseError(`数据库迁移任务失败 [TaskId=${taskId}]: ${task.Reason || '未知原因'}`, {
224
+ requestId: task.RequestId
225
+ });
226
+ }
227
+ if (Date.now() - startTime > timeoutMs) {
228
+ throw new error_1.CloudBaseError(`数据库迁移任务超时(${timeoutMs / 1000}s),TaskId: ${taskId},当前状态: ${task.Status}/${task.Phase}`, {
229
+ requestId: task.RequestId
230
+ });
231
+ }
232
+ await new Promise(resolve => {
233
+ setTimeout(resolve, POLL_INTERVAL_MS);
234
+ });
235
+ }
236
+ }
237
+ }
238
+ exports.DatabaseDeployer = DatabaseDeployer;