@cloudbase/manager-node 5.8.2 → 5.8.4

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 (36) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/lib/database/index.js +11 -6
  3. package/lib/deploy/DeployOrchestrator.js +170 -278
  4. package/lib/deploy/FunctionDeployer.js +310 -52
  5. package/lib/deploy/StaticDeployer.js +7 -1
  6. package/lib/deploy/function/artifact.js +55 -41
  7. package/lib/deploy/function/builders/cloud.js +58 -359
  8. package/lib/deploy/function/cam-preflight.js +2 -1
  9. package/lib/deploy/function/cloud-build-service.js +2 -16
  10. package/lib/deploy/function/config-guard.js +210 -55
  11. package/lib/deploy/function/enterprise-tcr.js +195 -0
  12. package/lib/deploy/function/image-tag.js +31 -0
  13. package/lib/deploy/function/local-builder.js +178 -32
  14. package/lib/deploy/function/personal-tcr.js +153 -0
  15. package/lib/deploy/function/preflight.js +3 -2
  16. package/lib/deploy/types.js +11 -0
  17. package/lib/hosting/index.js +27 -0
  18. package/lib/projectValidator/index.js +22 -23
  19. package/package.json +2 -2
  20. package/types/database/index.d.ts +1 -0
  21. package/types/deploy/DeployOrchestrator.d.ts +19 -25
  22. package/types/deploy/FunctionDeployer.d.ts +35 -3
  23. package/types/deploy/StaticDeployer.d.ts +11 -0
  24. package/types/deploy/function/artifact.d.ts +0 -5
  25. package/types/deploy/function/builders/cloud.d.ts +6 -39
  26. package/types/deploy/function/config-guard.d.ts +18 -0
  27. package/types/deploy/function/enterprise-tcr.d.ts +32 -0
  28. package/types/deploy/function/image-tag.d.ts +10 -0
  29. package/types/deploy/function/local-builder.d.ts +35 -6
  30. package/types/deploy/function/personal-tcr.d.ts +35 -0
  31. package/types/deploy/types.d.ts +110 -28
  32. package/types/hosting/index.d.ts +13 -0
  33. package/types/projectValidator/index.d.ts +3 -2
  34. package/types/projectValidator/types.d.ts +0 -1
  35. package/lib/deploy/StateStore.js +0 -328
  36. package/types/deploy/StateStore.d.ts +0 -174
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.IMAGE_PULL_GRANT_URL = exports.REQUIRED_IMAGE_PULL_POLICY = exports.SCF_PULL_IMAGE_ROLE = exports.isCamPermissionError = exports.runImagePullAuthPreflight = exports.runImageRemotePreflight = exports.runLocalPreflight = exports.createCloudBuildService = exports.buildImageOnCloud = exports.toCloudFunction = exports.createImageArtifactFromConfig = exports.createCodeArtifact = exports.toCurrentState = exports.createDeployPlan = exports.parseImageReference = exports.normalizeGatewayPath = exports.normalizeDeployConfig = exports.isCustomImageRuntime = exports.checkDeployConfig = exports.assertDeployConfig = exports.FunctionDeployer = void 0;
17
+ exports.IMAGE_PULL_GRANT_URL = exports.REQUIRED_IMAGE_PULL_POLICY = exports.SCF_PULL_IMAGE_ROLE = exports.isCamPermissionError = exports.runImagePullAuthPreflight = exports.runImageRemotePreflight = exports.runLocalPreflight = exports.createCloudBuildService = exports.buildImageOnCloud = exports.toCloudFunction = exports.createImageArtifactFromConfig = exports.createCodeArtifact = exports.toCurrentState = exports.createDeployPlan = exports.parseImageReference = exports.normalizeGatewayPath = exports.normalizeDeployConfig = exports.isCustomImageRuntime = exports.prepareMinimalDeployConfig = exports.getMissingDeployInputs = exports.applyMinimalDeployConfigDefaults = exports.checkDeployConfig = exports.assertDeployConfig = exports.FunctionDeployer = void 0;
18
18
  const error_1 = require("../error");
19
19
  const artifact_1 = require("./function/artifact");
20
20
  const config_guard_1 = require("./function/config-guard");
@@ -26,6 +26,8 @@ const GatewayDeployer_1 = require("./GatewayDeployer");
26
26
  const domain_1 = require("./domain");
27
27
  const image_preflight_1 = require("./function/image-preflight");
28
28
  const local_builder_1 = require("./function/local-builder");
29
+ const enterprise_tcr_1 = require("./function/enterprise-tcr");
30
+ const personal_tcr_1 = require("./function/personal-tcr");
29
31
  const planner_1 = require("./function/planner");
30
32
  const preflight_1 = require("./function/preflight");
31
33
  const types_1 = require("./types");
@@ -41,16 +43,21 @@ const AUTHZ_USER_REGO_KEY = 'authz.user.rego';
41
43
  *
42
44
  * 已支持代码包、已有镜像、云端构建、本地构建、匿名访问与网关路径收敛;
43
45
  * 函数类型、运行时或协议等创建期字段变化时不会自动删除函数,而是引导用户
44
- * 在控制台确认并手工删除后重新部署。local 企业版 TCR 等未实现能力会显式报错。
46
+ * 在控制台确认并手工删除后重新部署。
45
47
  */
46
48
  class FunctionDeployer {
47
49
  constructor(environment, deps) {
48
- var _a;
50
+ var _a, _b, _c;
49
51
  this.environment = environment;
50
52
  this.functionService = environment.getFunctionService();
51
53
  this.imagePreflightDeps = deps === null || deps === void 0 ? void 0 : deps.imagePreflightDeps;
52
54
  this.cloudBuildServiceFactory =
53
55
  (_a = deps === null || deps === void 0 ? void 0 : deps.cloudBuildServiceFactory) !== null && _a !== void 0 ? _a : (() => (0, cloud_build_service_1.createCloudBuildService)(this.environment.getCloudAppService()));
56
+ this.localBuilderDeps = deps === null || deps === void 0 ? void 0 : deps.localBuilderDeps;
57
+ this.tcrServiceFactory =
58
+ (_b = deps === null || deps === void 0 ? void 0 : deps.tcrServiceFactory) !== null && _b !== void 0 ? _b : (() => (0, enterprise_tcr_1.createTcrApiService)(this.environment));
59
+ this.personalTcrServiceFactory =
60
+ (_c = deps === null || deps === void 0 ? void 0 : deps.personalTcrServiceFactory) !== null && _c !== void 0 ? _c : (() => (0, personal_tcr_1.createPersonalTcrService)(this.environment));
54
61
  }
55
62
  /**
56
63
  * 兼容既有声明式部署入口
@@ -88,7 +95,12 @@ class FunctionDeployer {
88
95
  return;
89
96
  }
90
97
  const rule = this.buildPublicAccessRego(functionName);
91
- const mergedRego = currentRego.trim() ? `${currentRego.trim()}\n\n${rule}` : rule;
98
+ // 云端 Rego 校验器要求首条有效语句(注释不计)必须是 package 声明。
99
+ // currentRego 非空时已含 package authz.user,直接追加规则体即可;
100
+ // 为空(新环境首次配置)时需补齐 package 声明,否则触发 2:1: package expected。
101
+ const mergedRego = currentRego.trim()
102
+ ? `${currentRego.trim()}\n\n${rule}`
103
+ : `package authz.user\n\n${rule}`;
92
104
  await permissionService.modifyEnvAuthzConfig({
93
105
  key: AUTHZ_USER_REGO_KEY,
94
106
  value: mergedRego
@@ -169,6 +181,24 @@ class FunctionDeployer {
169
181
  checkConfig(config) {
170
182
  return (0, config_guard_1.checkDeployConfig)(config);
171
183
  }
184
+ /**
185
+ * 计算最小化部署配置的默认值,不执行网络或云端变更。
186
+ */
187
+ applyMinimalConfigDefaults(config, context = {}) {
188
+ return (0, config_guard_1.applyMinimalDeployConfigDefaults)(config, context);
189
+ }
190
+ /**
191
+ * 返回最小化配置仍缺失的字段,不执行网络或云端变更。
192
+ */
193
+ getMissingConfigInputs(config, context = {}) {
194
+ return (0, config_guard_1.getMissingDeployInputs)(config, context);
195
+ }
196
+ /**
197
+ * 应用安全默认值并返回缺失字段,供 CLI/MCP 逐步收集用户输入。
198
+ */
199
+ prepareMinimalConfig(config, context = {}) {
200
+ return (0, config_guard_1.prepareMinimalDeployConfig)(config, context);
201
+ }
172
202
  /**
173
203
  * 生成部署计划
174
204
  *
@@ -195,13 +225,14 @@ class FunctionDeployer {
195
225
  * @param options 部署选项,dryRun 时只生成计划不做任何变更
196
226
  */
197
227
  async deployFunction(config, options = {}) {
228
+ const deployConfig = config;
198
229
  const startTime = Date.now();
199
230
  const ctx = { steps: [], options };
200
231
  const warnings = [];
201
- const report = (0, config_guard_1.checkDeployConfig)(config);
232
+ const report = (0, config_guard_1.checkDeployConfig)(deployConfig);
202
233
  this.appendWarnings(warnings, report);
203
234
  const normalized = await this.runStep(ctx, 'validate', async () => {
204
- return (0, config_guard_1.assertDeployConfig)(config);
235
+ return (0, config_guard_1.assertDeployConfig)(deployConfig);
205
236
  });
206
237
  const plan = await this.runStep(ctx, 'plan', async () => {
207
238
  const current = await this.getCurrentFunction(normalized.name, normalized.codeSecret);
@@ -214,27 +245,52 @@ class FunctionDeployer {
214
245
  steps: ctx.steps,
215
246
  warnings,
216
247
  startTime,
217
- dryRun: true
248
+ dryRun: true,
249
+ options
218
250
  });
219
251
  }
220
252
  // 不可原地更新的变更必须在任何可能产生副作用的 Preflight 之前中止。
221
253
  // 尤其避免镜像拉取授权自动补齐等云端写操作先发生,再提示用户手工删除函数。
222
254
  this.assertPlanExecutable(plan);
223
- await this.runStep(ctx, 'preflight', async () => {
224
- const report = (0, preflight_1.runLocalPreflight)(normalized);
225
- this.appendWarnings(warnings, report);
226
- this.assertPreflightReady(report);
227
- });
228
- await this.runStep(ctx, 'preflight', async () => {
229
- const report = await (0, cam_preflight_1.runImagePullAuthPreflight)(this.createCamPreflightAdapter(), normalized, options.autoGrant !== false);
230
- this.appendWarnings(warnings, report);
231
- this.assertPreflightReady(report);
232
- });
233
- await this.runStep(ctx, 'preflight', async () => {
234
- const report = await (0, image_preflight_1.runImageRemotePreflight)(normalized, this.resolveDeployRegion(), this.imagePreflightDeps);
235
- this.appendWarnings(warnings, report);
236
- this.assertPreflightReady(report);
237
- });
255
+ if (normalized.type === 'HTTP' &&
256
+ (normalized.buildStrategy === 'cloud' || normalized.buildStrategy === 'zip')) {
257
+ await this.runLabeledStep(ctx, {
258
+ stage: 'preflight',
259
+ handler: async () => {
260
+ const report = (0, preflight_1.runLocalPreflight)(normalized);
261
+ this.appendWarnings(warnings, report);
262
+ this.assertPreflightReady(report);
263
+ },
264
+ label: normalized.buildStrategy === 'cloud'
265
+ ? '检查云端构建上下文'
266
+ : '检查函数代码包'
267
+ });
268
+ }
269
+ if (normalized.type === 'HTTP' &&
270
+ (normalized.buildStrategy === 'image' ||
271
+ normalized.buildStrategy === 'local' ||
272
+ normalized.buildStrategy === 'cloud')) {
273
+ await this.runLabeledStep(ctx, {
274
+ stage: 'preflight',
275
+ handler: async () => {
276
+ const report = await (0, cam_preflight_1.runImagePullAuthPreflight)(this.createCamPreflightAdapter(), normalized, options.autoGrant !== false);
277
+ this.appendWarnings(warnings, report);
278
+ this.assertPreflightReady(report);
279
+ },
280
+ label: '检查镜像仓库访问权限'
281
+ });
282
+ }
283
+ if (normalized.type === 'HTTP' && normalized.buildStrategy === 'image') {
284
+ await this.runLabeledStep(ctx, {
285
+ stage: 'preflight',
286
+ handler: async () => {
287
+ const report = await (0, image_preflight_1.runImageRemotePreflight)(normalized, this.resolveDeployRegion(), this.imagePreflightDeps);
288
+ this.appendWarnings(warnings, report);
289
+ this.assertPreflightReady(report);
290
+ },
291
+ label: '检查远端镜像与地域'
292
+ });
293
+ }
238
294
  // noop:函数本身无变更,但仍可能需要收敛访问配置
239
295
  if (plan.action === 'noop') {
240
296
  await this.applyAccessPlan(ctx, normalized, plan);
@@ -244,7 +300,8 @@ class FunctionDeployer {
244
300
  steps: ctx.steps,
245
301
  warnings,
246
302
  startTime,
247
- dryRun: false
303
+ dryRun: false,
304
+ options
248
305
  });
249
306
  }
250
307
  const artifact = await this.prepareArtifact(ctx, normalized, warnings);
@@ -257,6 +314,7 @@ class FunctionDeployer {
257
314
  warnings,
258
315
  startTime,
259
316
  dryRun: false,
317
+ options,
260
318
  artifact
261
319
  });
262
320
  }
@@ -264,7 +322,7 @@ class FunctionDeployer {
264
322
  * 将既有声明式调用补齐为完整部署配置
265
323
  */
266
324
  withLegacyDeployContext(func, functionRootPath, functionPath) {
267
- var _a, _b;
325
+ var _a, _b, _c, _d, _e;
268
326
  const config = Object.assign({}, func);
269
327
  const strategy = this.resolveStrategy(config);
270
328
  if (functionPath) {
@@ -282,16 +340,14 @@ class FunctionDeployer {
282
340
  (effectiveFunctionRootPath
283
341
  ? `${effectiveFunctionRootPath}/${config.name}`
284
342
  : undefined);
285
- if (buildCwd || ((_a = config.build) === null || _a === void 0 ? void 0 : _a.cwd)) {
286
- config.build = Object.assign(Object.assign({}, (config.build || {})), { cwd: ((_b = config.build) === null || _b === void 0 ? void 0 : _b.cwd) || buildCwd });
343
+ const existingCwd = (_b = (_a = config.imageConfig) === null || _a === void 0 ? void 0 : _a.build) === null || _b === void 0 ? void 0 : _b.cwd;
344
+ if (buildCwd || existingCwd) {
345
+ config.imageConfig = Object.assign(Object.assign({}, (config.imageConfig || {})), { build: Object.assign(Object.assign({}, (((_c = config.imageConfig) === null || _c === void 0 ? void 0 : _c.build) || {})), { cwd: existingCwd || buildCwd }) });
287
346
  }
288
347
  }
289
- // 兼容旧声明式 imageUri 字段,统一转换到运行时 imageConfig 契约
290
- if (strategy === 'image' && config.imageUri && !config.imageConfig) {
291
- config.imageType = config.imageType || 'personal';
292
- config.imageConfig = {
293
- imageUri: config.imageUri
294
- };
348
+ // 兼容旧声明式顶层 imageUri 字段,统一收敛到 imageConfig 契约
349
+ if (strategy === 'image' && config.imageUri && !((_d = config.imageConfig) === null || _d === void 0 ? void 0 : _d.imageUri)) {
350
+ config.imageConfig = Object.assign(Object.assign({ imageType: ((_e = config.imageConfig) === null || _e === void 0 ? void 0 : _e.imageType) || 'personal' }, (config.imageConfig || {})), { imageUri: config.imageUri });
295
351
  delete config.imageUri;
296
352
  }
297
353
  return config;
@@ -310,6 +366,21 @@ class FunctionDeployer {
310
366
  return undefined;
311
367
  }
312
368
  }
369
+ resolveEnvironmentId() {
370
+ try {
371
+ return this.environment.getEnvId();
372
+ }
373
+ catch (_a) {
374
+ return '';
375
+ }
376
+ }
377
+ requireDeployRegion() {
378
+ const region = this.resolveDeployRegion();
379
+ if (!region) {
380
+ throw new error_1.CloudBaseError('企业版 TCR 自动发现需要明确部署地域,请在环境配置中设置 region。', { code: types_1.FUNCTION_DEPLOY_ERROR.TCR_REGION_MISSING });
381
+ }
382
+ return region;
383
+ }
313
384
  /**
314
385
  * 构造镜像拉取授权 Preflight 所需的 CAM 适配器
315
386
  *
@@ -398,6 +469,66 @@ class FunctionDeployer {
398
469
  '\n部署器不会自动删除已有云函数。请先在云开发控制台确认触发器、访问配置和服务中断影响,手工删除该函数后重新部署。', { code: types_1.FUNCTION_DEPLOY_ERROR.FUNCTION_RECREATE_REQUIRED });
399
470
  }
400
471
  }
472
+ async prepareEnterpriseBuildConfig(ctx, config) {
473
+ const build = config.imageConfig.build;
474
+ const repository = build.repository || '';
475
+ const hasPreparedTarget = Boolean((config.imageConfig.registryId || build.registryId) && repository.split('/').length >= 3);
476
+ if (config.imageConfig.imageType !== 'enterprise' || hasPreparedTarget) {
477
+ return { config };
478
+ }
479
+ const prepared = await this.runLabeledStep(ctx, {
480
+ stage: 'preflight',
481
+ label: '准备企业版 TCR 目标仓库',
482
+ handler: () => (0, enterprise_tcr_1.prepareEnterpriseTcrTarget)(config, {
483
+ envId: this.resolveEnvironmentId(),
484
+ region: this.requireDeployRegion(),
485
+ service: this.tcrServiceFactory()
486
+ })
487
+ });
488
+ return { config: prepared.config, target: prepared.target };
489
+ }
490
+ async preparePersonalBuildConfig(ctx, config) {
491
+ var _a, _b, _c;
492
+ if (config.imageConfig.imageType !== 'personal') {
493
+ return config;
494
+ }
495
+ const envId = this.resolveEnvironmentId();
496
+ const build = config.imageConfig.build;
497
+ const configuredNamespace = (_a = build.namespace) === null || _a === void 0 ? void 0 : _a.trim();
498
+ const hasConfiguredRepository = Boolean((_b = build.repository) === null || _b === void 0 ? void 0 : _b.trim());
499
+ const configuredRepository = ((_c = build.repository) === null || _c === void 0 ? void 0 : _c.trim()) || config.name;
500
+ const parsedRepository = (0, config_guard_1.parseImageReference)(configuredRepository);
501
+ if (!parsedRepository || parsedRepository.tag || parsedRepository.digest) {
502
+ throw new error_1.CloudBaseError('个人版 TCR repository 不合法。', {
503
+ code: types_1.FUNCTION_DEPLOY_ERROR.BUILD_REPOSITORY_INVALID
504
+ });
505
+ }
506
+ const repositoryParts = parsedRepository.repository.split('/');
507
+ const repository = repositoryParts[repositoryParts.length - 1];
508
+ const repositoryNamespace = repositoryParts.length > 1 ? repositoryParts.slice(0, -1).join('/') : undefined;
509
+ const namespace = configuredNamespace || repositoryNamespace || envId;
510
+ const hasConfiguredNamespace = Boolean(configuredNamespace || repositoryNamespace);
511
+ const registry = parsedRepository.registry || personal_tcr_1.DEFAULT_PERSONAL_TCR_REGISTRY;
512
+ const credential = build.registryCredential;
513
+ if (!(credential === null || credential === void 0 ? void 0 : credential.username) || !credential.password) {
514
+ throw new error_1.CloudBaseError('个人版 TCR 构建缺少推送凭证。', {
515
+ code: types_1.FUNCTION_DEPLOY_ERROR.CLOUD_REGISTRY_CREDENTIAL_MISSING
516
+ });
517
+ }
518
+ await this.runLabeledStep(ctx, {
519
+ stage: 'preflight',
520
+ label: '准备个人版 TCR 目标仓库',
521
+ handler: () => this.personalTcrServiceFactory().ensurePushTarget({
522
+ namespace,
523
+ repository,
524
+ ensureNamespace: !hasConfiguredNamespace,
525
+ ensureRepository: !hasConfiguredRepository
526
+ })
527
+ });
528
+ const targetRepository = `${registry}/${namespace}/${repository}`;
529
+ const preparedConfig = Object.assign(Object.assign({}, config), { imageConfig: Object.assign(Object.assign({}, config.imageConfig), { build: Object.assign(Object.assign({}, build), { namespace, repository: targetRepository, registryCredential: credential }) }) });
530
+ return preparedConfig;
531
+ }
401
532
  /**
402
533
  * 准备部署物
403
534
  *
@@ -406,8 +537,22 @@ class FunctionDeployer {
406
537
  * 其余策略走同步的 pack。
407
538
  */
408
539
  async prepareArtifact(ctx, config, warnings) {
540
+ var _a;
409
541
  if (config.buildStrategy === 'cloud') {
410
- const cloudConfig = config;
542
+ const prepared = await this.prepareEnterpriseBuildConfig(ctx, config);
543
+ const cloudConfig = await this.preparePersonalBuildConfig(ctx, prepared.config);
544
+ // 企业版登录凭证在触发 CloudApp 构建前换取,构建容器只消费 Secrets,
545
+ // 不再自行签名调用 TCR API。
546
+ const cloudRegistryId = ((_a = prepared.target) === null || _a === void 0 ? void 0 : _a.registryId) ||
547
+ cloudConfig.imageConfig.build.registryId ||
548
+ cloudConfig.imageConfig.registryId;
549
+ const enterpriseCredential = cloudConfig.imageConfig.imageType === 'enterprise' && cloudRegistryId
550
+ ? await this.runLabeledStep(ctx, {
551
+ stage: 'preflight',
552
+ label: '获取企业版 TCR 临时登录凭证',
553
+ handler: () => (0, enterprise_tcr_1.createEnterpriseTcrCredential)(this.tcrServiceFactory(), cloudRegistryId)
554
+ })
555
+ : undefined;
411
556
  const buildResult = await this.runStep(ctx, 'build', async () => {
412
557
  const cloudBuildService = this.cloudBuildServiceFactory();
413
558
  return (0, cloud_1.buildImageOnCloud)(cloudConfig, cloudBuildService, {
@@ -416,27 +561,100 @@ class FunctionDeployer {
416
561
  status: 'start',
417
562
  message: line
418
563
  }),
419
- region: this.resolveDeployRegion()
564
+ enterpriseCredential
420
565
  });
421
566
  });
422
- return (0, artifact_1.createImageArtifactFromCloudBuild)(config, buildResult);
567
+ return (0, artifact_1.createImageArtifactFromCloudBuild)(cloudConfig, buildResult);
423
568
  }
424
569
  if (config.buildStrategy === 'local') {
425
- await this.runStep(ctx, 'preflight', async () => {
426
- const report = await (0, docker_preflight_1.runDockerPreflight)();
427
- this.appendWarnings(warnings, report);
428
- this.assertPreflightReady(report);
570
+ await this.runLabeledStep(ctx, {
571
+ stage: 'preflight',
572
+ handler: async () => {
573
+ const report = await (0, docker_preflight_1.runDockerPreflight)();
574
+ this.appendWarnings(warnings, report);
575
+ this.assertPreflightReady(report);
576
+ },
577
+ label: '检查本地 Docker 环境'
429
578
  });
430
- const localConfig = config;
431
- const buildResult = await this.runStep(ctx, 'build', async () => {
432
- return (0, local_builder_1.buildAndPushImage)(localConfig, line => this.emitProgress(ctx.options, { stage: 'build', status: 'start', message: line }));
433
- });
434
- return (0, artifact_1.createImageArtifactFromBuild)(config, buildResult);
579
+ const prepared = await this.prepareEnterpriseBuildConfig(ctx, config);
580
+ const localConfig = await this.preparePersonalBuildConfig(ctx, prepared.config);
581
+ const credential = await this.resolveLocalRegistryCredential(localConfig);
582
+ const dockerConfig = credential ? (0, local_builder_1.createTemporaryDockerConfig)() : undefined;
583
+ const commandOptions = dockerConfig ? { env: dockerConfig.env } : undefined;
584
+ try {
585
+ if (credential) {
586
+ await this.runStep(ctx, 'login', async () => {
587
+ await (0, local_builder_1.loginDockerRegistry)(this.resolveRegistryFromRepository(localConfig.imageConfig.build.repository), credential, { deps: this.localBuilderDeps, commandOptions });
588
+ });
589
+ }
590
+ const buildResult = await this.runStep(ctx, 'build', async () => {
591
+ return (0, local_builder_1.buildLocalImage)(localConfig, line => this.emitProgress(ctx.options, {
592
+ stage: 'build',
593
+ status: 'start',
594
+ message: line
595
+ }), { deps: this.localBuilderDeps, commandOptions });
596
+ });
597
+ const pushResult = await this.runStep(ctx, 'push', async () => {
598
+ return (0, local_builder_1.pushLocalImage)(buildResult.imageUri, line => this.emitProgress(ctx.options, {
599
+ stage: 'push',
600
+ status: 'start',
601
+ message: line
602
+ }), { deps: this.localBuilderDeps, commandOptions });
603
+ });
604
+ if (localConfig.imageConfig.imageType === 'personal') {
605
+ await this.runLabeledStep(ctx, {
606
+ stage: 'push',
607
+ label: '清理历史镜像标签',
608
+ handler: () => this.personalTcrServiceFactory().cleanupTags({
609
+ namespace: localConfig.imageConfig.build.namespace,
610
+ repository: localConfig.imageConfig.build.repository,
611
+ retain: localConfig.imageConfig.build.retainedTags
612
+ })
613
+ });
614
+ }
615
+ return (0, artifact_1.createImageArtifactFromBuild)(localConfig, {
616
+ imageUri: buildResult.imageUri,
617
+ imageDigest: pushResult.imageDigest
618
+ });
619
+ }
620
+ finally {
621
+ dockerConfig === null || dockerConfig === void 0 ? void 0 : dockerConfig.cleanup();
622
+ }
435
623
  }
436
624
  return this.runStep(ctx, 'pack', async () => {
437
625
  return this.createArtifact(config);
438
626
  });
439
627
  }
628
+ async resolveLocalRegistryCredential(config) {
629
+ var _a, _b, _c;
630
+ const build = config.imageConfig.build;
631
+ const imageType = (_a = config.imageConfig.imageType) !== null && _a !== void 0 ? _a : (((_b = config.imageConfig.registryId) !== null && _b !== void 0 ? _b : build.registryId) ? 'enterprise' : 'personal');
632
+ if (imageType === 'enterprise') {
633
+ const registryId = (_c = config.imageConfig.registryId) !== null && _c !== void 0 ? _c : build.registryId;
634
+ if (!registryId) {
635
+ throw new error_1.CloudBaseError('企业版 TCR local 构建缺少 registryId。', {
636
+ code: types_1.FUNCTION_DEPLOY_ERROR.IMAGE_REGISTRY_ID_MISSING
637
+ });
638
+ }
639
+ const credential = await (0, enterprise_tcr_1.createEnterpriseTcrCredential)(this.tcrServiceFactory(), registryId);
640
+ return { username: credential.username, secret: credential.token };
641
+ }
642
+ const credential = build.registryCredential;
643
+ if (!credential) {
644
+ return undefined;
645
+ }
646
+ return { username: credential.username, secret: credential.password };
647
+ }
648
+ resolveRegistryFromRepository(repository) {
649
+ const normalized = typeof repository === 'string' ? repository.trim() : '';
650
+ const slashIndex = normalized.indexOf('/');
651
+ if (slashIndex <= 0) {
652
+ throw new error_1.CloudBaseError('local 策略的目标镜像地址缺少仓库域名', {
653
+ code: types_1.FUNCTION_DEPLOY_ERROR.LOCAL_BUILD_REPOSITORY_MISSING
654
+ });
655
+ }
656
+ return normalized.slice(0, slashIndex);
657
+ }
440
658
  /** 生成部署物 */
441
659
  createArtifact(config) {
442
660
  if (config.buildStrategy === 'image') {
@@ -499,24 +717,53 @@ class FunctionDeployer {
499
717
  });
500
718
  }
501
719
  }
502
- /** 执行单个步骤并记录耗时与进度 */
720
+ /** 执行普通步骤并记录耗时与进度 */
503
721
  async runStep(ctx, stage, handler) {
722
+ return this.executeStep(ctx, { stage, handler });
723
+ }
724
+ /** 执行带具体名称的步骤并记录耗时与进度 */
725
+ async runLabeledStep(ctx, options) {
726
+ return this.executeStep(ctx, options);
727
+ }
728
+ async executeStep(ctx, options) {
729
+ var _a, _b, _c, _d, _e;
730
+ const { stage, handler, label } = options;
504
731
  const startTime = Date.now();
505
- this.emitProgress(ctx.options, { stage, status: 'start' });
732
+ this.emitProgress(ctx.options, { stage, label, status: 'start' });
506
733
  try {
507
734
  const result = await handler();
508
- ctx.steps.push({ stage, status: 'success', elapsedTime: Date.now() - startTime });
509
- this.emitProgress(ctx.options, { stage, status: 'success' });
735
+ const elapsedTime = Date.now() - startTime;
736
+ ctx.steps.push({ stage, label, status: 'success', elapsedTime });
737
+ this.emitProgress(ctx.options, { stage, label, status: 'success', elapsedTime });
510
738
  return result;
511
739
  }
512
740
  catch (error) {
741
+ const elapsedTime = Date.now() - startTime;
513
742
  ctx.steps.push({
514
743
  stage,
744
+ label,
745
+ status: 'failed',
746
+ elapsedTime,
747
+ detail: error === null || error === void 0 ? void 0 : error.message,
748
+ errorCode: error === null || error === void 0 ? void 0 : error.code
749
+ });
750
+ this.emitProgress(ctx.options, {
751
+ stage,
752
+ label,
515
753
  status: 'failed',
516
- elapsedTime: Date.now() - startTime,
517
- detail: error === null || error === void 0 ? void 0 : error.message
754
+ message: error === null || error === void 0 ? void 0 : error.message,
755
+ elapsedTime,
756
+ errorCode: error === null || error === void 0 ? void 0 : error.code,
757
+ requestId: (error === null || error === void 0 ? void 0 : error.requestId) ||
758
+ (error === null || error === void 0 ? void 0 : error.RequestId) ||
759
+ ((_a = error === null || error === void 0 ? void 0 : error.original) === null || _a === void 0 ? void 0 : _a.requestId) ||
760
+ ((_b = error === null || error === void 0 ? void 0 : error.original) === null || _b === void 0 ? void 0 : _b.RequestId) ||
761
+ ((_d = (_c = error === null || error === void 0 ? void 0 : error.original) === null || _c === void 0 ? void 0 : _c.Response) === null || _d === void 0 ? void 0 : _d.RequestId) ||
762
+ ((_e = error === null || error === void 0 ? void 0 : error.response) === null || _e === void 0 ? void 0 : _e.RequestId)
518
763
  });
519
- this.emitProgress(ctx.options, { stage, status: 'failed', message: error === null || error === void 0 ? void 0 : error.message });
764
+ if (error && !error.failedStage) {
765
+ error.failedStage = stage;
766
+ }
520
767
  throw error;
521
768
  }
522
769
  }
@@ -567,11 +814,19 @@ class FunctionDeployer {
567
814
  return result;
568
815
  }
569
816
  emitProgressDone(params) {
817
+ const elapsedTime = Date.now() - params.startTime;
570
818
  params.steps.push({
571
819
  stage: 'done',
572
820
  status: 'success',
573
- elapsedTime: Date.now() - params.startTime
821
+ elapsedTime
574
822
  });
823
+ if (params.options) {
824
+ this.emitProgress(params.options, {
825
+ stage: 'done',
826
+ status: 'success',
827
+ elapsedTime
828
+ });
829
+ }
575
830
  }
576
831
  }
577
832
  exports.FunctionDeployer = FunctionDeployer;
@@ -579,6 +834,9 @@ __exportStar(require("./types"), exports);
579
834
  var config_guard_2 = require("./function/config-guard");
580
835
  Object.defineProperty(exports, "assertDeployConfig", { enumerable: true, get: function () { return config_guard_2.assertDeployConfig; } });
581
836
  Object.defineProperty(exports, "checkDeployConfig", { enumerable: true, get: function () { return config_guard_2.checkDeployConfig; } });
837
+ Object.defineProperty(exports, "applyMinimalDeployConfigDefaults", { enumerable: true, get: function () { return config_guard_2.applyMinimalDeployConfigDefaults; } });
838
+ Object.defineProperty(exports, "getMissingDeployInputs", { enumerable: true, get: function () { return config_guard_2.getMissingDeployInputs; } });
839
+ Object.defineProperty(exports, "prepareMinimalDeployConfig", { enumerable: true, get: function () { return config_guard_2.prepareMinimalDeployConfig; } });
582
840
  Object.defineProperty(exports, "isCustomImageRuntime", { enumerable: true, get: function () { return config_guard_2.isCustomImageRuntime; } });
583
841
  Object.defineProperty(exports, "normalizeDeployConfig", { enumerable: true, get: function () { return config_guard_2.normalizeDeployConfig; } });
584
842
  Object.defineProperty(exports, "normalizeGatewayPath", { enumerable: true, get: function () { return config_guard_2.normalizeGatewayPath; } });
@@ -73,7 +73,13 @@ class StaticDeployer {
73
73
  const hostingOptions = {
74
74
  localPath: outputDir,
75
75
  cloudPath,
76
- ignore: config.ignore || ['.DS_Store']
76
+ ignore: config.ignore || ['.DS_Store'],
77
+ // 声明式配置名为 entryFile,透传到 uploadFiles 时对应 entryFiles
78
+ entryFiles: config.entryFile,
79
+ // 一致性发布开关:任一开启即走一致性上传(uploadDirectoryConsistent)
80
+ verify: config.verify,
81
+ safe: config.safe,
82
+ prune: config.prune
77
83
  };
78
84
  await this.environment.getHostingService().uploadFiles(hostingOptions);
79
85
  const url = await this.resolveHostingUrl(cloudPath);