@achs/env 3.1.0 → 3.1.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.
- package/arguments.d.ts +25 -0
- package/arguments.d.ts.map +1 -0
- package/{src/arguments.ts → arguments.js} +8 -32
- package/arguments.js.map +1 -0
- package/commands/env.command.d.ts +8 -0
- package/commands/env.command.d.ts.map +1 -0
- package/commands/env.command.js +85 -0
- package/commands/env.command.js.map +1 -0
- package/commands/export.command.d.ts +8 -0
- package/commands/export.command.d.ts.map +1 -0
- package/commands/export.command.js +54 -0
- package/commands/export.command.js.map +1 -0
- package/{src/commands/index.ts → commands/index.d.ts} +1 -0
- package/commands/index.d.ts.map +1 -0
- package/commands/index.js +14 -0
- package/commands/index.js.map +1 -0
- package/commands/pull.command.d.ts +7 -0
- package/commands/pull.command.d.ts.map +1 -0
- package/commands/pull.command.js +39 -0
- package/commands/pull.command.js.map +1 -0
- package/commands/push.command.d.ts +7 -0
- package/commands/push.command.d.ts.map +1 -0
- package/commands/push.command.js +38 -0
- package/commands/push.command.js.map +1 -0
- package/commands/schema.command.d.ts +4 -0
- package/commands/schema.command.d.ts.map +1 -0
- package/commands/schema.command.js +18 -0
- package/commands/schema.command.js.map +1 -0
- package/exec.d.ts +3 -0
- package/exec.d.ts.map +1 -0
- package/exec.js +142 -0
- package/exec.js.map +1 -0
- package/{src/index.ts → index.d.ts} +1 -0
- package/index.d.ts.map +1 -0
- package/index.js +20 -0
- package/index.js.map +1 -0
- package/{src/interfaces/index.ts → interfaces/index.d.ts} +1 -0
- package/interfaces/index.d.ts.map +1 -0
- package/interfaces/index.js +18 -0
- package/interfaces/index.js.map +1 -0
- package/interfaces/loader.interface.d.ts +21 -0
- package/interfaces/loader.interface.d.ts.map +1 -0
- package/interfaces/loader.interface.js +3 -0
- package/interfaces/loader.interface.js.map +1 -0
- package/main.d.ts +3 -0
- package/main.d.ts.map +1 -0
- package/main.js +6 -0
- package/main.js.map +1 -0
- package/package.json +1 -1
- package/providers/app-settings.provider.d.ts +8 -0
- package/providers/app-settings.provider.d.ts.map +1 -0
- package/providers/app-settings.provider.js +50 -0
- package/providers/app-settings.provider.js.map +1 -0
- package/providers/azure-key-vault.provider.d.ts +20 -0
- package/providers/azure-key-vault.provider.d.ts.map +1 -0
- package/providers/azure-key-vault.provider.js +143 -0
- package/providers/azure-key-vault.provider.js.map +1 -0
- package/providers/index.d.ts +7 -0
- package/providers/index.d.ts.map +1 -0
- package/providers/index.js +30 -0
- package/providers/index.js.map +1 -0
- package/providers/local.provider.d.ts +8 -0
- package/providers/local.provider.d.ts.map +1 -0
- package/providers/local.provider.js +31 -0
- package/providers/local.provider.js.map +1 -0
- package/providers/package-json.provider.d.ts +8 -0
- package/providers/package-json.provider.d.ts.map +1 -0
- package/providers/package-json.provider.js +29 -0
- package/providers/package-json.provider.js.map +1 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/utils/command.util.d.ts +13 -0
- package/utils/command.util.d.ts.map +1 -0
- package/utils/command.util.js +134 -0
- package/utils/command.util.js.map +1 -0
- package/{src/utils/index.ts → utils/index.d.ts} +1 -0
- package/utils/index.d.ts.map +1 -0
- package/utils/index.js +23 -0
- package/utils/index.js.map +1 -0
- package/utils/interpolate.util.d.ts +4 -0
- package/utils/interpolate.util.d.ts.map +1 -0
- package/utils/interpolate.util.js +33 -0
- package/utils/interpolate.util.js.map +1 -0
- package/utils/json.util.d.ts +5 -0
- package/utils/json.util.d.ts.map +1 -0
- package/utils/json.util.js +48 -0
- package/utils/json.util.js.map +1 -0
- package/utils/logger.d.ts +3 -0
- package/utils/logger.d.ts.map +1 -0
- package/{src/utils/logger.ts → utils/logger.js} +6 -6
- package/utils/logger.js.map +1 -0
- package/utils/normalize.util.d.ts +3 -0
- package/utils/normalize.util.d.ts.map +1 -0
- package/utils/normalize.util.js +61 -0
- package/utils/normalize.util.js.map +1 -0
- package/utils/schema.util.d.ts +11 -0
- package/utils/schema.util.d.ts.map +1 -0
- package/utils/schema.util.js +100 -0
- package/utils/schema.util.js.map +1 -0
- package/.eslintignore +0 -3
- package/.eslintrc.json +0 -329
- package/.vscode/extensions.json +0 -18
- package/.vscode/launch.json +0 -30
- package/.vscode/settings.json +0 -29
- package/jest.config.json +0 -28
- package/src/commands/env.command.ts +0 -139
- package/src/commands/export.command.ts +0 -88
- package/src/commands/pull.command.ts +0 -52
- package/src/commands/push.command.ts +0 -48
- package/src/commands/schema.command.ts +0 -31
- package/src/exec.ts +0 -221
- package/src/interfaces/loader.interface.ts +0 -66
- package/src/main.ts +0 -6
- package/src/providers/app-settings.provider.ts +0 -67
- package/src/providers/azure-key-vault.provider.ts +0 -277
- package/src/providers/index.ts +0 -29
- package/src/providers/local.provider.ts +0 -44
- package/src/providers/package-json.provider.ts +0 -39
- package/src/utils/command.util.ts +0 -223
- package/src/utils/interpolate.util.ts +0 -65
- package/src/utils/json.util.ts +0 -116
- package/src/utils/normalize.util.ts +0 -142
- package/src/utils/schema.util.ts +0 -191
- package/tests/env/appsettings.json +0 -32
- package/tests/env/dev.env.json +0 -12
- package/tests/env/dev.local.env.json +0 -9
- package/tests/env/env.schema.json +0 -225
- package/tests/env/keys.json +0 -7
- package/tests/env/settings/schema.json +0 -239
- package/tests/env/settings/settings.json +0 -22
- package/tests/env.int.test.ts +0 -42
- package/tests/exec.ts +0 -19
- package/tests/export.int.test.ts +0 -9
- package/tests/pull-push.int.test.ts +0 -15
- package/tests/run.js +0 -32
- package/tests/schema.int.test.ts +0 -9
- package/tests/setup.ts +0 -13
- package/tsconfig.build.json +0 -10
- package/tsconfig.json +0 -37
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { CommandArguments } from '../arguments';
|
|
3
|
-
import { EnvProvider } from '../interfaces';
|
|
4
|
-
import { logger as globalLogger, readJson, writeJson } from '../utils';
|
|
5
|
-
|
|
6
|
-
const KEY = 'app-settings';
|
|
7
|
-
|
|
8
|
-
const logger = globalLogger.getChildLogger({
|
|
9
|
-
prefix: [chalk.bold.blue(`[${KEY}]`)]
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const APP_SETTINGS_DEFAULT = {
|
|
13
|
-
'|DEFAULT|': {},
|
|
14
|
-
'|MODE|': {},
|
|
15
|
-
'|ENV|': {},
|
|
16
|
-
'|LOCAL|': {}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
interface AppSettingsCommandArguments extends CommandArguments {
|
|
20
|
-
envFile: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Loads config from appsettings.json.
|
|
25
|
-
*/
|
|
26
|
-
export const AppSettingsProvider: EnvProvider<AppSettingsCommandArguments> = {
|
|
27
|
-
key: KEY,
|
|
28
|
-
|
|
29
|
-
builder: (builder) => {
|
|
30
|
-
builder.options({
|
|
31
|
-
envFile: {
|
|
32
|
-
group: KEY,
|
|
33
|
-
alias: 'ef',
|
|
34
|
-
type: 'string',
|
|
35
|
-
default: '[[root]]/appsettings.json',
|
|
36
|
-
describe: 'Environment variables file path (non secrets)'
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
load: async ({ env, modes = [], envFile, local }) => {
|
|
42
|
-
const [appsettings = APP_SETTINGS_DEFAULT, wasFound] = await readJson(
|
|
43
|
-
envFile
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
if (!wasFound) {
|
|
47
|
-
logger.warn(`${chalk.blue(envFile)} not found`);
|
|
48
|
-
|
|
49
|
-
logger.debug(`creating default ${chalk.blue(envFile)} file`);
|
|
50
|
-
|
|
51
|
-
await writeJson(envFile, APP_SETTINGS_DEFAULT);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// only load local in env load cmd
|
|
55
|
-
if (!local) appsettings['|LOCAL|'] = null;
|
|
56
|
-
|
|
57
|
-
return [
|
|
58
|
-
appsettings['|DEFAULT|'],
|
|
59
|
-
|
|
60
|
-
appsettings['|ENV|']?.[env],
|
|
61
|
-
|
|
62
|
-
...modes.map((mode) => appsettings['|MODE|']?.[mode]),
|
|
63
|
-
|
|
64
|
-
appsettings['|LOCAL|']?.[env]
|
|
65
|
-
];
|
|
66
|
-
}
|
|
67
|
-
};
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import {
|
|
3
|
-
AzureKeyVault,
|
|
4
|
-
AzureKeyVaultSecrets,
|
|
5
|
-
createAzureKeyVaultMock
|
|
6
|
-
} from '@achs/azure-key-vault';
|
|
7
|
-
import { CommandArguments } from '../arguments';
|
|
8
|
-
import { EnvProvider } from '../interfaces';
|
|
9
|
-
import {
|
|
10
|
-
generateSchemaFrom,
|
|
11
|
-
logger as globalLogger,
|
|
12
|
-
readJson,
|
|
13
|
-
schemaToJson,
|
|
14
|
-
writeJson
|
|
15
|
-
} from '../utils';
|
|
16
|
-
import { Arguments } from 'yargs';
|
|
17
|
-
import { existsSync } from 'fs';
|
|
18
|
-
import { PullCommandArguments } from 'commands/pull.command';
|
|
19
|
-
|
|
20
|
-
const KEY = 'azure-key-vault';
|
|
21
|
-
|
|
22
|
-
const logger = globalLogger.getChildLogger({
|
|
23
|
-
prefix: [chalk.bold.blue(`[${KEY}]`)]
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
interface AzureKeyVaultCommandArguments extends CommandArguments {
|
|
27
|
-
secretsFile: string;
|
|
28
|
-
keysFile?: string[];
|
|
29
|
-
vaultUrl: string;
|
|
30
|
-
spn: string;
|
|
31
|
-
password: string;
|
|
32
|
-
tenant: string;
|
|
33
|
-
mock: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface AzureKeyVaultCommandConfig {
|
|
37
|
-
[key: string]: {
|
|
38
|
-
vaultUrl: string;
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Loads secrets from env files in env/secrets
|
|
44
|
-
* folder, loaded from Azure Key Vault.
|
|
45
|
-
*/
|
|
46
|
-
export const AzureKeyVaultProvider: EnvProvider<
|
|
47
|
-
AzureKeyVaultCommandArguments & PullCommandArguments,
|
|
48
|
-
AzureKeyVaultCommandConfig
|
|
49
|
-
> = {
|
|
50
|
-
key: KEY,
|
|
51
|
-
|
|
52
|
-
builder: (builder) => {
|
|
53
|
-
builder.options({
|
|
54
|
-
secretsFile: {
|
|
55
|
-
group: KEY,
|
|
56
|
-
type: 'string',
|
|
57
|
-
default: '[[root]]/[[env]].env.json',
|
|
58
|
-
describe: 'Secret variables file path'
|
|
59
|
-
},
|
|
60
|
-
keysFile: {
|
|
61
|
-
group: KEY,
|
|
62
|
-
alias: ['k', 'keys'],
|
|
63
|
-
type: 'array',
|
|
64
|
-
default: ['[[root]]/keys.json', '../keys.json'],
|
|
65
|
-
describe: 'Azure Key Vault keys file path'
|
|
66
|
-
},
|
|
67
|
-
vaultUrl: {
|
|
68
|
-
group: KEY,
|
|
69
|
-
alias: 'url',
|
|
70
|
-
type: 'string',
|
|
71
|
-
describe: 'Azure Key Vault URL'
|
|
72
|
-
},
|
|
73
|
-
spn: {
|
|
74
|
-
group: KEY,
|
|
75
|
-
alias: ['clientId', 'id'],
|
|
76
|
-
type: 'string',
|
|
77
|
-
describe: 'SPN Client ID'
|
|
78
|
-
},
|
|
79
|
-
password: {
|
|
80
|
-
group: KEY,
|
|
81
|
-
alias: ['p', 'pass', 'clientSecret'],
|
|
82
|
-
type: 'string',
|
|
83
|
-
describe: 'SPN Client Secret Password'
|
|
84
|
-
},
|
|
85
|
-
tenant: {
|
|
86
|
-
group: KEY,
|
|
87
|
-
alias: 't',
|
|
88
|
-
type: 'string',
|
|
89
|
-
describe: 'Azure Tenant ID'
|
|
90
|
-
},
|
|
91
|
-
mock: {
|
|
92
|
-
group: KEY,
|
|
93
|
-
type: 'boolean',
|
|
94
|
-
default: false,
|
|
95
|
-
describe: 'Mocks Azure Key Vault client'
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
push: async (argv, config) => {
|
|
101
|
-
const [secrets, secretsWasFound] = await readJson(argv.secretsFile);
|
|
102
|
-
|
|
103
|
-
if (!secretsWasFound) {
|
|
104
|
-
logger.error(`${chalk.blue(argv.secretFile)} not found`);
|
|
105
|
-
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
logger.silly('local secrets loaded:', secrets);
|
|
110
|
-
const akv = await loadAzureKeyVaultClient(
|
|
111
|
-
argv,
|
|
112
|
-
config?.[argv.env]?.vaultUrl
|
|
113
|
-
);
|
|
114
|
-
logger.info('pushing variables to store');
|
|
115
|
-
const results = await akv.setAll(secrets);
|
|
116
|
-
logger.silly('secrets pushed:', results);
|
|
117
|
-
|
|
118
|
-
const schema = await generateSchemaFrom(
|
|
119
|
-
[{ key: KEY, value: secrets }],
|
|
120
|
-
argv
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
logger.silly('schema for akv updated:', schema);
|
|
124
|
-
},
|
|
125
|
-
|
|
126
|
-
pull: async (argv, config) => {
|
|
127
|
-
const schema = argv.schema?.[KEY] as
|
|
128
|
-
| Record<string, unknown>
|
|
129
|
-
| undefined;
|
|
130
|
-
|
|
131
|
-
if (!schema) {
|
|
132
|
-
logger.error('no schema found');
|
|
133
|
-
|
|
134
|
-
process.exit(1);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const jsonTemplate = schemaToJson(schema) as Record<string, unknown>;
|
|
138
|
-
|
|
139
|
-
const akv = await loadAzureKeyVaultClient(
|
|
140
|
-
argv,
|
|
141
|
-
config?.[argv.env]?.vaultUrl
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
logger.info('pulling variables from store');
|
|
145
|
-
|
|
146
|
-
const secrets = await akv.getFor(
|
|
147
|
-
jsonTemplate as AzureKeyVaultSecrets,
|
|
148
|
-
true
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
logger.silly('remote secrets loaded:', secrets);
|
|
152
|
-
|
|
153
|
-
await writeJson(argv.secretsFile, secrets, argv.overwrite, true);
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
load: async (argv, config) => {
|
|
157
|
-
const { secretsFile } = argv;
|
|
158
|
-
|
|
159
|
-
if (!existsSync(secretsFile)) {
|
|
160
|
-
logger.warn('secrets file not found, pulling from store');
|
|
161
|
-
|
|
162
|
-
await AzureKeyVaultProvider.pull!(argv, config);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const [secrets] = await readJson(secretsFile);
|
|
166
|
-
|
|
167
|
-
return [secrets];
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Validate SPN credentials/keys.
|
|
173
|
-
*
|
|
174
|
-
* @param {(Record<string, any> | null)} keys
|
|
175
|
-
*
|
|
176
|
-
* @returns {boolean}
|
|
177
|
-
*/
|
|
178
|
-
function keysAreValid(keys: Record<string, any> | null): boolean {
|
|
179
|
-
return keys && keys.clientId && keys.clientSecret && keys.tenantId;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Loads SPN Azure Key Vault credentials from keys file.
|
|
184
|
-
*
|
|
185
|
-
* @param {string} env
|
|
186
|
-
* @param {string[]} paths
|
|
187
|
-
*
|
|
188
|
-
* @returns {Record<string, string>} credentials
|
|
189
|
-
*/
|
|
190
|
-
async function loadKeysFile(
|
|
191
|
-
env: string,
|
|
192
|
-
paths: string[]
|
|
193
|
-
): Promise<Record<string, string>> {
|
|
194
|
-
logger.debug(`searching keys at ${chalk.yellow(paths.join(','))}`);
|
|
195
|
-
|
|
196
|
-
const readers = await Promise.all(paths.map((path) => readJson(path)));
|
|
197
|
-
|
|
198
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
199
|
-
const [keys, wasFound] = readers.find(
|
|
200
|
-
([keys, wasFound]) => wasFound && keysAreValid(keys[env])
|
|
201
|
-
) ?? [null, false];
|
|
202
|
-
|
|
203
|
-
// if (!wasFound || !keys) {
|
|
204
|
-
// logger.error(`no credentials found for ${chalk.green.underline(env)}`);
|
|
205
|
-
// logger.warn(
|
|
206
|
-
// 'if you use Azure CLI, set "keysFile": null in your env.config file'
|
|
207
|
-
// );
|
|
208
|
-
|
|
209
|
-
// process.exit(1);
|
|
210
|
-
// }
|
|
211
|
-
|
|
212
|
-
return keys?.[env] ?? {};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Loads credentials and initializes Azure Key Vault client.
|
|
217
|
-
*
|
|
218
|
-
* @param {Arguments<AzureKeyVaultCommandArguments>} argv command arguments
|
|
219
|
-
*
|
|
220
|
-
* @returns {*} {Promise<AzureKeyVault>}
|
|
221
|
-
*/
|
|
222
|
-
async function loadAzureKeyVaultClient(
|
|
223
|
-
{
|
|
224
|
-
env,
|
|
225
|
-
vaultUrl,
|
|
226
|
-
spn,
|
|
227
|
-
password,
|
|
228
|
-
tenant,
|
|
229
|
-
app,
|
|
230
|
-
keysFile,
|
|
231
|
-
mock
|
|
232
|
-
}: Arguments<AzureKeyVaultCommandArguments>,
|
|
233
|
-
configVaultUrl?: string
|
|
234
|
-
): Promise<AzureKeyVault> {
|
|
235
|
-
let url = process.env.AZURE_VAULT_URL ?? vaultUrl ?? configVaultUrl;
|
|
236
|
-
|
|
237
|
-
const config = {
|
|
238
|
-
project: process.env.AZURE_PROJECT ?? (app?.project as string),
|
|
239
|
-
group: process.env.AZURE_GROUP ?? (app?.name as string),
|
|
240
|
-
env
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
if (!config.project) {
|
|
244
|
-
logger.error(
|
|
245
|
-
`no project info from ${chalk.blue('package.json')} found`
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
process.exit(1);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const credentials = {
|
|
252
|
-
clientId: process.env.AZURE_CLIENT_ID ?? spn,
|
|
253
|
-
clientSecret: process.env.AZURE_CLIENT_SECRET ?? password,
|
|
254
|
-
tenantId: process.env.AZURE_TENANT_ID ?? tenant
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
if (keysFile && keysFile.length > 0 && !keysAreValid(credentials)) {
|
|
258
|
-
const keys = await loadKeysFile(env, keysFile);
|
|
259
|
-
|
|
260
|
-
url ??= keys.vaultUrl;
|
|
261
|
-
credentials.clientId ??= keys.clientId;
|
|
262
|
-
credentials.clientSecret ??= keys.clientSecret;
|
|
263
|
-
credentials.tenantId ??= keys.tenantId;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
logger.debug(
|
|
267
|
-
`credentials loaded for project ${chalk.bold.underline.yellowBright(
|
|
268
|
-
config.project
|
|
269
|
-
)} and group ${chalk.bold.underline.yellowBright(config.group)}`
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
logger.debug(`connected to ${chalk.bold.underline.greenBright(url)}`);
|
|
273
|
-
|
|
274
|
-
return mock
|
|
275
|
-
? createAzureKeyVaultMock(config)
|
|
276
|
-
: new AzureKeyVault(url, config, credentials);
|
|
277
|
-
}
|
package/src/providers/index.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { EnvProvider } from '../interfaces';
|
|
2
|
-
import { AppSettingsProvider } from './app-settings.provider';
|
|
3
|
-
import { PackageJsonProvider } from './package-json.provider';
|
|
4
|
-
import { AzureKeyVaultProvider } from './azure-key-vault.provider';
|
|
5
|
-
import { LocalProvider } from './local.provider';
|
|
6
|
-
|
|
7
|
-
const IntegratedProviders: Record<string, EnvProvider<any, any>> = {
|
|
8
|
-
[PackageJsonProvider.key]: PackageJsonProvider,
|
|
9
|
-
[AppSettingsProvider.key]: AppSettingsProvider,
|
|
10
|
-
[AzureKeyVaultProvider.key]: AzureKeyVaultProvider,
|
|
11
|
-
[LocalProvider.key]: LocalProvider
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const IntegratedProviderConfig = [
|
|
15
|
-
{
|
|
16
|
-
path: PackageJsonProvider.key
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
path: AppSettingsProvider.key
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
path: AzureKeyVaultProvider.key
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
path: LocalProvider.key
|
|
26
|
-
}
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
export { IntegratedProviders, IntegratedProviderConfig };
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'fs';
|
|
2
|
-
import { CommandArguments } from '../arguments';
|
|
3
|
-
import { EnvProvider } from '../interfaces';
|
|
4
|
-
import { readJson, writeJson } from '../utils';
|
|
5
|
-
|
|
6
|
-
const KEY = 'local';
|
|
7
|
-
|
|
8
|
-
interface LocalCommandArguments extends CommandArguments {
|
|
9
|
-
localFile: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Loads local variables from env files in env folder.
|
|
14
|
-
*/
|
|
15
|
-
export const LocalProvider: EnvProvider<LocalCommandArguments> = {
|
|
16
|
-
key: KEY,
|
|
17
|
-
|
|
18
|
-
builder: (builder) => {
|
|
19
|
-
builder.options({
|
|
20
|
-
localFile: {
|
|
21
|
-
group: KEY,
|
|
22
|
-
alias: 'lf',
|
|
23
|
-
type: 'string',
|
|
24
|
-
default: '[[root]]/[[env]].local.env.json',
|
|
25
|
-
describe: 'Local secret variables file path'
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
load: async ({ localFile, ci }) => {
|
|
31
|
-
// ci mode doesn't load local vars
|
|
32
|
-
if (ci) return [];
|
|
33
|
-
|
|
34
|
-
if (!existsSync(localFile)) {
|
|
35
|
-
await writeJson(localFile, {});
|
|
36
|
-
|
|
37
|
-
return [];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const [vars] = await readJson(localFile);
|
|
41
|
-
|
|
42
|
-
return [vars];
|
|
43
|
-
}
|
|
44
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { CommandArguments } from '../arguments';
|
|
2
|
-
import { EnvProvider } from '../interfaces';
|
|
3
|
-
|
|
4
|
-
const KEY = 'package-json';
|
|
5
|
-
|
|
6
|
-
interface PackageJsonCommandArguments extends CommandArguments {
|
|
7
|
-
varPrefix: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Loads project info from package.json.
|
|
12
|
-
*/
|
|
13
|
-
export const PackageJsonProvider: EnvProvider<PackageJsonCommandArguments> = {
|
|
14
|
-
key: KEY,
|
|
15
|
-
|
|
16
|
-
builder: (builder) => {
|
|
17
|
-
builder.options({
|
|
18
|
-
varPrefix: {
|
|
19
|
-
group: KEY,
|
|
20
|
-
alias: 'vp',
|
|
21
|
-
type: 'string',
|
|
22
|
-
default: '',
|
|
23
|
-
describe: 'Prefix for loaded variables'
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
load: ({ env, app, varPrefix }) => {
|
|
29
|
-
return {
|
|
30
|
-
[`${varPrefix}ENV`]: env,
|
|
31
|
-
|
|
32
|
-
[`${varPrefix}VERSION`]: app?.version,
|
|
33
|
-
[`${varPrefix}PROJECT`]: app?.project,
|
|
34
|
-
[`${varPrefix}NAME`]: app?.name,
|
|
35
|
-
[`${varPrefix}TITLE`]: app?.title,
|
|
36
|
-
[`${varPrefix}DESCRIPTION`]: app?.description
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
};
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import merge from 'merge-deep';
|
|
3
|
-
import { Arguments } from 'yargs';
|
|
4
|
-
import { CommandArguments } from 'arguments';
|
|
5
|
-
import { EnvCommandArguments } from 'commands/env.command';
|
|
6
|
-
import { EnvProviderConfig, EnvProviderResult } from '../interfaces';
|
|
7
|
-
import {
|
|
8
|
-
createValidators,
|
|
9
|
-
interpolate,
|
|
10
|
-
logger,
|
|
11
|
-
readJson,
|
|
12
|
-
schemaFrom,
|
|
13
|
-
writeJson
|
|
14
|
-
} from '../utils';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Injects config to command arguments from file.
|
|
18
|
-
*
|
|
19
|
-
* @param {Record<string, unknown>} argv
|
|
20
|
-
* @param {[string, string]} delimiters
|
|
21
|
-
*/
|
|
22
|
-
export async function loadConfigFile(
|
|
23
|
-
argv: Record<string, unknown>,
|
|
24
|
-
delimiters: [string, string]
|
|
25
|
-
): Promise<void> {
|
|
26
|
-
if (typeof argv.configFile === 'string') {
|
|
27
|
-
const path = interpolate(argv.configFile, argv, delimiters);
|
|
28
|
-
const [config, success] = await readJson(path);
|
|
29
|
-
|
|
30
|
-
if (success) for (const key in config) argv[key] ??= config[key];
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Extracts subcommand from command line parameters.
|
|
36
|
-
*
|
|
37
|
-
* @export
|
|
38
|
-
* @param {string[]} rawArgv process.argv.slice(2)
|
|
39
|
-
* @param {[string, string]} delimiters
|
|
40
|
-
*
|
|
41
|
-
* @returns {string[]} subcommand for wrap if exists
|
|
42
|
-
*/
|
|
43
|
-
export function getSubcommand(rawArgv: string[], delimiters: [string, string]) {
|
|
44
|
-
let subcommand: string[] = [];
|
|
45
|
-
|
|
46
|
-
// subcommand delimiter indexes
|
|
47
|
-
const begin = rawArgv.indexOf(delimiters[0]);
|
|
48
|
-
const count = rawArgv.lastIndexOf(delimiters[1]) - begin;
|
|
49
|
-
|
|
50
|
-
// calculates subcommand surrounded by delimiters
|
|
51
|
-
if (begin > 0) {
|
|
52
|
-
subcommand =
|
|
53
|
-
count > 0
|
|
54
|
-
? rawArgv.splice(begin, count + 1).slice(1, -1)
|
|
55
|
-
: rawArgv.splice(begin).slice(1);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return subcommand;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Loads providers JSON schema from file.
|
|
63
|
-
*
|
|
64
|
-
* @param {Record<string, unknown>} argv
|
|
65
|
-
* @param {[string, string]} delimiters
|
|
66
|
-
*
|
|
67
|
-
* @returns {Promise<Record<string, unknown>>}
|
|
68
|
-
*/
|
|
69
|
-
export async function loadSchemaFile(
|
|
70
|
-
argv: Record<string, unknown>,
|
|
71
|
-
delimiters: [string, string]
|
|
72
|
-
): Promise<Record<string, unknown> | undefined> {
|
|
73
|
-
if (typeof argv.schemaFile === 'string') {
|
|
74
|
-
const path = interpolate(argv.schemaFile, argv, delimiters);
|
|
75
|
-
const [schema, success] = await readJson(path);
|
|
76
|
-
|
|
77
|
-
return success ? schema : undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return undefined;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Reads project package.json.
|
|
85
|
-
*
|
|
86
|
-
* @export
|
|
87
|
-
* @returns {Promise<Record<string, unknown>> | never}
|
|
88
|
-
*/
|
|
89
|
-
export async function loadProjectInfo(): Promise<
|
|
90
|
-
Record<string, unknown> | undefined
|
|
91
|
-
> {
|
|
92
|
-
try {
|
|
93
|
-
return await import(`${process.cwd()}/package.json`);
|
|
94
|
-
} catch {
|
|
95
|
-
logger.warn(
|
|
96
|
-
`project file ${chalk.underline.yellow('package.json')} not found`
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
return undefined;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Executes load functions from provider handlers.
|
|
105
|
-
*
|
|
106
|
-
* @param {EnvProviderConfig[]} providers
|
|
107
|
-
* @param {Partial<Arguments<EnvCommandArguments>>} argv
|
|
108
|
-
*
|
|
109
|
-
* @returns {EnvProviderResult[]}
|
|
110
|
-
*/
|
|
111
|
-
export function loadVariablesFromProviders(
|
|
112
|
-
providers: EnvProviderConfig[],
|
|
113
|
-
argv: Partial<Arguments<EnvCommandArguments>>
|
|
114
|
-
): Promise<EnvProviderResult[]> {
|
|
115
|
-
if (!providers) return Promise.resolve([]) as Promise<EnvProviderResult[]>;
|
|
116
|
-
|
|
117
|
-
return Promise.all(
|
|
118
|
-
providers.map(({ handler: { key, load }, config }) => {
|
|
119
|
-
logger.silly(`executing ${chalk.yellow(key)} provider`);
|
|
120
|
-
|
|
121
|
-
const value = load(argv, config);
|
|
122
|
-
|
|
123
|
-
if (value instanceof Promise) {
|
|
124
|
-
return value.then((value) => ({
|
|
125
|
-
key,
|
|
126
|
-
config,
|
|
127
|
-
value
|
|
128
|
-
}));
|
|
129
|
-
} else {
|
|
130
|
-
return { key, config, value };
|
|
131
|
-
}
|
|
132
|
-
})
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Flattern environment provider results.
|
|
138
|
-
*
|
|
139
|
-
* @param {EnvProviderResult[]} results
|
|
140
|
-
* @param {Partial<Arguments<EnvCommandArguments>>} argv
|
|
141
|
-
*
|
|
142
|
-
* @throws {Error} on schema validation failed
|
|
143
|
-
*
|
|
144
|
-
* @returns {EnvProviderResult[]} flatten results
|
|
145
|
-
*/
|
|
146
|
-
export function flatResults(
|
|
147
|
-
results: EnvProviderResult[]
|
|
148
|
-
): EnvProviderResult[] | never {
|
|
149
|
-
return results.flatMap(({ value }) => {
|
|
150
|
-
if (Array.isArray(value)) value = merge({}, ...value);
|
|
151
|
-
|
|
152
|
-
return value;
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Flattern and validates environment provider results.
|
|
158
|
-
*
|
|
159
|
-
* @param {EnvProviderResult[]} results
|
|
160
|
-
* @param {Partial<Arguments<EnvCommandArguments>>} argv
|
|
161
|
-
*
|
|
162
|
-
* @throws {Error} on schema validation failed
|
|
163
|
-
*
|
|
164
|
-
* @returns {EnvProviderResult[]}
|
|
165
|
-
*/
|
|
166
|
-
export function flatAndValidateResults(
|
|
167
|
-
results: EnvProviderResult[],
|
|
168
|
-
argv: Partial<Arguments<EnvCommandArguments>>
|
|
169
|
-
): EnvProviderResult[] | never {
|
|
170
|
-
if (!argv.schemaValidate) return flatResults(results);
|
|
171
|
-
|
|
172
|
-
const validators = createValidators(argv.schema!, argv.detectFormat);
|
|
173
|
-
|
|
174
|
-
return results.flatMap(({ key, value }) => {
|
|
175
|
-
if (Array.isArray(value)) value = merge({}, ...value);
|
|
176
|
-
|
|
177
|
-
const validator = validators![key];
|
|
178
|
-
|
|
179
|
-
if (validator(value)) return value;
|
|
180
|
-
|
|
181
|
-
logger.error(
|
|
182
|
-
`schema validation failed for ${chalk.yellow(key)}`,
|
|
183
|
-
validator.errors
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
throw new Error(`schema validation failed for ${key}`);
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Creates or updates JSON schema from
|
|
192
|
-
* environment variables grouped by provider key.
|
|
193
|
-
*
|
|
194
|
-
* @export
|
|
195
|
-
* @param {EnvProviderResult[]} env
|
|
196
|
-
* @param {Arguments<EnvCommandArguments>} argv
|
|
197
|
-
*
|
|
198
|
-
* @returns {Promise<object>} JSON schema grouped by provider key.
|
|
199
|
-
*/
|
|
200
|
-
export async function generateSchemaFrom(
|
|
201
|
-
env: EnvProviderResult[],
|
|
202
|
-
argv: Arguments<CommandArguments>
|
|
203
|
-
): Promise<object> {
|
|
204
|
-
const { resolve, nullable, detectFormat, schemaFile } = argv;
|
|
205
|
-
|
|
206
|
-
// generates schemas from proviers results
|
|
207
|
-
let schema = env.reduce((schema, { key, value }) => {
|
|
208
|
-
const env = Array.isArray(value) ? merge({}, ...value) : value;
|
|
209
|
-
|
|
210
|
-
schema[key] = schemaFrom(env, {
|
|
211
|
-
nullable,
|
|
212
|
-
strings: { detectFormat }
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
return schema;
|
|
216
|
-
}, {} as Record<string, unknown>);
|
|
217
|
-
|
|
218
|
-
if (resolve === 'merge') schema = merge(argv.schema, schema);
|
|
219
|
-
|
|
220
|
-
await writeJson(schemaFile, schema, true);
|
|
221
|
-
|
|
222
|
-
return schema;
|
|
223
|
-
}
|