@openstax/ts-utils 1.1.28 → 1.1.30

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 (33) hide show
  1. package/dist/cjs/config/awsAccountConfig.d.ts +5 -0
  2. package/dist/cjs/config/awsAccountConfig.js +35 -0
  3. package/dist/cjs/config/awsParameterConfig.d.ts +2 -0
  4. package/dist/cjs/config/awsParameterConfig.js +18 -0
  5. package/dist/cjs/config/envConfig.d.ts +3 -0
  6. package/dist/cjs/config/envConfig.js +35 -0
  7. package/dist/cjs/config/index.d.ts +21 -0
  8. package/dist/cjs/config/index.js +39 -0
  9. package/dist/cjs/config/lambdaParameterConfig.d.ts +2 -0
  10. package/dist/cjs/config/lambdaParameterConfig.js +36 -0
  11. package/dist/cjs/config/replaceConfig.d.ts +4 -0
  12. package/dist/cjs/config/replaceConfig.js +12 -0
  13. package/dist/cjs/config/resolveConfigValue.d.ts +2 -0
  14. package/dist/cjs/config/resolveConfigValue.js +12 -0
  15. package/dist/cjs/services/authProvider/decryption.js +4 -4
  16. package/dist/cjs/tsconfig.withoutspecs.cjs.tsbuildinfo +1 -1
  17. package/dist/esm/config/awsAccountConfig.d.ts +5 -0
  18. package/dist/esm/config/awsAccountConfig.js +31 -0
  19. package/dist/esm/config/awsParameterConfig.d.ts +2 -0
  20. package/dist/esm/config/awsParameterConfig.js +14 -0
  21. package/dist/esm/config/envConfig.d.ts +3 -0
  22. package/dist/esm/config/envConfig.js +31 -0
  23. package/dist/esm/config/index.d.ts +21 -0
  24. package/dist/esm/config/index.js +21 -0
  25. package/dist/esm/config/lambdaParameterConfig.d.ts +2 -0
  26. package/dist/esm/config/lambdaParameterConfig.js +29 -0
  27. package/dist/esm/config/replaceConfig.d.ts +4 -0
  28. package/dist/esm/config/replaceConfig.js +8 -0
  29. package/dist/esm/config/resolveConfigValue.d.ts +2 -0
  30. package/dist/esm/config/resolveConfigValue.js +8 -0
  31. package/dist/esm/services/authProvider/decryption.js +1 -1
  32. package/dist/esm/tsconfig.withoutspecs.esm.tsbuildinfo +1 -1
  33. package/package.json +1 -1
@@ -0,0 +1,5 @@
1
+ import { ConfigValueProvider } from '.';
2
+ export declare const awsAccountConfig: <C extends string>(config: {
3
+ sandbox: ConfigValueProvider<C>;
4
+ production: ConfigValueProvider<C>;
5
+ }) => ConfigValueProvider<C>;
@@ -0,0 +1,31 @@
1
+ import { GetCallerIdentityCommand } from '@aws-sdk/client-sts';
2
+ import { assertDefined } from '../assertions';
3
+ import { securityTokenService } from '../aws/securityTokenService';
4
+ import { envConfig } from './envConfig';
5
+ import { resolveConfigValue } from './resolveConfigValue';
6
+ /*
7
+ * uses a different given value depending on which aws account the code is deployed in.
8
+ * this resolves the given value recursively, so its composable with more configProviders in the
9
+ * conditional cases.
10
+ *
11
+ * eg:
12
+ * const config = {
13
+ * configValue: awsAccountConfig({sandbox: 'inTheSandboxConfig', production: 'inProductionConfig'}),
14
+ * configValue: awsAccountConfig({sandbox: envConfig('an_environment_variable'), production: 'inProductionConfig'}),
15
+ * };
16
+ * */
17
+ export const awsAccountConfig = (config) => {
18
+ const production = envConfig('PRODUCTION_AWS');
19
+ const sandbox = envConfig('SANDBOX_AWS');
20
+ return async () => {
21
+ const identity = await securityTokenService().send(new GetCallerIdentityCommand({}));
22
+ switch (identity.Account) {
23
+ case await resolveConfigValue(sandbox):
24
+ return await resolveConfigValue(assertDefined(config.sandbox, 'a sandbox config was not provided'));
25
+ case await resolveConfigValue(production):
26
+ return await resolveConfigValue(assertDefined(config.production, 'a production config was not provided'));
27
+ default:
28
+ throw new Error('unknown aws account');
29
+ }
30
+ };
31
+ };
@@ -0,0 +1,2 @@
1
+ import { ConfigValueProvider } from '.';
2
+ export declare const awsParameterConfig: (parameterName: ConfigValueProvider<string>) => ConfigValueProvider<string>;
@@ -0,0 +1,14 @@
1
+ import { GetParameterCommand } from '@aws-sdk/client-ssm';
2
+ import { assertDefined } from '../assertions';
3
+ import { ssmService } from '../aws/ssmService';
4
+ import { resolveConfigValue } from './resolveConfigValue';
5
+ export const awsParameterConfig = (parameterName) => {
6
+ return async () => {
7
+ const command = new GetParameterCommand({ Name: await resolveConfigValue(parameterName), WithDecryption: true });
8
+ // send() throws ParameterNotFound if the parameter is missing,
9
+ // so it's not clear what missing Parameter or Value mean
10
+ const response = await ssmService().send(command);
11
+ const parameter = assertDefined(response.Parameter, `aws GetParameter response missing Parameter key for ${parameterName}"`);
12
+ return assertDefined(parameter.Value, `aws GetParameter response missing Parameter.Value key for ${parameterName}"`);
13
+ };
14
+ };
@@ -0,0 +1,3 @@
1
+ import { ConfigValueProvider } from '.';
2
+ export declare const ENV_BUILD_CONFIGS: string[];
3
+ export declare const envConfig: (name: string, type?: 'build' | 'runtime', defaultValue?: string | undefined) => ConfigValueProvider<string>;
@@ -0,0 +1,31 @@
1
+ import { assertDefined } from '../assertions';
2
+ import { ifDefined } from '../guards';
3
+ /*
4
+ * uses a config from the process environment.
5
+ *
6
+ * there are two modes for this, by default it expects the value to be provided at build time,
7
+ * and there is access built in here for webpack to provide the configs. if you pass `runtime`
8
+ * as the second argument it skips the build logic and will try to literally pull it from
9
+ * `process.env` when the config is used at runtime
10
+ *
11
+ * the value is read from the environment when something tries to use it, not when `envConfig` is called.
12
+ *
13
+ * eg:
14
+ * const config = {
15
+ * configValue: envConfig('environment_variable_name'),
16
+ * };
17
+ * */
18
+ export const ENV_BUILD_CONFIGS = [];
19
+ export const envConfig = (name, type = 'build', defaultValue) => {
20
+ if (type === 'build') {
21
+ ENV_BUILD_CONFIGS.push(name);
22
+ }
23
+ return () => {
24
+ /*global __PROCESS_ENV*/
25
+ // @ts-ignore - hack to get around the way webpack/define works
26
+ // - https://github.com/webpack/webpack/issues/14800
27
+ // - https://github.com/webpack/webpack/issues/5392
28
+ const envs = { ...process.env, ...(typeof __PROCESS_ENV !== 'undefined' ? __PROCESS_ENV : {}) };
29
+ return assertDefined(ifDefined(envs[name], defaultValue), `expected to find environment variable with name: ${name}`);
30
+ };
31
+ };
@@ -0,0 +1,21 @@
1
+ export declare type ConfigValue = string;
2
+ export declare type Config = {
3
+ [key: string]: Config | ConfigValue;
4
+ };
5
+ export declare type ConfigValueProvider<V extends ConfigValue = ConfigValue> = (() => Promise<V> | V) | V;
6
+ export declare type ConfigProvider = {
7
+ [key: string]: ConfigProvider | ConfigValueProvider;
8
+ };
9
+ export declare type ConfigForConfigProvider<T> = T extends ConfigValue ? T : T extends ConfigProvider ? {
10
+ [key in keyof T]: ConfigForConfigProvider<T[key]>;
11
+ } : T extends ConfigValueProvider<infer R> ? R : never;
12
+ export declare type ConfigProviderForConfig<T> = T extends ConfigValue ? ConfigValueProvider<T> : T extends Config ? {
13
+ [key in keyof T]: ConfigProviderForConfig<T[key]>;
14
+ } : never;
15
+ export * from './resolveConfigValue';
16
+ export declare const stubConfig: <V extends string>(configValue: V) => ConfigValueProvider<V>;
17
+ export * from './envConfig';
18
+ export * from './replaceConfig';
19
+ export * from './awsAccountConfig';
20
+ export * from './awsParameterConfig';
21
+ export * from './lambdaParameterConfig';
@@ -0,0 +1,21 @@
1
+ export * from './resolveConfigValue';
2
+ /*
3
+ * ===========
4
+ * re-usable config providers
5
+ * ===========
6
+ * */
7
+ /*
8
+ * stub, mostly for testing. sometimes it helps please typescript to use this if you have
9
+ * two configs you want to have the same type but one is a fixed string and one is a complicated provider
10
+ *
11
+ * eg:
12
+ * const config = {
13
+ * configValue: stubConfig('just-a-string'),
14
+ * };
15
+ * */
16
+ export const stubConfig = (configValue) => configValue;
17
+ export * from './envConfig';
18
+ export * from './replaceConfig';
19
+ export * from './awsAccountConfig';
20
+ export * from './awsParameterConfig';
21
+ export * from './lambdaParameterConfig';
@@ -0,0 +1,2 @@
1
+ import { ConfigValueProvider } from '.';
2
+ export declare const lambdaParameterConfig: (parameterName: ConfigValueProvider<string>) => ConfigValueProvider<string>;
@@ -0,0 +1,29 @@
1
+ import fetch from 'node-fetch';
2
+ import { assertDefined } from '../assertions';
3
+ import { envConfig } from './envConfig';
4
+ import { resolveConfigValue } from '.';
5
+ const lambdaExtensionUrl = 'http://localhost:2773';
6
+ let lambdaExtensionReadyPromise;
7
+ // NOTE: Can only be used during in AWS Lambda
8
+ // The AWS Parameters and Secrets Lambda Extension Layer must be included in the Lambda function
9
+ export const lambdaParameterConfig = (parameterName) => async () => {
10
+ const token = await resolveConfigValue(envConfig('AWS_SESSION_TOKEN', 'runtime'));
11
+ const name = await resolveConfigValue(parameterName);
12
+ if (!lambdaExtensionReadyPromise) {
13
+ // This request will return 400 Bad Request,
14
+ // but we only care that it'll block until the extension is ready
15
+ lambdaExtensionReadyPromise = fetch(lambdaExtensionUrl);
16
+ }
17
+ await lambdaExtensionReadyPromise;
18
+ const resp = await fetch(
19
+ // Port 2773 is the default port for the extension
20
+ `${lambdaExtensionUrl}/systemsmanager/parameters/get?name=${name}&withDecryption=true`, { headers: { 'X-Aws-Parameters-Secrets-Token': token } });
21
+ if (resp.ok) {
22
+ const response = await resp.json();
23
+ const parameter = assertDefined(response.Parameter, `aws GetParameter response missing Parameter key for ${name}"`);
24
+ return assertDefined(parameter.Value, `aws GetParameter response missing Parameter.Value key for ${name}"`);
25
+ }
26
+ else {
27
+ throw new Error(`HTTP Error Response ${resp.status} ${resp.statusText} while fetching parameter ${name}`);
28
+ }
29
+ };
@@ -0,0 +1,4 @@
1
+ import { ConfigValueProvider } from '.';
2
+ export declare const replaceConfig: (base: ConfigValueProvider<string>, replacements: {
3
+ [token: string]: ConfigValueProvider<string>;
4
+ }) => ConfigValueProvider<string>;
@@ -0,0 +1,8 @@
1
+ import { resolveConfigValue } from './resolveConfigValue';
2
+ export const replaceConfig = (base, replacements) => {
3
+ return async () => {
4
+ const resolved = await Promise.all(Object.entries(replacements)
5
+ .map(async ([token, replacement]) => [token, await resolveConfigValue(replacement)]));
6
+ return resolved.reduce((result, [token, replacement]) => result.replace(token, replacement), await resolveConfigValue(base));
7
+ };
8
+ };
@@ -0,0 +1,2 @@
1
+ import { ConfigValueProvider } from '.';
2
+ export declare const resolveConfigValue: <V extends string>(provider: ConfigValueProvider<V>) => Promise<V>;
@@ -0,0 +1,8 @@
1
+ /*
2
+ * resolves a config value into a string, to be used inside of things that are provided configurations
3
+ * */
4
+ export const resolveConfigValue = async (provider) => {
5
+ return typeof provider === 'function'
6
+ ? await provider()
7
+ : provider;
8
+ };
@@ -1,6 +1,6 @@
1
1
  import { compactDecrypt, compactVerify, importSPKI } from 'jose';
2
2
  import { once } from '../..';
3
- import { resolveConfigValue } from '../../config';
3
+ import { resolveConfigValue } from '../../config/resolveConfigValue';
4
4
  import { ifDefined } from '../../guards';
5
5
  import { getAuthTokenOrCookie } from '.';
6
6
  export const decryptionAuthProvider = (initializer) => (configProvider) => {