@uofx/cli 1.0.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.
- package/LICENSE +40 -0
- package/README.md +444 -0
- package/THIRD-PARTY-NOTICES.txt +894 -0
- package/dist/application/dtos/index.js +24 -0
- package/dist/application/dtos/request/delete-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/get-config.request.dto.js +3 -0
- package/dist/application/dtos/request/get-credentials.request.dto.js +3 -0
- package/dist/application/dtos/request/index.js +27 -0
- package/dist/application/dtos/request/install-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/list-charts.request.dto.js +3 -0
- package/dist/application/dtos/request/set-config.request.dto.js +16 -0
- package/dist/application/dtos/request/setup-environment.request.dto.js +16 -0
- package/dist/application/dtos/request/show-logs.request.dto.js +19 -0
- package/dist/application/dtos/request/start-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/stop-instance.request.dto.js +3 -0
- package/dist/application/dtos/response/credentials.response.dto.js +3 -0
- package/dist/application/dtos/response/delete-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/index.js +26 -0
- package/dist/application/dtos/response/install-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/instance-list.response.dto.js +3 -0
- package/dist/application/dtos/response/instance-status.response.dto.js +3 -0
- package/dist/application/dtos/response/setup-result.response.dto.js +3 -0
- package/dist/application/dtos/response/show-logs.response.dto.js +3 -0
- package/dist/application/dtos/response/start-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/stop-instance.response.dto.js +3 -0
- package/dist/application/index.js +25 -0
- package/dist/application/interfaces/index.js +24 -0
- package/dist/application/interfaces/use-case.interface.js +3 -0
- package/dist/application/use-cases/config/get-config.use-case.js +66 -0
- package/dist/application/use-cases/config/set-config.use-case.js +49 -0
- package/dist/application/use-cases/credentials/get-credentials.use-case.js +57 -0
- package/dist/application/use-cases/index.js +28 -0
- package/dist/application/use-cases/instance/delete-instance.use-case.js +81 -0
- package/dist/application/use-cases/instance/index.js +23 -0
- package/dist/application/use-cases/instance/install-instance.use-case.js +424 -0
- package/dist/application/use-cases/instance/list-charts.use-case.js +43 -0
- package/dist/application/use-cases/instance/list-instances.use-case.js +62 -0
- package/dist/application/use-cases/instance/start-instance.use-case.js +154 -0
- package/dist/application/use-cases/instance/stop-instance.use-case.js +55 -0
- package/dist/application/use-cases/logs/show-logs.use-case.js +66 -0
- package/dist/application/use-cases/setup/setup-environment.use-case.js +53 -0
- package/dist/cli.js +286 -0
- package/dist/constants/config-defaults.js +23 -0
- package/dist/constants/defaults.js +89 -0
- package/dist/constants/deployment.js +39 -0
- package/dist/constants/environments.js +93 -0
- package/dist/constants/index.js +53 -0
- package/dist/constants/oci-artifacts.js +25 -0
- package/dist/constants/paths.js +92 -0
- package/dist/constants/timeouts.js +60 -0
- package/dist/di/container.js +34 -0
- package/dist/di/index.js +22 -0
- package/dist/di/modules/application.module.js +54 -0
- package/dist/di/modules/infrastructure.module.js +206 -0
- package/dist/di/modules/interceptor.module.js +68 -0
- package/dist/di/modules/presentation.module.js +31 -0
- package/dist/di/tokens.js +149 -0
- package/dist/domain/decorators/sensitive.decorator.js +39 -0
- package/dist/domain/entities/credentials-resolver.entity.js +127 -0
- package/dist/domain/entities/credentials.entity.js +65 -0
- package/dist/domain/entities/delete-instance-validation.entity.js +100 -0
- package/dist/domain/entities/deployment-parameters.entity.js +120 -0
- package/dist/domain/entities/environment-validation.entity.js +125 -0
- package/dist/domain/entities/index.js +29 -0
- package/dist/domain/entities/instance-lifecycle-state.entity.js +100 -0
- package/dist/domain/entities/instance-list-aggregator.entity.js +104 -0
- package/dist/domain/entities/instance-metadata.entity.js +86 -0
- package/dist/domain/entities/instance-status.entity.js +79 -0
- package/dist/domain/entities/instance.entity.js +128 -0
- package/dist/domain/entities/log-filter.entity.js +141 -0
- package/dist/domain/index.js +29 -0
- package/dist/domain/interfaces/safe-loggable.interface.js +3 -0
- package/dist/domain/ports/app-config.port.js +3 -0
- package/dist/domain/ports/base-image.port.js +3 -0
- package/dist/domain/ports/chart-version.port.js +3 -0
- package/dist/domain/ports/correlation-id.port.js +3 -0
- package/dist/domain/ports/credentials.port.js +3 -0
- package/dist/domain/ports/deployment.port.js +3 -0
- package/dist/domain/ports/error-handler.port.js +3 -0
- package/dist/domain/ports/index.js +46 -0
- package/dist/domain/ports/instance-manager.port.js +3 -0
- package/dist/domain/ports/instance-metadata.port.js +8 -0
- package/dist/domain/ports/instance-storage.port.js +3 -0
- package/dist/domain/ports/k8s-deployer.port.js +3 -0
- package/dist/domain/ports/logger.port.js +14 -0
- package/dist/domain/ports/output.port.js +3 -0
- package/dist/domain/ports/runtime-environment.port.js +6 -0
- package/dist/domain/ports/user-interaction.port.js +9 -0
- package/dist/domain/ports/user-settings.port.js +3 -0
- package/dist/domain/types/index.js +22 -0
- package/dist/domain/types/logger.types.js +29 -0
- package/dist/domain/types/validation.types.js +9 -0
- package/dist/domain/value-objects/acr-credentials.value-object.js +92 -0
- package/dist/domain/value-objects/chart-version.value-object.js +124 -0
- package/dist/domain/value-objects/config-log-level.value-object.js +84 -0
- package/dist/domain/value-objects/connection-info.value-object.js +65 -0
- package/dist/domain/value-objects/index.js +25 -0
- package/dist/domain/value-objects/instance-name.value-object.js +91 -0
- package/dist/domain/value-objects/jwt-key.value-object.js +97 -0
- package/dist/domain/value-objects/mssql-password.value-object.js +140 -0
- package/dist/domain/value-objects/rsa-key-pair.value-object.js +181 -0
- package/dist/index.js +6 -0
- package/dist/infrastructure/config/app-config.interface.js +3 -0
- package/dist/infrastructure/config/app-config.service.js +280 -0
- package/dist/infrastructure/config/config-validator.js +31 -0
- package/dist/infrastructure/config/crypto.service.js +125 -0
- package/dist/infrastructure/deployment/deployment.adapter.js +118 -0
- package/dist/infrastructure/deployment/interfaces/acr-credential-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/app-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/helm-registry.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/infra-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/k8s-job-runner.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-database-init.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-helm-deployment.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-storage.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-user-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/oci-artifact.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/secret-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/service-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/version-compatibility.interface.js +3 -0
- package/dist/infrastructure/deployment/services/acr-credential-manager.service.js +144 -0
- package/dist/infrastructure/deployment/services/app-manager.service.js +193 -0
- package/dist/infrastructure/deployment/services/base-helm-deployment.service.js +163 -0
- package/dist/infrastructure/deployment/services/helm-registry.service.js +126 -0
- package/dist/infrastructure/deployment/services/infra-manager.service.js +130 -0
- package/dist/infrastructure/deployment/services/k8s-job-runner.service.js +194 -0
- package/dist/infrastructure/deployment/services/mssql-database-init.service.js +139 -0
- package/dist/infrastructure/deployment/services/mssql-helm-deployment.service.js +100 -0
- package/dist/infrastructure/deployment/services/mssql-storage.service.js +54 -0
- package/dist/infrastructure/deployment/services/mssql-user-manager.service.js +66 -0
- package/dist/infrastructure/deployment/services/oci-artifact.service.js +289 -0
- package/dist/infrastructure/deployment/services/secret-manager.service.js +179 -0
- package/dist/infrastructure/deployment/services/service-manager.service.js +82 -0
- package/dist/infrastructure/deployment/services/version-compatibility.service.js +291 -0
- package/dist/infrastructure/environment/interfaces/hardware-info.interface.js +3 -0
- package/dist/infrastructure/environment/interfaces/network-checker.interface.js +3 -0
- package/dist/infrastructure/environment/services/hardware-info.service.js +135 -0
- package/dist/infrastructure/environment/services/network-checker.service.js +142 -0
- package/dist/infrastructure/environment/windows-environment.adapter.js +162 -0
- package/dist/infrastructure/errors/app-error.js +73 -0
- package/dist/infrastructure/errors/error-handler.interface.js +3 -0
- package/dist/infrastructure/errors/error-handler.js +218 -0
- package/dist/infrastructure/errors/exit-codes.js +27 -0
- package/dist/infrastructure/errors/index.js +25 -0
- package/dist/infrastructure/execution/builders/base-command.builder.js +122 -0
- package/dist/infrastructure/execution/builders/host-command.builder.js +58 -0
- package/dist/infrastructure/execution/builders/windows-host-command.builder.js +50 -0
- package/dist/infrastructure/execution/builders/wsl-command.builder.js +29 -0
- package/dist/infrastructure/execution/command-builder.js +252 -0
- package/dist/infrastructure/execution/command-executor.service.js +230 -0
- package/dist/infrastructure/execution/environments/wsl-execution.environment.js +70 -0
- package/dist/infrastructure/execution/execution-environment.factory.js +53 -0
- package/dist/infrastructure/execution/index.js +25 -0
- package/dist/infrastructure/execution/interfaces/command-builder.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/command-executor.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/execution-environment-factory.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/execution-environment.interface.js +7 -0
- package/dist/infrastructure/execution/interfaces/host-command-builder.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/index.js +23 -0
- package/dist/infrastructure/execution/interfaces/script-executor.interface.js +3 -0
- package/dist/infrastructure/execution/script-executor.service.js +171 -0
- package/dist/infrastructure/http/http-client.service.js +176 -0
- package/dist/infrastructure/http/index.js +18 -0
- package/dist/infrastructure/http/interfaces/http-client.interface.js +3 -0
- package/dist/infrastructure/interceptors/index.js +8 -0
- package/dist/infrastructure/interceptors/interceptor.factory.js +44 -0
- package/dist/infrastructure/interceptors/interceptor.interface.js +3 -0
- package/dist/infrastructure/interceptors/logging.interceptor.js +171 -0
- package/dist/infrastructure/logger/correlation-id.adapter.js +68 -0
- package/dist/infrastructure/logger/index.js +23 -0
- package/dist/infrastructure/logger/interfaces/index.js +22 -0
- package/dist/infrastructure/logger/interfaces/log-reader.repository.interface.js +7 -0
- package/dist/infrastructure/logger/interfaces/log-writer.repository.interface.js +7 -0
- package/dist/infrastructure/logger/logger.adapter.js +274 -0
- package/dist/infrastructure/logger/services/file-log-reader.repository.js +148 -0
- package/dist/infrastructure/logger/services/file-log-writer.repository.js +307 -0
- package/dist/infrastructure/logger/services/index.js +22 -0
- package/dist/infrastructure/persistence/index.js +25 -0
- package/dist/infrastructure/persistence/instance-metadata.adapter.js +100 -0
- package/dist/infrastructure/persistence/instance-storage.adapter.js +64 -0
- package/dist/infrastructure/persistence/interfaces/config.repository.interface.js +3 -0
- package/dist/infrastructure/persistence/interfaces/index.js +22 -0
- package/dist/infrastructure/persistence/interfaces/instance.repository.interface.js +3 -0
- package/dist/infrastructure/persistence/services/file-system-config.repository.js +168 -0
- package/dist/infrastructure/persistence/services/file-system-instance.repository.js +170 -0
- package/dist/infrastructure/persistence/services/index.js +22 -0
- package/dist/infrastructure/persistence/user-settings.adapter.js +55 -0
- package/dist/infrastructure/platform-detector.js +71 -0
- package/dist/infrastructure/platforms/windows/interfaces/microk8s.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/rootfs-manager.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/windows-features.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/windows-info.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-config.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-info.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-inspection.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-lifecycle.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-naming.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-manager.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-resources.interface.js +8 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-updater.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wslconfig-parser.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/parsers/wsl-version.parser.js +133 -0
- package/dist/infrastructure/platforms/windows/services/microk8s.service.js +168 -0
- package/dist/infrastructure/platforms/windows/services/rootfs-manager.service.js +336 -0
- package/dist/infrastructure/platforms/windows/services/windows-features.service.js +191 -0
- package/dist/infrastructure/platforms/windows/services/windows-info.service.js +138 -0
- package/dist/infrastructure/platforms/windows/services/wsl-config.service.js +171 -0
- package/dist/infrastructure/platforms/windows/services/wsl-info.service.js +226 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-inspection.service.js +325 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-lifecycle.service.js +442 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-naming.service.js +93 -0
- package/dist/infrastructure/platforms/windows/services/wsl-updater.service.js +273 -0
- package/dist/infrastructure/platforms/windows/services/wslconfig-parser.service.js +222 -0
- package/dist/infrastructure/platforms/windows/wsl-base-image.adapter.js +41 -0
- package/dist/infrastructure/platforms/windows/wsl-instance-manager.adapter.js +150 -0
- package/dist/infrastructure/utils/error-formatter.util.js +29 -0
- package/dist/infrastructure/utils/file-operations.util.js +201 -0
- package/dist/infrastructure/utils/input-validator.util.js +152 -0
- package/dist/infrastructure/utils/retry.util.js +98 -0
- package/dist/presentation/controllers/config.controller.js +146 -0
- package/dist/presentation/controllers/credentials.controller.js +105 -0
- package/dist/presentation/controllers/index.js +25 -0
- package/dist/presentation/controllers/instance.controller.js +363 -0
- package/dist/presentation/controllers/logs.controller.js +103 -0
- package/dist/presentation/controllers/setup.controller.js +175 -0
- package/dist/presentation/interfaces/cli-options.interface.js +8 -0
- package/dist/presentation/prompts/acr-credentials.prompt.js +76 -0
- package/dist/presentation/prompts/index.js +21 -0
- package/dist/presentation/ui/cli-progress.service.js +193 -0
- package/dist/presentation/ui/constants/output-symbols.js +42 -0
- package/dist/presentation/ui/index.js +27 -0
- package/dist/presentation/ui/interaction.service.js +276 -0
- package/dist/presentation/ui/interfaces/cli-progress.interface.js +9 -0
- package/dist/presentation/ui/interfaces/output-formatter.interface.js +23 -0
- package/dist/presentation/ui/log-level.enum.js +66 -0
- package/dist/presentation/ui/output-builder.service.js +378 -0
- package/dist/presentation/ui/output-formatter.service.js +393 -0
- package/package.json +65 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 錯誤格式化工具
|
|
4
|
+
* 提供統一的錯誤訊息轉換方法
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.formatErrorMessage = formatErrorMessage;
|
|
8
|
+
exports.toError = toError;
|
|
9
|
+
/**
|
|
10
|
+
* 從 unknown 類型的錯誤中提取訊息字串
|
|
11
|
+
* @param error - 任何類型的錯誤
|
|
12
|
+
* @returns 錯誤訊息字串
|
|
13
|
+
*/
|
|
14
|
+
function formatErrorMessage(error) {
|
|
15
|
+
return error instanceof Error ? error.message : String(error);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 將錯誤轉換為 Error 物件
|
|
19
|
+
* @param error - 任何類型的錯誤
|
|
20
|
+
* @param defaultMessage - 當無法轉換時使用的預設訊息
|
|
21
|
+
* @returns Error 物件
|
|
22
|
+
*/
|
|
23
|
+
function toError(error, defaultMessage = 'Unknown error') {
|
|
24
|
+
if (error instanceof Error) {
|
|
25
|
+
return error;
|
|
26
|
+
}
|
|
27
|
+
return new Error(error ? String(error) : defaultMessage);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=error-formatter.util.js.map
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 檔案操作工具函數
|
|
4
|
+
*
|
|
5
|
+
* 提供同步和非同步檔案操作的統一介面,
|
|
6
|
+
* 減少重複程式碼並提高可維護性。
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.rotateLogFiles = rotateLogFiles;
|
|
43
|
+
exports.cleanupOldLogFiles = cleanupOldLogFiles;
|
|
44
|
+
exports.shouldRotate = shouldRotate;
|
|
45
|
+
exports.rotateLogFilesSync = rotateLogFilesSync;
|
|
46
|
+
exports.cleanupOldLogFilesSync = cleanupOldLogFilesSync;
|
|
47
|
+
exports.shouldRotateSync = shouldRotateSync;
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// 非同步版本
|
|
52
|
+
// ============================================================================
|
|
53
|
+
/**
|
|
54
|
+
* 執行日誌檔案輪轉(非同步)
|
|
55
|
+
*/
|
|
56
|
+
async function rotateLogFiles(config) {
|
|
57
|
+
const { filePath, maxFiles } = config;
|
|
58
|
+
const ext = path.extname(filePath);
|
|
59
|
+
const baseWithoutExt = filePath.slice(0, -ext.length);
|
|
60
|
+
// 刪除最舊的檔案
|
|
61
|
+
const oldestFile = `${baseWithoutExt}.${maxFiles}${ext}`;
|
|
62
|
+
await safeUnlink(oldestFile);
|
|
63
|
+
// 依序將 .n 移動到 .n+1
|
|
64
|
+
for (let i = maxFiles - 1; i >= 1; i--) {
|
|
65
|
+
const oldFile = `${baseWithoutExt}.${i}${ext}`;
|
|
66
|
+
const newFile = `${baseWithoutExt}.${i + 1}${ext}`;
|
|
67
|
+
await safeRename(oldFile, newFile);
|
|
68
|
+
}
|
|
69
|
+
// 將當前檔案移動到 .1
|
|
70
|
+
await safeRename(filePath, `${baseWithoutExt}.1${ext}`);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 清理過期的日誌檔案(非同步)
|
|
74
|
+
*/
|
|
75
|
+
async function cleanupOldLogFiles(config) {
|
|
76
|
+
const { baseDir, filePrefix, fileExtension, maxFiles } = config;
|
|
77
|
+
try {
|
|
78
|
+
const files = await fs.promises.readdir(baseDir);
|
|
79
|
+
const logFiles = files
|
|
80
|
+
.filter((f) => f.startsWith(filePrefix) && f.endsWith(fileExtension))
|
|
81
|
+
.sort()
|
|
82
|
+
.reverse();
|
|
83
|
+
for (let i = maxFiles; i < logFiles.length; i++) {
|
|
84
|
+
const filePath = path.join(baseDir, logFiles[i]);
|
|
85
|
+
await safeUnlink(filePath);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// 靜默處理:讀取目錄失敗
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 檢查檔案大小是否超過限制(非同步)
|
|
94
|
+
*/
|
|
95
|
+
async function shouldRotate(filePath, maxSize) {
|
|
96
|
+
try {
|
|
97
|
+
const stats = await fs.promises.stat(filePath);
|
|
98
|
+
return stats.size >= maxSize;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// 同步版本
|
|
106
|
+
// ============================================================================
|
|
107
|
+
/**
|
|
108
|
+
* 執行日誌檔案輪轉(同步)
|
|
109
|
+
*/
|
|
110
|
+
function rotateLogFilesSync(config) {
|
|
111
|
+
const { filePath, maxFiles } = config;
|
|
112
|
+
const ext = path.extname(filePath);
|
|
113
|
+
const baseWithoutExt = filePath.slice(0, -ext.length);
|
|
114
|
+
// 刪除最舊的檔案
|
|
115
|
+
const oldestFile = `${baseWithoutExt}.${maxFiles}${ext}`;
|
|
116
|
+
safeUnlinkSync(oldestFile);
|
|
117
|
+
// 依序將 .n 移動到 .n+1
|
|
118
|
+
for (let i = maxFiles - 1; i >= 1; i--) {
|
|
119
|
+
const oldFile = `${baseWithoutExt}.${i}${ext}`;
|
|
120
|
+
const newFile = `${baseWithoutExt}.${i + 1}${ext}`;
|
|
121
|
+
safeRenameSync(oldFile, newFile);
|
|
122
|
+
}
|
|
123
|
+
// 將當前檔案移動到 .1
|
|
124
|
+
safeRenameSync(filePath, `${baseWithoutExt}.1${ext}`);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 清理過期的日誌檔案(同步)
|
|
128
|
+
*/
|
|
129
|
+
function cleanupOldLogFilesSync(config) {
|
|
130
|
+
const { baseDir, filePrefix, fileExtension, maxFiles } = config;
|
|
131
|
+
try {
|
|
132
|
+
const files = fs.readdirSync(baseDir);
|
|
133
|
+
const logFiles = files
|
|
134
|
+
.filter((f) => f.startsWith(filePrefix) && f.endsWith(fileExtension))
|
|
135
|
+
.sort()
|
|
136
|
+
.reverse();
|
|
137
|
+
for (let i = maxFiles; i < logFiles.length; i++) {
|
|
138
|
+
const filePath = path.join(baseDir, logFiles[i]);
|
|
139
|
+
safeUnlinkSync(filePath);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// 靜默處理:讀取目錄失敗
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 檢查檔案大小是否超過限制(同步)
|
|
148
|
+
*/
|
|
149
|
+
function shouldRotateSync(filePath, maxSize) {
|
|
150
|
+
try {
|
|
151
|
+
if (!fs.existsSync(filePath)) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
const stats = fs.statSync(filePath);
|
|
155
|
+
return stats.size >= maxSize;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// 內部輔助函數
|
|
163
|
+
// ============================================================================
|
|
164
|
+
async function safeUnlink(filePath) {
|
|
165
|
+
try {
|
|
166
|
+
await fs.promises.unlink(filePath);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// 檔案可能不存在,靜默處理
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function safeUnlinkSync(filePath) {
|
|
173
|
+
try {
|
|
174
|
+
if (fs.existsSync(filePath)) {
|
|
175
|
+
fs.unlinkSync(filePath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// 檔案可能不存在,靜默處理
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function safeRename(oldPath, newPath) {
|
|
183
|
+
try {
|
|
184
|
+
await fs.promises.access(oldPath);
|
|
185
|
+
await fs.promises.rename(oldPath, newPath);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// 檔案可能不存在,靜默處理
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function safeRenameSync(oldPath, newPath) {
|
|
192
|
+
try {
|
|
193
|
+
if (fs.existsSync(oldPath)) {
|
|
194
|
+
fs.renameSync(oldPath, newPath);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// 檔案可能不存在,靜默處理
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=file-operations.util.js.map
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateInstanceName = validateInstanceName;
|
|
4
|
+
exports.validateLinuxPath = validateLinuxPath;
|
|
5
|
+
exports.validateUsername = validateUsername;
|
|
6
|
+
exports.validateChartVersion = validateChartVersion;
|
|
7
|
+
exports.validateCommandArg = validateCommandArg;
|
|
8
|
+
exports.requireValidInstanceName = requireValidInstanceName;
|
|
9
|
+
exports.requireValidUsername = requireValidUsername;
|
|
10
|
+
exports.requireValidPath = requireValidPath;
|
|
11
|
+
const instance_name_value_object_1 = require("../../domain/value-objects/instance-name.value-object");
|
|
12
|
+
/**
|
|
13
|
+
* 輸入驗證工具
|
|
14
|
+
*
|
|
15
|
+
* 提供命令參數的安全驗證,防止 Command Injection 攻擊
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* 驗證實例名稱格式
|
|
19
|
+
* 委託給 Domain VO 進行驗證,確保 Single Source of Truth
|
|
20
|
+
*
|
|
21
|
+
* @param name - 實例名稱
|
|
22
|
+
* @returns true 如果名稱格式正確
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* validateInstanceName('dev') // true
|
|
26
|
+
* validateInstanceName('test-env') // true
|
|
27
|
+
* validateInstanceName('bad;name') // false
|
|
28
|
+
* validateInstanceName('$(rm -rf /)') // false
|
|
29
|
+
*/
|
|
30
|
+
function validateInstanceName(name) {
|
|
31
|
+
return instance_name_value_object_1.InstanceName.isValid(name);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 驗證 Linux 路徑格式
|
|
35
|
+
* 只允許安全的路徑字符,禁止命令注入字符
|
|
36
|
+
*
|
|
37
|
+
* @param path - 路徑字串
|
|
38
|
+
* @returns true 如果路徑格式安全
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* validateLinuxPath('/home/ubuntu/data') // true
|
|
42
|
+
* validateLinuxPath('/var/opt/mssql') // true
|
|
43
|
+
* validateLinuxPath('/path/$(rm -rf /)') // false
|
|
44
|
+
* validateLinuxPath('/path;rm -rf /') // false
|
|
45
|
+
*/
|
|
46
|
+
function validateLinuxPath(path) {
|
|
47
|
+
if (!path || typeof path !== 'string') {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
// 禁止命令注入字符: $, `, ;, &, |, (, ), {, }, [, ], <, >, \n, \r
|
|
51
|
+
const dangerousChars = /[$`;&|(){}[\]<>\n\r]/;
|
|
52
|
+
if (dangerousChars.test(path)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
// 只允許安全的路徑字符
|
|
56
|
+
return /^[a-zA-Z0-9_\-./]+$/.test(path);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 驗證使用者名稱格式
|
|
60
|
+
* 只允許標準 Linux 使用者名稱字符
|
|
61
|
+
*
|
|
62
|
+
* @param username - 使用者名稱
|
|
63
|
+
* @returns true 如果使用者名稱格式正確
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* validateUsername('ubuntu') // true
|
|
67
|
+
* validateUsername('user_123') // true
|
|
68
|
+
* validateUsername("user'; rm -rf /") // false
|
|
69
|
+
*/
|
|
70
|
+
function validateUsername(username) {
|
|
71
|
+
if (!username || typeof username !== 'string') {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// Linux 使用者名稱規則:以字母開頭,只能包含字母、數字、底線、連字號
|
|
75
|
+
// 長度限制 1-32 字符
|
|
76
|
+
return /^[a-z_][a-z0-9_-]{0,31}$/.test(username);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 驗證 Chart 版本格式
|
|
80
|
+
* 只允許語義化版本號格式
|
|
81
|
+
*
|
|
82
|
+
* @param version - 版本字串
|
|
83
|
+
* @returns true 如果版本格式正確
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* validateChartVersion('1.0.0') // true
|
|
87
|
+
* validateChartVersion('1.2.3-beta.1') // true
|
|
88
|
+
* validateChartVersion('0.0.0-dev') // true
|
|
89
|
+
* validateChartVersion('$(rm -rf /)') // false
|
|
90
|
+
*/
|
|
91
|
+
function validateChartVersion(version) {
|
|
92
|
+
if (!version || typeof version !== 'string') {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
// 語義化版本號:major.minor.patch[-prerelease][+build]
|
|
96
|
+
return /^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/.test(version);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 驗證命令參數是否安全
|
|
100
|
+
* 檢查是否包含危險的 shell 字符
|
|
101
|
+
*
|
|
102
|
+
* @param arg - 命令參數
|
|
103
|
+
* @returns true 如果參數安全
|
|
104
|
+
*/
|
|
105
|
+
function validateCommandArg(arg) {
|
|
106
|
+
if (!arg || typeof arg !== 'string') {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
// 禁止 shell 元字符
|
|
110
|
+
const dangerousChars = /[$`;&|(){}[\]<>\n\r\\'"]/;
|
|
111
|
+
return !dangerousChars.test(arg);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 確保實例名稱有效,無效則拋出錯誤
|
|
115
|
+
*
|
|
116
|
+
* @param name - 實例名稱
|
|
117
|
+
* @throws Error 如果名稱無效
|
|
118
|
+
*/
|
|
119
|
+
function requireValidInstanceName(name) {
|
|
120
|
+
if (!validateInstanceName(name)) {
|
|
121
|
+
throw new Error(`Invalid instance name: '${name}'. ` +
|
|
122
|
+
`Instance name must be 1-50 characters, start and end with alphanumeric characters, ` +
|
|
123
|
+
`and contain only letters, numbers, and hyphens.`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 確保使用者名稱有效,無效則拋出錯誤
|
|
128
|
+
*
|
|
129
|
+
* @param username - 使用者名稱
|
|
130
|
+
* @throws Error 如果使用者名稱無效
|
|
131
|
+
*/
|
|
132
|
+
function requireValidUsername(username) {
|
|
133
|
+
if (!validateUsername(username)) {
|
|
134
|
+
throw new Error(`Invalid username: '${username}'. ` +
|
|
135
|
+
`Username must start with a lowercase letter or underscore, ` +
|
|
136
|
+
`contain only lowercase letters, numbers, underscores, and hyphens, ` +
|
|
137
|
+
`and be at most 32 characters.`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 確保路徑有效,無效則拋出錯誤
|
|
142
|
+
*
|
|
143
|
+
* @param path - 路徑
|
|
144
|
+
* @throws Error 如果路徑無效
|
|
145
|
+
*/
|
|
146
|
+
function requireValidPath(path) {
|
|
147
|
+
if (!validateLinuxPath(path)) {
|
|
148
|
+
throw new Error(`Invalid path: '${path}'. ` +
|
|
149
|
+
`Path contains dangerous characters or is in an invalid format.`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=input-validator.util.js.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 重試工具
|
|
4
|
+
*
|
|
5
|
+
* 提供可配置的重試邏輯,支援退避策略
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isRetryableNetworkError = isRetryableNetworkError;
|
|
9
|
+
exports.retryWithBackoff = retryWithBackoff;
|
|
10
|
+
exports.createHelmRetryOptions = createHelmRetryOptions;
|
|
11
|
+
/**
|
|
12
|
+
* 預設的可重試錯誤判斷
|
|
13
|
+
* 檢查是否為網路相關錯誤
|
|
14
|
+
*/
|
|
15
|
+
function isRetryableNetworkError(error) {
|
|
16
|
+
const message = error.message || '';
|
|
17
|
+
return (message.includes('connection refused') ||
|
|
18
|
+
message.includes('dial tcp') ||
|
|
19
|
+
message.includes('ECONNREFUSED') ||
|
|
20
|
+
message.includes('ETIMEDOUT') ||
|
|
21
|
+
message.includes('ENOTFOUND'));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 帶退避策略的重試執行器
|
|
25
|
+
*
|
|
26
|
+
* @param operation - 要執行的非同步操作
|
|
27
|
+
* @param options - 重試選項
|
|
28
|
+
* @returns 操作結果
|
|
29
|
+
* @throws 最後一次失敗的錯誤
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const result = await retryWithBackoff(
|
|
34
|
+
* () => fetchData(),
|
|
35
|
+
* {
|
|
36
|
+
* maxRetries: 3,
|
|
37
|
+
* delayMs: 1000,
|
|
38
|
+
* backoffMultiplier: 2,
|
|
39
|
+
* shouldRetry: isRetryableNetworkError,
|
|
40
|
+
* onRetry: (attempt, error) => console.log(`Retry ${attempt}: ${error.message}`)
|
|
41
|
+
* }
|
|
42
|
+
* );
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
async function retryWithBackoff(operation, options) {
|
|
46
|
+
const { maxRetries, delayMs, backoffMultiplier = 1, maxDelayMs = 60000, shouldRetry = () => true, onRetry, } = options;
|
|
47
|
+
let lastError = null;
|
|
48
|
+
let currentDelay = delayMs;
|
|
49
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
50
|
+
try {
|
|
51
|
+
return await operation();
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
lastError = err;
|
|
55
|
+
// 最後一次嘗試失敗,直接拋出
|
|
56
|
+
if (attempt >= maxRetries) {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
// 檢查是否應該重試
|
|
60
|
+
if (!shouldRetry(lastError)) {
|
|
61
|
+
throw lastError;
|
|
62
|
+
}
|
|
63
|
+
// 執行重試回調
|
|
64
|
+
if (onRetry) {
|
|
65
|
+
onRetry(attempt + 1, lastError);
|
|
66
|
+
}
|
|
67
|
+
// 等待後重試
|
|
68
|
+
await sleep(currentDelay);
|
|
69
|
+
// 計算下次延遲(使用退避策略)
|
|
70
|
+
currentDelay = Math.min(currentDelay * backoffMultiplier, maxDelayMs);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
throw lastError;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 延遲指定時間
|
|
77
|
+
* @param ms - 毫秒數
|
|
78
|
+
*/
|
|
79
|
+
function sleep(ms) {
|
|
80
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 建立 Helm 安裝的重試選項
|
|
84
|
+
* 預設配置適用於 Helm chart 安裝
|
|
85
|
+
*
|
|
86
|
+
* @param options - 自訂選項
|
|
87
|
+
* @returns 完整的重試選項
|
|
88
|
+
*/
|
|
89
|
+
function createHelmRetryOptions(options) {
|
|
90
|
+
return {
|
|
91
|
+
maxRetries: options?.maxRetries ?? 3,
|
|
92
|
+
delayMs: options?.delayMs ?? 5000,
|
|
93
|
+
backoffMultiplier: 1,
|
|
94
|
+
shouldRetry: isRetryableNetworkError,
|
|
95
|
+
onRetry: options?.onRetry,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=retry.util.js.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.ConfigController = void 0;
|
|
16
|
+
const tsyringe_1 = require("tsyringe");
|
|
17
|
+
const tokens_1 = require("../../di/tokens");
|
|
18
|
+
const get_config_use_case_1 = require("../../application/use-cases/config/get-config.use-case");
|
|
19
|
+
const set_config_use_case_1 = require("../../application/use-cases/config/set-config.use-case");
|
|
20
|
+
const error_formatter_util_1 = require("../../infrastructure/utils/error-formatter.util");
|
|
21
|
+
/**
|
|
22
|
+
* Config Controller
|
|
23
|
+
*
|
|
24
|
+
* 處理設定相關的 CLI 命令
|
|
25
|
+
*/
|
|
26
|
+
let ConfigController = class ConfigController {
|
|
27
|
+
constructor(getConfigUseCase, setConfigUseCase, output) {
|
|
28
|
+
this.getConfigUseCase = getConfigUseCase;
|
|
29
|
+
this.setConfigUseCase = setConfigUseCase;
|
|
30
|
+
this.output = output;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 列出所有配置
|
|
34
|
+
*/
|
|
35
|
+
async list(_format = 'table') {
|
|
36
|
+
try {
|
|
37
|
+
const configs = await this.getConfigUseCase.getAll();
|
|
38
|
+
this.output
|
|
39
|
+
.newline()
|
|
40
|
+
.section('Current Configurations')
|
|
41
|
+
.divider();
|
|
42
|
+
// 顯示 Log Level
|
|
43
|
+
if (configs.logLevel) {
|
|
44
|
+
this.output
|
|
45
|
+
.newline()
|
|
46
|
+
.item('bullet', `Log Level: ${configs.logLevel}`);
|
|
47
|
+
}
|
|
48
|
+
// 顯示 ACR 憑證(如果有)
|
|
49
|
+
if (configs.defaultAcrCredentials) {
|
|
50
|
+
this.output
|
|
51
|
+
.newline()
|
|
52
|
+
.section('Default ACR Credentials')
|
|
53
|
+
.item('bullet', `Name: ${configs.defaultAcrCredentials.name}`)
|
|
54
|
+
.item('bullet', `Account: ${configs.defaultAcrCredentials.account}`)
|
|
55
|
+
.item('bullet', `Password: ********`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.output
|
|
59
|
+
.newline()
|
|
60
|
+
.item('bullet', 'Default ACR Credentials: (not set)');
|
|
61
|
+
}
|
|
62
|
+
this.output
|
|
63
|
+
.newline()
|
|
64
|
+
.divider()
|
|
65
|
+
.render();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
this.output
|
|
69
|
+
.error(`Failed to list configurations: ${(0, error_formatter_util_1.formatErrorMessage)(error)}`)
|
|
70
|
+
.render();
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 設定配置值
|
|
76
|
+
*/
|
|
77
|
+
async set(options) {
|
|
78
|
+
try {
|
|
79
|
+
// 驗證 log-level
|
|
80
|
+
if (options.logLevel) {
|
|
81
|
+
const validLevels = ['debug', 'info', 'error'];
|
|
82
|
+
if (!validLevels.includes(options.logLevel)) {
|
|
83
|
+
this.output
|
|
84
|
+
.error(`Invalid log level: ${options.logLevel}. Valid values: ${validLevels.join(', ')}`)
|
|
85
|
+
.render();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 處理 ACR credentials
|
|
90
|
+
const acrName = options['acr.name'];
|
|
91
|
+
const acrAccount = options['acr.account'];
|
|
92
|
+
const acrPassword = options['acr.password'];
|
|
93
|
+
// 驗證 ACR credentials
|
|
94
|
+
if ((acrName || acrAccount || acrPassword) && !(acrName && acrAccount && acrPassword)) {
|
|
95
|
+
this.output
|
|
96
|
+
.error('ACR credentials require all three: --acr.name, --acr.account, --acr.password')
|
|
97
|
+
.render();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// 檢查是否有任何配置變更
|
|
101
|
+
const hasChanges = options.logLevel || (acrName && acrAccount && acrPassword);
|
|
102
|
+
if (!hasChanges) {
|
|
103
|
+
this.output
|
|
104
|
+
.info('No configuration changes specified')
|
|
105
|
+
.newline()
|
|
106
|
+
.section('Available Options')
|
|
107
|
+
.item('bullet', '--log-level <level> Set log level (debug, info, error)')
|
|
108
|
+
.item('bullet', '--acr.name <name> Set ACR name')
|
|
109
|
+
.item('bullet', '--acr.account <account> Set ACR account')
|
|
110
|
+
.item('bullet', '--acr.password <pass> Set ACR password')
|
|
111
|
+
.render();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// 使用統一的 execute 方法
|
|
115
|
+
await this.setConfigUseCase.execute({
|
|
116
|
+
logLevel: options.logLevel,
|
|
117
|
+
acrName,
|
|
118
|
+
acrAccount,
|
|
119
|
+
acrPassword,
|
|
120
|
+
});
|
|
121
|
+
if (options.logLevel) {
|
|
122
|
+
this.output.success(`Log level set to "${options.logLevel}"`);
|
|
123
|
+
}
|
|
124
|
+
if (acrName && acrAccount && acrPassword) {
|
|
125
|
+
this.output.success('Default ACR credentials set');
|
|
126
|
+
}
|
|
127
|
+
this.output.render();
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
this.output
|
|
131
|
+
.error(`Failed to set configuration: ${(0, error_formatter_util_1.formatErrorMessage)(error)}`)
|
|
132
|
+
.render();
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
exports.ConfigController = ConfigController;
|
|
138
|
+
exports.ConfigController = ConfigController = __decorate([
|
|
139
|
+
(0, tsyringe_1.injectable)(),
|
|
140
|
+
__param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.GetConfigUseCase)),
|
|
141
|
+
__param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.SetConfigUseCase)),
|
|
142
|
+
__param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.IOutputPort)),
|
|
143
|
+
__metadata("design:paramtypes", [get_config_use_case_1.GetConfigUseCase,
|
|
144
|
+
set_config_use_case_1.SetConfigUseCase, Object])
|
|
145
|
+
], ConfigController);
|
|
146
|
+
//# sourceMappingURL=config.controller.js.map
|