@quonfig/cli 0.0.1

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 (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +707 -0
  3. package/bin/dev.cmd +3 -0
  4. package/bin/dev.js +9 -0
  5. package/bin/run.cmd +3 -0
  6. package/bin/run.js +8 -0
  7. package/dist/api/get-environments.d.ts +10 -0
  8. package/dist/api/get-environments.js +11 -0
  9. package/dist/codegen/code-generators/base-generator.d.ts +11 -0
  10. package/dist/codegen/code-generators/base-generator.js +8 -0
  11. package/dist/codegen/code-generators/base-typescript-generator.d.ts +17 -0
  12. package/dist/codegen/code-generators/base-typescript-generator.js +35 -0
  13. package/dist/codegen/code-generators/node-typescript-generator.d.ts +8 -0
  14. package/dist/codegen/code-generators/node-typescript-generator.js +96 -0
  15. package/dist/codegen/code-generators/react-typescript-generator.d.ts +11 -0
  16. package/dist/codegen/code-generators/react-typescript-generator.js +116 -0
  17. package/dist/codegen/config-downloader.d.ts +7 -0
  18. package/dist/codegen/config-downloader.js +26 -0
  19. package/dist/codegen/json-schema-to-zod.d.ts +3 -0
  20. package/dist/codegen/json-schema-to-zod.js +170 -0
  21. package/dist/codegen/language-mappers/json-to-zod-mapper.d.ts +4 -0
  22. package/dist/codegen/language-mappers/json-to-zod-mapper.js +55 -0
  23. package/dist/codegen/language-mappers/zod-base-mapper.d.ts +35 -0
  24. package/dist/codegen/language-mappers/zod-base-mapper.js +111 -0
  25. package/dist/codegen/language-mappers/zod-to-string-mapper.d.ts +25 -0
  26. package/dist/codegen/language-mappers/zod-to-string-mapper.js +87 -0
  27. package/dist/codegen/language-mappers/zod-to-typescript-mapper.d.ts +35 -0
  28. package/dist/codegen/language-mappers/zod-to-typescript-mapper.js +133 -0
  29. package/dist/codegen/language-mappers/zod-to-typescript-return-value-mapper.d.ts +36 -0
  30. package/dist/codegen/language-mappers/zod-to-typescript-return-value-mapper.js +150 -0
  31. package/dist/codegen/mustache-extractor.d.ts +6 -0
  32. package/dist/codegen/mustache-extractor.js +83 -0
  33. package/dist/codegen/schema-evaluator.d.ts +37 -0
  34. package/dist/codegen/schema-evaluator.js +283 -0
  35. package/dist/codegen/schema-extractor.d.ts +24 -0
  36. package/dist/codegen/schema-extractor.js +265 -0
  37. package/dist/codegen/types.d.ts +44 -0
  38. package/dist/codegen/types.js +5 -0
  39. package/dist/codegen/zod-introspection.d.ts +85 -0
  40. package/dist/codegen/zod-introspection.js +205 -0
  41. package/dist/commands/create.d.ts +19 -0
  42. package/dist/commands/create.js +175 -0
  43. package/dist/commands/download.d.ts +13 -0
  44. package/dist/commands/download.js +63 -0
  45. package/dist/commands/generate-new-hex-key.d.ts +7 -0
  46. package/dist/commands/generate-new-hex-key.js +10 -0
  47. package/dist/commands/generate.d.ts +16 -0
  48. package/dist/commands/generate.js +220 -0
  49. package/dist/commands/get.d.ts +13 -0
  50. package/dist/commands/get.js +141 -0
  51. package/dist/commands/info.d.ts +21 -0
  52. package/dist/commands/info.js +464 -0
  53. package/dist/commands/interactive.d.ts +5 -0
  54. package/dist/commands/interactive.js +8 -0
  55. package/dist/commands/list.d.ts +13 -0
  56. package/dist/commands/list.js +61 -0
  57. package/dist/commands/login.d.ts +10 -0
  58. package/dist/commands/login.js +124 -0
  59. package/dist/commands/logout.d.ts +7 -0
  60. package/dist/commands/logout.js +12 -0
  61. package/dist/commands/mcp.d.ts +13 -0
  62. package/dist/commands/mcp.js +145 -0
  63. package/dist/commands/override.d.ts +17 -0
  64. package/dist/commands/override.js +170 -0
  65. package/dist/commands/profile.d.ts +7 -0
  66. package/dist/commands/profile.js +47 -0
  67. package/dist/commands/schema.d.ts +21 -0
  68. package/dist/commands/schema.js +168 -0
  69. package/dist/commands/serve.d.ts +13 -0
  70. package/dist/commands/serve.js +99 -0
  71. package/dist/commands/set-default.d.ts +20 -0
  72. package/dist/commands/set-default.js +273 -0
  73. package/dist/commands/verify.d.ts +12 -0
  74. package/dist/commands/verify.js +48 -0
  75. package/dist/commands/whoami.d.ts +7 -0
  76. package/dist/commands/whoami.js +52 -0
  77. package/dist/commands/workspace.d.ts +7 -0
  78. package/dist/commands/workspace.js +38 -0
  79. package/dist/constants.d.ts +2 -0
  80. package/dist/constants.js +2 -0
  81. package/dist/help.d.ts +4 -0
  82. package/dist/help.js +10 -0
  83. package/dist/index.d.ts +40 -0
  84. package/dist/index.js +112 -0
  85. package/dist/interactive-prompt.d.ts +2 -0
  86. package/dist/interactive-prompt.js +162 -0
  87. package/dist/quonfig.d.ts +15 -0
  88. package/dist/quonfig.js +75 -0
  89. package/dist/result.d.ts +35 -0
  90. package/dist/result.js +9 -0
  91. package/dist/services/mcp.d.ts +15 -0
  92. package/dist/services/mcp.js +59 -0
  93. package/dist/ui/get-confirmation.d.ts +10 -0
  94. package/dist/ui/get-confirmation.js +4 -0
  95. package/dist/ui/get-environment.d.ts +11 -0
  96. package/dist/ui/get-environment.js +42 -0
  97. package/dist/ui/get-key.d.ts +27 -0
  98. package/dist/ui/get-key.js +15 -0
  99. package/dist/ui/get-string.d.ts +5 -0
  100. package/dist/ui/get-string.js +8 -0
  101. package/dist/ui/get-value.d.ts +18 -0
  102. package/dist/ui/get-value.js +46 -0
  103. package/dist/util/autocomplete.d.ts +6 -0
  104. package/dist/util/autocomplete.js +25 -0
  105. package/dist/util/coerce.d.ts +7 -0
  106. package/dist/util/coerce.js +62 -0
  107. package/dist/util/color.d.ts +3 -0
  108. package/dist/util/color.js +4 -0
  109. package/dist/util/config-value-dto.d.ts +16 -0
  110. package/dist/util/config-value-dto.js +82 -0
  111. package/dist/util/context.d.ts +18 -0
  112. package/dist/util/context.js +10 -0
  113. package/dist/util/domain-urls.d.ts +3 -0
  114. package/dist/util/domain-urls.js +18 -0
  115. package/dist/util/encryption.d.ts +20 -0
  116. package/dist/util/encryption.js +153 -0
  117. package/dist/util/file-manager.d.ts +12 -0
  118. package/dist/util/file-manager.js +16 -0
  119. package/dist/util/get-client.d.ts +7 -0
  120. package/dist/util/get-client.js +127 -0
  121. package/dist/util/is-interactive.d.ts +5 -0
  122. package/dist/util/is-interactive.js +7 -0
  123. package/dist/util/json-maybe.d.ts +3 -0
  124. package/dist/util/json-maybe.js +14 -0
  125. package/dist/util/name-arg.d.ts +4 -0
  126. package/dist/util/name-arg.js +3 -0
  127. package/dist/util/oauth-client.d.ts +30 -0
  128. package/dist/util/oauth-client.js +99 -0
  129. package/dist/util/secret-flags.d.ts +13 -0
  130. package/dist/util/secret-flags.js +13 -0
  131. package/dist/util/token-storage.d.ts +25 -0
  132. package/dist/util/token-storage.js +90 -0
  133. package/dist/validations/value.d.ts +4 -0
  134. package/dist/validations/value.js +11 -0
  135. package/dist/verify/standalone.d.ts +14 -0
  136. package/dist/verify/standalone.js +133 -0
  137. package/dist/verify/validate.d.ts +43 -0
  138. package/dist/verify/validate.js +756 -0
  139. package/dist/version.d.ts +2 -0
  140. package/dist/version.js +2 -0
  141. package/oclif.manifest.json +1429 -0
  142. package/package.json +104 -0
@@ -0,0 +1,220 @@
1
+ import { Flags } from '@oclif/core';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { z } from 'zod';
5
+ import { NodeTypeScriptGenerator } from '../codegen/code-generators/node-typescript-generator.js';
6
+ import { ReactTypeScriptGenerator } from '../codegen/code-generators/react-typescript-generator.js';
7
+ import { ConfigDownloader } from '../codegen/config-downloader.js';
8
+ import { SupportedLanguage } from '../codegen/types.js';
9
+ import { APICommand } from '../index.js';
10
+ import { createFileManager } from '../util/file-manager.js';
11
+ // base types
12
+ const nodeOrReactLanguageSpecificSchema = z.object({
13
+ clientFileName: z.string().optional(),
14
+ declarationFileName: z.string().optional(),
15
+ outputDirectory: z.string().optional(),
16
+ });
17
+ /**
18
+ * Types for parsed config schema
19
+ *
20
+ * {
21
+ * <react|node>: {
22
+ * clientFileName: string;
23
+ * declarationFileName: string;
24
+ * outputDirectory: string;
25
+ * },
26
+ * }
27
+ */
28
+ const requiredNodeOrReactLanguageSpecificSchema = nodeOrReactLanguageSpecificSchema.required();
29
+ const allLanguageEntries = {
30
+ [SupportedLanguage.Node]: requiredNodeOrReactLanguageSpecificSchema,
31
+ [SupportedLanguage.React]: requiredNodeOrReactLanguageSpecificSchema,
32
+ };
33
+ const parsedConfigSchema = z.object(allLanguageEntries);
34
+ /**
35
+ * Types for input config schema
36
+ *
37
+ * {
38
+ * outputDiretory?: string;
39
+ * targets?: {
40
+ * <supported language>?: {
41
+ * outputDirectory: string;
42
+ * outputFileName: string;
43
+ * },
44
+ * },
45
+ * }
46
+ */
47
+ const allTargetsSchema = z.object({
48
+ [SupportedLanguage.Node]: nodeOrReactLanguageSpecificSchema.optional(),
49
+ [SupportedLanguage.React]: nodeOrReactLanguageSpecificSchema.optional(),
50
+ });
51
+ const inputConfigSchema = z.object({
52
+ outputDirectory: z.string().optional(),
53
+ targets: allTargetsSchema.optional(),
54
+ });
55
+ const CONFIG_NAME = 'quonfig.config.json';
56
+ const DEFAULT_CONFIG = {
57
+ outputDirectory: 'generated',
58
+ targets: {
59
+ 'node-ts': {
60
+ clientFileName: 'quonfig-server.ts',
61
+ declarationFileName: 'quonfig-server-types.d.ts',
62
+ },
63
+ 'react-ts': {
64
+ clientFileName: 'quonfig-client.ts',
65
+ declarationFileName: 'quonfig-client-types.d.ts',
66
+ },
67
+ },
68
+ };
69
+ export default class Generate extends APICommand {
70
+ /* eslint-disable no-irregular-whitespace */
71
+ static description = `You can use the default type-generation configuration, or by provide your own via a quonfig.config.json file:
72
+
73
+ Format:
74
+ {
75
+ ​ outputDirectory?: string;
76
+ ​ targets?: {
77
+ ​ <language key>?: {
78
+ ​ outputDirectory?: string;
79
+ ​ outputFileName?: string;
80
+ ​ }
81
+ ​ }
82
+ };
83
+
84
+ Example quonfig.config.json:
85
+ \`\`\`json
86
+ {
87
+ ​ "outputDirectory": "path/to/your/directory",
88
+ ​ "targets": {
89
+ ​ "react-ts": {
90
+ ​ "outputDirectory": "diff/path/to/your/directory",
91
+ ​ "declarationFileName": "quonfig-client-types.d.ts",
92
+ ​ "clientFileName": "quonfig-client.ts",
93
+ ​ },
94
+ ​ "node-ts": {
95
+ ​ "declarationFileName": "quonfig-server-types.d.ts",
96
+ ​ "clientFileName": "quonfig-server.ts",
97
+ ​ }
98
+ ​ }
99
+ }
100
+ \`\`\`
101
+ `;
102
+ /* eslint-enable no-irregular-whitespace */
103
+ static examples = [
104
+ '<%= config.bin %> <%= command.id %> # react-ts only by default',
105
+ '<%= config.bin %> <%= command.id %> --targets node-ts # node-ts only',
106
+ '<%= config.bin %> <%= command.id %> --targets react-ts,node-ts # both node + react-ts',
107
+ '<%= config.bin %> <%= command.id %> -o ./src/generated # specify output directory',
108
+ '<%= config.bin %> <%= command.id %> --targets node-ts -o ./dist # combine with targets',
109
+ ];
110
+ static flags = {
111
+ 'output-directory': Flags.string({
112
+ char: 'o',
113
+ description: 'Override the output directory for generated files',
114
+ }),
115
+ targets: Flags.string({
116
+ default: SupportedLanguage.React,
117
+ description: `Determines for language/framework to generate code for (${Object.values(SupportedLanguage).join(', ')})`,
118
+ }),
119
+ };
120
+ static summary = 'Generate type definitions for your Quonfig configuration';
121
+ async run() {
122
+ const { flags } = await this.parse(Generate);
123
+ this.verboseLog('=== GENERATE COMMAND START ===');
124
+ this.verboseLog(`Base API URL: ${process.env.QUONFIG_API_URL || 'Default'}`);
125
+ try {
126
+ // Look for and read local quonfig.config.json file
127
+ const localConfig = await this.readLocalConfig(flags['output-directory']);
128
+ // Use tarets flag override, otherwise fall back to local config
129
+ const targets = flags.targets.split(',') || Object.keys(localConfig);
130
+ this.verboseLog(`Language(s): ${targets.join(', ')}`);
131
+ // Download the configuration using the APICommand's client
132
+ const downloader = new ConfigDownloader(this);
133
+ this.verboseLog('Downloading config...');
134
+ const configFile = await downloader.downloadConfig();
135
+ this.verboseLog('Config download complete.');
136
+ const fileCreationPromises = [];
137
+ for (const target of targets) {
138
+ // Resolve the language input
139
+ const language = this.resolveLanguage(target);
140
+ // Get language-specific config or fall back to global config
141
+ const targetConfig = localConfig[language];
142
+ const outputDir = targetConfig.outputDirectory;
143
+ this.verboseLog(`Output directory for ${target}: ${outputDir}`);
144
+ this.verboseLog('Resolving generator...');
145
+ const generator = this.resolveGenerator(language, configFile);
146
+ console.log(`Generating ${language} code for configs...`);
147
+ const generatedCode = generator.generate();
148
+ this.verboseLog(`Code generation complete. Size: ${generatedCode.length}`);
149
+ const fileManager = createFileManager({ outputDirectory: outputDir, verboseLog: this.verboseLog.bind(this) });
150
+ fileCreationPromises.push(fileManager.writeFile({ data: generatedCode, filename: targetConfig.clientFileName }));
151
+ if ([SupportedLanguage.Node, SupportedLanguage.React].includes(language)) {
152
+ const declarationGeneratedCode = generator.declarationGenerate();
153
+ this.verboseLog(`Code generation complete. Size: ${declarationGeneratedCode.length}`);
154
+ fileCreationPromises.push(fileManager.writeFile({ data: declarationGeneratedCode, filename: targetConfig.declarationFileName }));
155
+ }
156
+ }
157
+ await Promise.all(fileCreationPromises);
158
+ }
159
+ catch (error) {
160
+ console.error('ERROR:', error);
161
+ this.error(error);
162
+ }
163
+ this.verboseLog('=== GENERATE COMMAND END ===');
164
+ return { success: true };
165
+ }
166
+ generateParsedConfig(jsonConfig = {}, outputDirectoryOverride) {
167
+ const parsedConfig = inputConfigSchema.parse(jsonConfig);
168
+ return Object.values(SupportedLanguage).reduce((agg, language) => {
169
+ const parsedLanguageConfig = parsedConfig.targets?.[language] || {};
170
+ const languageConfig = {
171
+ clientFileName: parsedLanguageConfig.clientFileName || DEFAULT_CONFIG.targets[language].clientFileName,
172
+ declarationFileName: parsedLanguageConfig.declarationFileName || DEFAULT_CONFIG.targets[language].declarationFileName,
173
+ outputDirectory: outputDirectoryOverride ||
174
+ parsedLanguageConfig.outputDirectory ||
175
+ parsedConfig.outputDirectory ||
176
+ DEFAULT_CONFIG.outputDirectory,
177
+ };
178
+ agg[language] = languageConfig;
179
+ return agg;
180
+ }, {});
181
+ }
182
+ async readLocalConfig(outputDirectoryOverride) {
183
+ const configPath = path.join(process.cwd(), CONFIG_NAME);
184
+ try {
185
+ // Check if file exists
186
+ await fs.promises.access(configPath, fs.constants.F_OK);
187
+ this.verboseLog(`Found local ${CONFIG_NAME}`);
188
+ // Read and parse the file
189
+ const configContent = await fs.promises.readFile(configPath, 'utf8');
190
+ const parsedConfig = JSON.parse(configContent);
191
+ this.verboseLog(`Local config loaded from ${CONFIG_NAME}: ${JSON.stringify(parsedConfig, null, 2)}`);
192
+ return this.generateParsedConfig(parsedConfig, outputDirectoryOverride);
193
+ }
194
+ catch (error) {
195
+ // File doesn't exist or can't be read/parsed
196
+ if (error.code === 'ENOENT') {
197
+ this.verboseLog(`No ${CONFIG_NAME} file found in current directory.`);
198
+ }
199
+ else {
200
+ this.error(`Error reading ${CONFIG_NAME}: ${error}`);
201
+ }
202
+ return this.generateParsedConfig({}, outputDirectoryOverride);
203
+ }
204
+ }
205
+ resolveGenerator(language, configFile) {
206
+ switch (language) {
207
+ case SupportedLanguage.Node:
208
+ return new NodeTypeScriptGenerator({ configFile, log: this.verboseLog });
209
+ case SupportedLanguage.React:
210
+ return new ReactTypeScriptGenerator({ configFile, log: this.verboseLog });
211
+ }
212
+ }
213
+ resolveLanguage(languageTarget) {
214
+ const target = languageTarget?.toLowerCase();
215
+ if (!target || !Object.values(SupportedLanguage).includes(target)) {
216
+ throw new Error(`Unsupported target: ${languageTarget}`);
217
+ }
218
+ return target;
219
+ }
220
+ }
@@ -0,0 +1,13 @@
1
+ import { APICommand } from '../index.js';
2
+ import { JsonObj } from '../result.js';
3
+ export default class Get extends APICommand {
4
+ static args: {
5
+ name: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
6
+ };
7
+ static description: string;
8
+ static examples: string[];
9
+ static flags: {
10
+ environment: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
+ };
12
+ run(): Promise<JsonObj | void>;
13
+ }
@@ -0,0 +1,141 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { APICommand } from '../index.js';
3
+ import autocomplete from '../util/autocomplete.js';
4
+ import getEnvironment from '../ui/get-environment.js';
5
+ import isInteractive from '../util/is-interactive.js';
6
+ import nameArg from '../util/name-arg.js';
7
+ import { decrypt } from '../util/encryption.js';
8
+ export default class Get extends APICommand {
9
+ static args = { ...nameArg };
10
+ static description = 'Get the value of a config/feature-flag/etc.';
11
+ static examples = [
12
+ '<%= config.bin %> <%= command.id %> my.config.name',
13
+ '<%= config.bin %> <%= command.id %> my.config.name --environment=production',
14
+ ];
15
+ static flags = {
16
+ environment: Flags.string({ description: 'environment to evaluate in' }),
17
+ };
18
+ async run() {
19
+ const { args, flags } = await this.parse(Get);
20
+ // Fetch metadata first for validation and autocomplete
21
+ const metadataRequest = await this.apiClient.post('/api/v1/metadata/list', { workspaceId: this.workspaceId });
22
+ if (!metadataRequest.ok) {
23
+ const errorMsg = metadataRequest.error?.error || `Failed to fetch configs: ${metadataRequest.status}`;
24
+ return this.err(errorMsg, { serverError: metadataRequest.error });
25
+ }
26
+ const metadataResponse = metadataRequest.json;
27
+ const configKeys = metadataResponse.configs.map((c) => c.key);
28
+ // Get the key with autocomplete
29
+ let key = args.name;
30
+ if (!key && isInteractive(flags)) {
31
+ const selectedKey = await autocomplete({
32
+ message: 'Config key',
33
+ source: configKeys,
34
+ });
35
+ if (selectedKey) {
36
+ key = selectedKey;
37
+ }
38
+ }
39
+ if (!key) {
40
+ return this.err('Key is required');
41
+ }
42
+ // Validate key exists
43
+ const configExists = metadataResponse.configs.some((config) => config.key === key);
44
+ if (!configExists) {
45
+ return this.err(`${key} does not exist`);
46
+ }
47
+ // Get the environment
48
+ const environment = await getEnvironment({
49
+ command: this,
50
+ flags,
51
+ message: 'Which environment would you like to evaluate in?',
52
+ providedEnvironment: flags.environment,
53
+ });
54
+ if (!environment) {
55
+ return;
56
+ }
57
+ const request = await this.apiClient.post('/api/v1/evaluations/evaluate', {
58
+ workspaceId: this.workspaceId,
59
+ environmentId: environment.id,
60
+ context: {},
61
+ });
62
+ if (!request.ok) {
63
+ const errorMsg = request.error?.error || `Failed to get config: ${request.status}`;
64
+ return this.err(errorMsg, { serverError: request.error });
65
+ }
66
+ // oRPC returns EvaluationResult[] — find the matching key
67
+ const results = (Array.isArray(request.json) ? request.json : []);
68
+ const result = results.find((r) => r.key === key);
69
+ if (!result) {
70
+ return this.err(`${key} could not be evaluated in this environment`);
71
+ }
72
+ // Adapt to the legacy response shape for downstream compatibility
73
+ const config = {
74
+ key: result.key,
75
+ type: result.configType,
76
+ value: result.displayValue,
77
+ metadata: {
78
+ conditionalValueIndex: 0,
79
+ configRowIndex: 0,
80
+ id: 0,
81
+ type: result.configType,
82
+ valueType: result.valueType,
83
+ },
84
+ };
85
+ let value = config.value;
86
+ // Check if this config has dependencies
87
+ if (config.dependencies && config.dependencies.length > 0) {
88
+ // Check for providedBy dependency (config value from env var)
89
+ const providedByDep = config.dependencies.find((dep) => dep.dependencyType === 'providedBy');
90
+ if (providedByDep) {
91
+ const envVarName = providedByDep.source;
92
+ this.log(`This config is provided by env var '${envVarName}'`);
93
+ // Check if the env var is present
94
+ const envValue = process.env[envVarName];
95
+ if (!envValue) {
96
+ return this.err(`Environment variable '${envVarName}' is not set. Cannot resolve config '${key}'.`, {
97
+ [key]: value,
98
+ provided: true,
99
+ missingEnvVar: envVarName,
100
+ });
101
+ }
102
+ value = envValue;
103
+ this.log(`Successfully resolved config '${key}' from env var`);
104
+ }
105
+ // Check for decryptWith dependency (encrypted config)
106
+ const decryptWithDep = config.dependencies.find((dep) => dep.dependencyType === 'decryptWith');
107
+ if (decryptWithDep && decryptWithDep.config) {
108
+ const encryptionKeyConfig = decryptWithDep.config;
109
+ // Find the providedBy dependency to get the env var name for the encryption key
110
+ const keyProvidedByDep = encryptionKeyConfig.dependencies?.find((dep) => dep.dependencyType === 'providedBy');
111
+ if (keyProvidedByDep) {
112
+ const envVarName = keyProvidedByDep.source;
113
+ this.log(`This config is encrypted by key '${encryptionKeyConfig.key}' that should be found in env var '${envVarName}'`);
114
+ // Check if the env var is present
115
+ const encryptionKey = process.env[envVarName];
116
+ if (!encryptionKey) {
117
+ return this.err(`Environment variable '${envVarName}' is not set. Cannot decrypt config '${key}'.`, {
118
+ [key]: value,
119
+ encrypted: true,
120
+ missingEnvVar: envVarName,
121
+ });
122
+ }
123
+ // Attempt decryption
124
+ try {
125
+ value = decrypt(value, encryptionKey);
126
+ this.log(`Successfully decrypted config '${key}'`);
127
+ }
128
+ catch (error) {
129
+ const errorMessage = error instanceof Error ? error.message : String(error);
130
+ return this.err(`Failed to decrypt config '${key}': ${errorMessage}`, {
131
+ [key]: value,
132
+ encrypted: true,
133
+ error: errorMessage,
134
+ });
135
+ }
136
+ }
137
+ }
138
+ }
139
+ return this.ok(this.toSuccessJson(value), { [key]: value });
140
+ }
141
+ }
@@ -0,0 +1,21 @@
1
+ import { APICommand } from '../index.js';
2
+ import { JsonObj } from '../result.js';
3
+ export default class Info extends APICommand {
4
+ static args: {
5
+ name: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
6
+ };
7
+ static description: string;
8
+ static examples: string[];
9
+ static flags: {
10
+ 'exclude-evaluations': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<JsonObj | void>;
13
+ private displayEvaluationStats;
14
+ private extractSimpleValue;
15
+ private fetchEvaluationStats;
16
+ private formatValue;
17
+ private hasNonTrivialCriteria;
18
+ private parseConfig;
19
+ private transformEvaluationStatsForJson;
20
+ private transformValueForJson;
21
+ }