@cloudbase/manager-node 5.6.7 → 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 (60) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/lib/cloudApp/index.js +12 -3
  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/deploy/DatabaseDeployer.d.ts +70 -0
  33. package/types/deploy/DeployOrchestrator.d.ts +150 -0
  34. package/types/deploy/FunctionDeployer.d.ts +158 -0
  35. package/types/deploy/GatewayDeployer.d.ts +175 -0
  36. package/types/deploy/StateStore.d.ts +170 -0
  37. package/types/deploy/StaticDeployer.d.ts +104 -0
  38. package/types/deploy/domain.d.ts +17 -0
  39. package/types/deploy/framework.d.ts +23 -0
  40. package/types/deploy/function/artifact.d.ts +40 -0
  41. package/types/deploy/function/builders/cloud.d.ts +110 -0
  42. package/types/deploy/function/cam-preflight.d.ts +51 -0
  43. package/types/deploy/function/cloud-build-service.d.ts +10 -0
  44. package/types/deploy/function/config-guard.d.ts +41 -0
  45. package/types/deploy/function/docker-preflight.d.ts +17 -0
  46. package/types/deploy/function/image-preflight.d.ts +21 -0
  47. package/types/deploy/function/local-builder.d.ts +26 -0
  48. package/types/deploy/function/planner.d.ts +15 -0
  49. package/types/deploy/function/preflight.d.ts +9 -0
  50. package/types/deploy/types.d.ts +429 -0
  51. package/types/env/type.d.ts +4 -4
  52. package/types/environment.d.ts +7 -0
  53. package/types/function/types.d.ts +15 -0
  54. package/types/hosting/index.d.ts +6 -0
  55. package/types/index.d.ts +18 -0
  56. package/types/interfaces/function.interface.d.ts +1 -1
  57. package/types/projectValidator/index.d.ts +24 -0
  58. package/types/projectValidator/types.d.ts +26 -0
  59. package/types/storage/index.d.ts +6 -0
  60. package/types/utils/index.d.ts +13 -0
@@ -0,0 +1,264 @@
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.runLocalPreflight = runLocalPreflight;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const packer_1 = require("../../function/packer");
10
+ const types_1 = require("../types");
11
+ /**
12
+ * 部署前环境检查(Preflight)
13
+ *
14
+ * 与 config-guard 的区别:config-guard 是纯函数、无 IO 的配置契约校验;
15
+ * 本文件执行有 IO 的本地检查,目前覆盖 HTTP 代码包部署所需的文件系统条件。
16
+ *
17
+ * 本阶段只读文件系统,不执行命令、不访问网络、不涉及 Docker 与 TCR。
18
+ * Docker、TCR、CAM、网络等检查属于后续 local/cloud Preflight,不在此处。
19
+ */
20
+ /** HTTP 代码包函数要求的启动文件 */
21
+ const SCF_BOOTSTRAP = 'scf_bootstrap';
22
+ /** 可执行位掩码(owner/group/other 任一可执行即可) */
23
+ const EXECUTABLE_MASK = 0o111;
24
+ /** 解压前代码包大小阈值,复用底层上传阈值,超过给出告警 */
25
+ const PACKAGE_SIZE_WARN_THRESHOLD = packer_1.BIG_FILE_SIZE;
26
+ /** 遍历目录项数量上限,超过则停止统计,避免超大目录阻塞检查 */
27
+ const MAX_SCAN_ENTRIES = 20000;
28
+ /** 遍历目录深度上限,避免异常深层结构阻塞检查 */
29
+ const MAX_SCAN_DEPTH = 64;
30
+ function fail(id, summary, options = {}) {
31
+ return { id, status: 'fail', summary, remediation: options.remediation, detail: options.detail };
32
+ }
33
+ function warn(id, summary, remediation) {
34
+ return { id, status: 'warn', summary, remediation };
35
+ }
36
+ /** 构造本地 Preflight 报告 */
37
+ function buildReport(strategy, checks) {
38
+ return {
39
+ scope: 'local',
40
+ strategy,
41
+ ready: !checks.some(item => item.status === 'fail'),
42
+ checks
43
+ };
44
+ }
45
+ /**
46
+ * 解析 HTTP zip 部署的函数目录
47
+ *
48
+ * functionPath 直接指向函数目录;functionRootPath 是父目录,需拼接函数名;
49
+ * base64Code 已是内存中的 ZIP,无本地目录可检查
50
+ * @returns 函数目录绝对路径;base64Code 或无法定位时返回 null
51
+ */
52
+ function resolveFunctionDir(config) {
53
+ if (typeof config.functionPath === 'string' && config.functionPath.trim()) {
54
+ return path_1.default.resolve(config.functionPath);
55
+ }
56
+ if (typeof config.functionRootPath === 'string' && config.functionRootPath.trim()) {
57
+ return path_1.default.resolve(config.functionRootPath, config.name);
58
+ }
59
+ return null;
60
+ }
61
+ /** 安全获取文件状态,不存在返回 null,其它 IO 错误抛出 */
62
+ function safeStat(target) {
63
+ try {
64
+ return fs_1.default.statSync(target);
65
+ }
66
+ catch (error) {
67
+ if (error && error.code === 'ENOENT') {
68
+ return null;
69
+ }
70
+ throw error;
71
+ }
72
+ }
73
+ /** 检查函数目录下的 scf_bootstrap 启动文件 */
74
+ function checkBootstrap(functionDir, checks) {
75
+ const bootstrapPath = path_1.default.join(functionDir, SCF_BOOTSTRAP);
76
+ const stat = safeStat(bootstrapPath);
77
+ if (stat === null) {
78
+ checks.push(fail(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_BOOTSTRAP_MISSING, `HTTP 代码包缺少启动文件 ${SCF_BOOTSTRAP}`, {
79
+ remediation: `请在函数目录下提供可执行的 ${SCF_BOOTSTRAP},用于启动监听端口的 HTTP 服务`,
80
+ detail: `期望路径:${bootstrapPath}`
81
+ }));
82
+ return;
83
+ }
84
+ if (!stat.isFile()) {
85
+ checks.push(fail(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_BOOTSTRAP_NOT_FILE, `${SCF_BOOTSTRAP} 不是普通文件`, {
86
+ remediation: `请确保 ${SCF_BOOTSTRAP} 是一个文件而非目录或链接`,
87
+ detail: `路径:${bootstrapPath}`
88
+ }));
89
+ return;
90
+ }
91
+ // 仅 POSIX 有可执行位,Windows 无该概念,跳过可执行位判断
92
+ if (process.platform !== 'win32' && (stat.mode & EXECUTABLE_MASK) === 0) {
93
+ checks.push(warn(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_BOOTSTRAP_NOT_EXECUTABLE, `${SCF_BOOTSTRAP} 缺少可执行权限`, `建议执行 chmod +x ${SCF_BOOTSTRAP},否则运行环境可能无法启动服务`));
94
+ }
95
+ }
96
+ /** 判断 target 解析后是否逃逸出根目录 */
97
+ function isPathEscaped(root, target) {
98
+ const relative = path_1.default.relative(root, target);
99
+ // 空串表示与根相同;以 .. 开头或为绝对路径表示逃逸
100
+ return relative === '..' || relative.startsWith(`..${path_1.default.sep}`) || path_1.default.isAbsolute(relative);
101
+ }
102
+ /**
103
+ * 遍历函数目录,统计总大小并检测逃逸软链接
104
+ *
105
+ * 使用 lstat 不跟随链接;对软链接单独解析目标,判断是否指向根目录之外。
106
+ * 设深度与数量上限,避免异常目录结构阻塞检查。
107
+ */
108
+ function scanPackageContents(functionDir) {
109
+ const result = { totalSize: 0, escapedLinks: [], truncated: false };
110
+ let visited = 0;
111
+ // 根目录也解析为真实路径,避免 /var→/private/var 这类平台软链接导致内部链接被误判逃逸
112
+ let realRoot;
113
+ try {
114
+ realRoot = fs_1.default.realpathSync(functionDir);
115
+ }
116
+ catch (_a) {
117
+ realRoot = functionDir;
118
+ }
119
+ const walk = (dir, depth) => {
120
+ if (result.truncated || depth > MAX_SCAN_DEPTH) {
121
+ return;
122
+ }
123
+ const entries = fs_1.default.readdirSync(dir);
124
+ for (const entry of entries) {
125
+ if (visited >= MAX_SCAN_ENTRIES) {
126
+ result.truncated = true;
127
+ return;
128
+ }
129
+ visited += 1;
130
+ const fullPath = path_1.default.join(dir, entry);
131
+ const stat = fs_1.default.lstatSync(fullPath);
132
+ if (stat.isSymbolicLink()) {
133
+ // 解析链接目标,判断是否逃逸出函数目录
134
+ let realTarget;
135
+ try {
136
+ realTarget = fs_1.default.realpathSync(fullPath);
137
+ }
138
+ catch (_a) {
139
+ // 断链(指向不存在的目标)视为逃逸风险,记录相对路径
140
+ result.escapedLinks.push(path_1.default.relative(functionDir, fullPath));
141
+ continue;
142
+ }
143
+ if (isPathEscaped(realRoot, realTarget)) {
144
+ result.escapedLinks.push(path_1.default.relative(functionDir, fullPath));
145
+ }
146
+ continue;
147
+ }
148
+ if (stat.isDirectory()) {
149
+ walk(fullPath, depth + 1);
150
+ if (result.truncated) {
151
+ return;
152
+ }
153
+ continue;
154
+ }
155
+ if (stat.isFile()) {
156
+ result.totalSize += stat.size;
157
+ }
158
+ }
159
+ };
160
+ walk(functionDir, 0);
161
+ return result;
162
+ }
163
+ /**
164
+ * 检查依赖是否随包携带
165
+ *
166
+ * 非 Node.js HTTP 代码包部署会关闭云端安装依赖;若项目声明了 dependencies 却没有
167
+ * node_modules,运行时可能因缺少依赖而失败。此处为 warn,因为也可能使用打包产物,
168
+ * 或依赖并非 Node.js 模块。
169
+ */
170
+ function checkDependencyBundled(functionDir, checks) {
171
+ const pkgPath = path_1.default.join(functionDir, 'package.json');
172
+ const pkgStat = safeStat(pkgPath);
173
+ if (pkgStat === null || !pkgStat.isFile()) {
174
+ return;
175
+ }
176
+ let hasDependencies = false;
177
+ try {
178
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
179
+ const deps = pkg && typeof pkg === 'object' ? pkg.dependencies : undefined;
180
+ hasDependencies = !!deps && typeof deps === 'object' && Object.keys(deps).length > 0;
181
+ }
182
+ catch (_a) {
183
+ // package.json 无法解析属于用户代码问题,不在本检查职责内
184
+ return;
185
+ }
186
+ if (!hasDependencies) {
187
+ return;
188
+ }
189
+ const nodeModulesStat = safeStat(path_1.default.join(functionDir, 'node_modules'));
190
+ if (nodeModulesStat === null || !nodeModulesStat.isDirectory()) {
191
+ checks.push(warn(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_DEPENDENCY_NOT_BUNDLED, 'package.json 声明了依赖但未发现 node_modules', 'HTTP 代码包部署不会在云端安装依赖,请先在本地安装依赖并随包上传'));
192
+ }
193
+ }
194
+ /** 检查包大小与软链接逃逸 */
195
+ function checkPackageContents(functionDir, checks) {
196
+ const scan = scanPackageContents(functionDir);
197
+ for (const link of scan.escapedLinks) {
198
+ checks.push(fail(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_SYMLINK_ESCAPE, '代码目录包含逃逸到目录之外的软链接', {
199
+ remediation: '请移除指向函数目录之外的符号链接,避免打包引入非预期或敏感文件',
200
+ detail: `软链接:${link}`
201
+ }));
202
+ }
203
+ if (!scan.truncated && scan.totalSize > PACKAGE_SIZE_WARN_THRESHOLD) {
204
+ const sizeMb = (scan.totalSize / 1024 / 1024).toFixed(2);
205
+ const limitMb = (PACKAGE_SIZE_WARN_THRESHOLD / 1024 / 1024).toFixed(0);
206
+ checks.push(warn(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_PACKAGE_TOO_LARGE, `代码包体积约 ${sizeMb} MB,超过 ${limitMb} MB`, '较大的代码包会拖慢上传与冷启动,建议清理无关文件或依赖'));
207
+ }
208
+ }
209
+ /**
210
+ * 执行部署前本地检查
211
+ *
212
+ * 目前仅 HTTP 代码包部署有文件系统前置条件;其它策略返回空报告,表示本阶段无需检查。
213
+ * base64Code 来源无本地目录,跳过文件检查。
214
+ * @returns 本地检查报告,聚合全部问题
215
+ */
216
+ function runLocalPreflight(config) {
217
+ const strategy = config.buildStrategy;
218
+ // 仅 HTTP 代码包部署需要文件系统前置检查
219
+ if (config.type !== 'HTTP' || strategy !== 'zip') {
220
+ return buildReport(strategy, []);
221
+ }
222
+ // 收窄到 zip 子类型后可直接访问代码来源字段(base64Code/functionPath/functionRootPath)
223
+ const source = config;
224
+ // base64Code 已是内存 ZIP,无本地目录可查
225
+ if (typeof source.base64Code === 'string' && source.base64Code.trim()) {
226
+ return buildReport(strategy, []);
227
+ }
228
+ const checks = [];
229
+ try {
230
+ const functionDir = resolveFunctionDir(source);
231
+ if (functionDir === null) {
232
+ // 代码来源缺失属于配置契约问题,已由 config-guard 覆盖,此处不重复报错
233
+ return buildReport(strategy, checks);
234
+ }
235
+ const dirStat = safeStat(functionDir);
236
+ if (dirStat === null) {
237
+ checks.push(fail(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_CODE_PATH_MISSING, '代码目录不存在', {
238
+ remediation: '请确认 functionPath 或 functionRootPath 指向真实存在的目录',
239
+ detail: `期望路径:${functionDir}`
240
+ }));
241
+ return buildReport(strategy, checks);
242
+ }
243
+ if (!dirStat.isDirectory()) {
244
+ checks.push(fail(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_CODE_PATH_NOT_DIRECTORY, '代码路径不是目录', {
245
+ remediation: '代码来源需指向目录,而非文件',
246
+ detail: `路径:${functionDir}`
247
+ }));
248
+ return buildReport(strategy, checks);
249
+ }
250
+ checkBootstrap(functionDir, checks);
251
+ checkPackageContents(functionDir, checks);
252
+ const isNodejsRuntime = source.runtime === undefined || String(source.runtime).startsWith('Nodejs');
253
+ if (!isNodejsRuntime) {
254
+ checkDependencyBundled(functionDir, checks);
255
+ }
256
+ }
257
+ catch (error) {
258
+ checks.push(fail(types_1.FUNCTION_DEPLOY_ERROR.PREFLIGHT_IO_ERROR, '读取代码目录时发生 IO 错误', {
259
+ remediation: '请检查目录权限与磁盘状态后重试',
260
+ detail: error instanceof Error ? error.message : String(error)
261
+ }));
262
+ }
263
+ return buildReport(strategy, checks);
264
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FUNCTION_DEPLOY_ERROR = exports.CUSTOM_IMAGE_RUNTIME = exports.DEFAULT_DOCKERFILE = exports.DEFAULT_IMAGE_PLATFORM = exports.IMAGE_FUNCTION_PORT = void 0;
4
+ /**
5
+ * 镜像 HTTP 函数固定监听端口
6
+ * SCF HTTP 自定义镜像函数要求容器监听 9000
7
+ */
8
+ exports.IMAGE_FUNCTION_PORT = 9000;
9
+ /**
10
+ * 镜像构建默认目标平台
11
+ * SCF 运行环境为 linux/amd64,Apple Silicon 也必须显式构建该平台
12
+ */
13
+ exports.DEFAULT_IMAGE_PLATFORM = 'linux/amd64';
14
+ /** 默认 Dockerfile 名称,相对于构建上下文 */
15
+ exports.DEFAULT_DOCKERFILE = 'Dockerfile';
16
+ /** 自定义镜像运行时标识 */
17
+ exports.CUSTOM_IMAGE_RUNTIME = 'CustomImage';
18
+ /** 函数部署错误码 */
19
+ exports.FUNCTION_DEPLOY_ERROR = {
20
+ CONFIG_INVALID: 'CONFIG_INVALID',
21
+ CONFIG_NAME_INVALID: 'CONFIG_NAME_INVALID',
22
+ CONFIG_TYPE_INVALID: 'CONFIG_TYPE_INVALID',
23
+ CONFIG_STRATEGY_INVALID: 'CONFIG_STRATEGY_INVALID',
24
+ CONFIG_TIMEOUT_INVALID: 'CONFIG_TIMEOUT_INVALID',
25
+ CONFIG_MEMORY_SIZE_INVALID: 'CONFIG_MEMORY_SIZE_INVALID',
26
+ CONFIG_ENV_VARIABLE_INVALID: 'CONFIG_ENV_VARIABLE_INVALID',
27
+ EVENT_IMAGE_NOT_SUPPORTED: 'EVENT_IMAGE_NOT_SUPPORTED',
28
+ EVENT_GATEWAY_NOT_SUPPORTED: 'EVENT_GATEWAY_NOT_SUPPORTED',
29
+ EVENT_HTTP_FIELD_NOT_SUPPORTED: 'EVENT_HTTP_FIELD_NOT_SUPPORTED',
30
+ HTTP_ZIP_RUNTIME_INVALID: 'HTTP_ZIP_RUNTIME_INVALID',
31
+ HTTP_ZIP_IMAGE_CONFIG_CONFLICT: 'HTTP_ZIP_IMAGE_CONFIG_CONFLICT',
32
+ HTTP_ZIP_INSTALL_DEPENDENCY_OVERRIDDEN: 'HTTP_ZIP_INSTALL_DEPENDENCY_OVERRIDDEN',
33
+ HTTP_TRIGGER_NOT_SUPPORTED: 'HTTP_TRIGGER_NOT_SUPPORTED',
34
+ HTTP_CONCURRENCY_INVALID: 'HTTP_CONCURRENCY_INVALID',
35
+ HTTP_PROTOCOL_PARAMS_INVALID: 'HTTP_PROTOCOL_PARAMS_INVALID',
36
+ CODE_SOURCE_MISSING: 'CODE_SOURCE_MISSING',
37
+ CODE_SOURCE_CONFLICT: 'CODE_SOURCE_CONFLICT',
38
+ IMAGE_CONFIG_MISSING: 'IMAGE_CONFIG_MISSING',
39
+ IMAGE_CONFIG_NOT_ALLOWED: 'IMAGE_CONFIG_NOT_ALLOWED',
40
+ IMAGE_URI_INVALID: 'IMAGE_URI_INVALID',
41
+ IMAGE_TAG_MISSING: 'IMAGE_TAG_MISSING',
42
+ IMAGE_TAG_LATEST_FORBIDDEN: 'IMAGE_TAG_LATEST_FORBIDDEN',
43
+ IMAGE_TYPE_INVALID: 'IMAGE_TYPE_INVALID',
44
+ IMAGE_REGISTRY_ID_MISSING: 'IMAGE_REGISTRY_ID_MISSING',
45
+ IMAGE_PORT_INVALID: 'IMAGE_PORT_INVALID',
46
+ IMAGE_RUNTIME_INVALID: 'IMAGE_RUNTIME_INVALID',
47
+ IMAGE_HANDLER_NOT_ALLOWED: 'IMAGE_HANDLER_NOT_ALLOWED',
48
+ BUILD_CONFIG_MISSING: 'BUILD_CONFIG_MISSING',
49
+ BUILD_DOCKERFILE_INVALID: 'BUILD_DOCKERFILE_INVALID',
50
+ BUILD_CONTEXT_INVALID: 'BUILD_CONTEXT_INVALID',
51
+ BUILD_PLATFORM_INVALID: 'BUILD_PLATFORM_INVALID',
52
+ BUILD_TAG_INVALID: 'BUILD_TAG_INVALID',
53
+ BUILD_REPOSITORY_INVALID: 'BUILD_REPOSITORY_INVALID',
54
+ BUILD_ARG_INVALID: 'BUILD_ARG_INVALID',
55
+ CLOUD_REGISTRY_CREDENTIAL_MISSING: 'CLOUD_REGISTRY_CREDENTIAL_MISSING',
56
+ CLOUD_REGISTRY_CREDENTIAL_INVALID: 'CLOUD_REGISTRY_CREDENTIAL_INVALID',
57
+ GATEWAY_PATH_INVALID: 'GATEWAY_PATH_INVALID',
58
+ LOCAL_FALLBACK_INVALID: 'LOCAL_FALLBACK_INVALID',
59
+ // Preflight(有 IO 的本地检查)
60
+ PREFLIGHT_CODE_PATH_MISSING: 'PREFLIGHT_CODE_PATH_MISSING',
61
+ PREFLIGHT_CODE_PATH_NOT_DIRECTORY: 'PREFLIGHT_CODE_PATH_NOT_DIRECTORY',
62
+ PREFLIGHT_BOOTSTRAP_MISSING: 'PREFLIGHT_BOOTSTRAP_MISSING',
63
+ PREFLIGHT_BOOTSTRAP_NOT_FILE: 'PREFLIGHT_BOOTSTRAP_NOT_FILE',
64
+ PREFLIGHT_BOOTSTRAP_NOT_EXECUTABLE: 'PREFLIGHT_BOOTSTRAP_NOT_EXECUTABLE',
65
+ PREFLIGHT_PACKAGE_TOO_LARGE: 'PREFLIGHT_PACKAGE_TOO_LARGE',
66
+ PREFLIGHT_SYMLINK_ESCAPE: 'PREFLIGHT_SYMLINK_ESCAPE',
67
+ PREFLIGHT_DEPENDENCY_NOT_BUNDLED: 'PREFLIGHT_DEPENDENCY_NOT_BUNDLED',
68
+ PREFLIGHT_IO_ERROR: 'PREFLIGHT_IO_ERROR',
69
+ // Docker 本地能力 Preflight(local 策略,scope: local)
70
+ PREFLIGHT_DOCKER_CLI_MISSING: 'PREFLIGHT_DOCKER_CLI_MISSING',
71
+ PREFLIGHT_DOCKER_DAEMON_UNAVAILABLE: 'PREFLIGHT_DOCKER_DAEMON_UNAVAILABLE',
72
+ PREFLIGHT_DOCKER_BUILDX_MISSING: 'PREFLIGHT_DOCKER_BUILDX_MISSING',
73
+ // 本地构建与推送(local 策略)
74
+ LOCAL_BUILD_CONTEXT_MISSING: 'LOCAL_BUILD_CONTEXT_MISSING',
75
+ LOCAL_BUILD_DOCKERFILE_MISSING: 'LOCAL_BUILD_DOCKERFILE_MISSING',
76
+ LOCAL_BUILD_REPOSITORY_MISSING: 'LOCAL_BUILD_REPOSITORY_MISSING',
77
+ LOCAL_BUILD_FAILED: 'LOCAL_BUILD_FAILED',
78
+ LOCAL_PUSH_FAILED: 'LOCAL_PUSH_FAILED',
79
+ LOCAL_DIGEST_QUERY_FAILED: 'LOCAL_DIGEST_QUERY_FAILED',
80
+ // 云端构建(cloud 策略,CloudApp custom)
81
+ CLOUD_UPLOAD_FAILED: 'CLOUD_UPLOAD_FAILED',
82
+ CLOUD_BUILD_TRIGGER_FAILED: 'CLOUD_BUILD_TRIGGER_FAILED',
83
+ CLOUD_BUILD_FAILED: 'CLOUD_BUILD_FAILED',
84
+ CLOUD_BUILD_CANCELED: 'CLOUD_BUILD_CANCELED',
85
+ CLOUD_BUILD_TIMEOUT: 'CLOUD_BUILD_TIMEOUT',
86
+ // 镜像远端校验 Preflight(有 IO,scope: cloud)
87
+ PREFLIGHT_IMAGE_REMOTE_NOT_FOUND: 'PREFLIGHT_IMAGE_REMOTE_NOT_FOUND',
88
+ PREFLIGHT_IMAGE_REMOTE_UNVERIFIABLE: 'PREFLIGHT_IMAGE_REMOTE_UNVERIFIABLE',
89
+ PREFLIGHT_IMAGE_DIGEST_UNRESOLVED: 'PREFLIGHT_IMAGE_DIGEST_UNRESOLVED',
90
+ PREFLIGHT_IMAGE_REGION_MISMATCH: 'PREFLIGHT_IMAGE_REGION_MISMATCH',
91
+ // 镜像拉取授权 Preflight(涉及 CAM,scope: cloud)
92
+ PREFLIGHT_IMAGE_PULL_ROLE_MISSING: 'PREFLIGHT_IMAGE_PULL_ROLE_MISSING',
93
+ PREFLIGHT_IMAGE_PULL_POLICY_MISSING: 'PREFLIGHT_IMAGE_PULL_POLICY_MISSING',
94
+ PREFLIGHT_IMAGE_PULL_AUTH_GRANTED: 'PREFLIGHT_IMAGE_PULL_AUTH_GRANTED',
95
+ PREFLIGHT_IMAGE_PULL_AUTH_UNVERIFIABLE: 'PREFLIGHT_IMAGE_PULL_AUTH_UNVERIFIABLE',
96
+ PREFLIGHT_CAM_PERMISSION_DENIED: 'PREFLIGHT_CAM_PERMISSION_DENIED',
97
+ REPLACE_NOT_APPROVED: 'REPLACE_NOT_APPROVED',
98
+ NOT_IMPLEMENTED: 'NOT_IMPLEMENTED'
99
+ };
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Environment = void 0;
4
4
  const database_1 = require("./database");
5
5
  const function_1 = require("./function");
6
+ const FunctionDeployer_1 = require("./deploy/FunctionDeployer");
6
7
  const cloudrun_1 = require("./cloudrun");
7
8
  const agent_1 = require("./agent");
8
9
  const storage_1 = require("./storage");
@@ -83,6 +84,16 @@ class Environment {
83
84
  getFunctionService() {
84
85
  return this.functionService;
85
86
  }
87
+ /**
88
+ * 获取函数部署编排器
89
+ * 采用懒初始化,避免模块循环引用导致的初始化顺序问题
90
+ */
91
+ getFunctionDeployer() {
92
+ if (!this.functionDeployer) {
93
+ this.functionDeployer = new FunctionDeployer_1.FunctionDeployer(this);
94
+ }
95
+ return this.functionDeployer;
96
+ }
86
97
  getCloudRunService() {
87
98
  return this.cloudRunService;
88
99
  }
@@ -364,7 +364,7 @@ class HostingService {
364
364
  * @param options
365
365
  */
366
366
  async setWebsiteDocument(options) {
367
- const { indexDocument, errorDocument, routingRules } = options;
367
+ const { indexDocument, errorDocument, originalHttpStatus, charity404, autoAddressing, routingRules } = options;
368
368
  const hosting = await this.checkStatus();
369
369
  const { Bucket, Regoin } = hosting;
370
370
  const storageService = await this.environment.getStorageService();
@@ -373,6 +373,9 @@ class HostingService {
373
373
  region: Regoin,
374
374
  indexDocument,
375
375
  errorDocument,
376
+ originalHttpStatus,
377
+ charity404,
378
+ autoAddressing,
376
379
  routingRules
377
380
  });
378
381
  return res;
package/lib/index.js CHANGED
@@ -2,6 +2,8 @@
2
2
  const context_1 = require("./context");
3
3
  const environmentManager_1 = require("./environmentManager");
4
4
  const docs_1 = require("./docs");
5
+ const projectValidator_1 = require("./projectValidator");
6
+ const DeployOrchestrator_1 = require("./deploy/DeployOrchestrator");
5
7
  class CloudBase {
6
8
  /**
7
9
  * init 初始化 为单例
@@ -49,6 +51,13 @@ class CloudBase {
49
51
  get functions() {
50
52
  return this.currentEnvironment().getFunctionService();
51
53
  }
54
+ /**
55
+ * 函数部署编排器(FunctionDeployer)
56
+ * 在现有 FunctionService 之上,按 buildStrategy 编排 Event/HTTP 函数的创建、更新与访问收敛
57
+ */
58
+ get functionDeployer() {
59
+ return this.currentEnvironment().getFunctionDeployer();
60
+ }
52
61
  get cloudrun() {
53
62
  return this.currentEnvironment().getCloudRunService();
54
63
  }
@@ -146,6 +155,28 @@ class CloudBase {
146
155
  }
147
156
  return this.docsService;
148
157
  }
158
+ get projectValidator() {
159
+ if (!this.projectValidatorService) {
160
+ this.projectValidatorService = new projectValidator_1.ProjectValidator();
161
+ }
162
+ return this.projectValidatorService;
163
+ }
164
+ getProjectValidator() {
165
+ return this.projectValidator;
166
+ }
167
+ /**
168
+ * 声明式部署编排器
169
+ * 顺序:database → functions → app → hosting → gateway;支持 dry-run / only / skip / 幂等重试
170
+ */
171
+ get deployOrchestrator() {
172
+ if (!this.deployOrchestratorService) {
173
+ this.deployOrchestratorService = new DeployOrchestrator_1.DeployOrchestrator(this.currentEnvironment());
174
+ }
175
+ return this.deployOrchestratorService;
176
+ }
177
+ getDeployOrchestrator() {
178
+ return this.deployOrchestrator;
179
+ }
149
180
  getEnvironmentManager() {
150
181
  return this.environmentManager;
151
182
  }