@@ -20,64 +20,86 @@ export const getConfig = (): Config => {
20
20
return config ;
21
21
} ;
22
22
23
- export const loadAndCacheConfig = async ( ) : Promise < Config > => {
24
- const jsonConfig = await fetchConfig ( ) ;
25
- config = configSchema . parse ( jsonConfig ) ;
26
- return config ;
27
- } ;
28
-
29
23
// When Signed API is built, the "/dist" file contains "src" folder and "package.json" and the config is expected to be
30
24
// located next to the "/dist" folder. When run in development, the config is expected to be located next to the "src"
31
25
// folder (one less import level). We resolve the config by CWD as a workaround. Since the Signed API is dockerized,
32
26
// this is hidden from the user.
33
27
const getConfigPath = ( ) => join ( cwd ( ) , './config' ) ;
34
28
35
- export const loadRawConfig = ( ) => JSON . parse ( readFileSync ( join ( getConfigPath ( ) , 'signed-api.json' ) , 'utf8' ) ) ;
29
+ export const loadRawConfigFromFilesystem = ( ) =>
30
+ JSON . parse ( readFileSync ( join ( getConfigPath ( ) , 'signed-api.json' ) , 'utf8' ) ) ;
36
31
37
- export const loadRawSecrets = ( ) => dotenv . parse ( readFileSync ( join ( getConfigPath ( ) , 'secrets.env' ) , 'utf8' ) ) ;
32
+ export const loadRawSecretsFromFilesystem = ( ) =>
33
+ dotenv . parse ( readFileSync ( join ( getConfigPath ( ) , 'secrets.env' ) , 'utf8' ) ) ;
38
34
39
35
export const loadConfigFromFilesystem = ( ) => {
40
36
const goLoadConfig = goSync ( ( ) => {
41
- const rawSecrets = loadRawSecrets ( ) ;
42
- const rawConfig = loadRawConfig ( ) ;
37
+ const rawSecrets = loadRawSecretsFromFilesystem ( ) ;
38
+ const rawConfig = loadRawConfigFromFilesystem ( ) ;
43
39
const secrets = parseSecrets ( rawSecrets ) ;
44
- return configSchema . parse ( interpolateSecrets ( rawConfig , secrets ) ) ;
40
+ return interpolateSecrets ( rawConfig , secrets ) ;
45
41
} ) ;
46
42
47
- if ( ! goLoadConfig . success ) throw new Error ( `Unable to load configuration.` , { cause : goLoadConfig . error } ) ;
43
+ if ( ! goLoadConfig . success ) {
44
+ logger . error ( `Unable to load configuration.` , goLoadConfig . error ) ;
45
+ return null ;
46
+ }
48
47
return goLoadConfig . data ;
49
48
} ;
50
49
51
- const fetchConfig = async ( ) : Promise < any > => {
50
+ export const loadNonValidatedConfig = async ( ) => {
52
51
const env = loadEnv ( ) ;
53
52
const source = env . CONFIG_SOURCE ;
54
53
switch ( source ) {
55
54
case 'local' : {
56
55
return loadConfigFromFilesystem ( ) ;
57
56
}
58
57
case 'aws-s3' : {
59
- return fetchConfigFromS3 ( ) ;
58
+ return loadConfigFromS3 ( ) ;
60
59
}
61
60
}
62
61
} ;
63
62
64
- const fetchConfigFromS3 = async ( ) : Promise < any > => {
65
- const env = loadEnv ( ) ;
66
- const region = env . AWS_REGION ! ; // Validated by environment variables schema.
67
- const s3 = new S3 ( { region } ) ;
68
-
69
- const params = {
70
- Bucket : env . AWS_S3_BUCKET_NAME ,
71
- Key : env . AWS_S3_BUCKET_PATH ,
72
- } ;
73
-
74
- logger . info ( `Fetching config from AWS S3 region.` , { region } ) ;
75
- const res = await go ( async ( ) => s3 . getObject ( params ) , { retries : 1 } ) ;
76
- if ( ! res . success ) {
77
- logger . error ( 'Error fetching config from AWS S3.' , res . error ) ;
78
- throw res . error ;
63
+ export const loadConfig = async ( ) => {
64
+ if ( config ) return config ;
65
+
66
+ const nonValidatedConfig = await loadNonValidatedConfig ( ) ;
67
+ if ( ! nonValidatedConfig ) return null ;
68
+
69
+ const safeParsedConfig = configSchema . safeParse ( nonValidatedConfig ) ;
70
+ if ( ! safeParsedConfig . success ) {
71
+ logger . error ( 'Config failed validation.' , safeParsedConfig . error ) ;
72
+ return null ;
73
+ }
74
+ return ( config = safeParsedConfig . data ) ;
75
+ } ;
76
+
77
+ const loadConfigFromS3 = async ( ) : Promise < any > => {
78
+ const goFetchConfig = await go ( async ( ) => {
79
+ const env = loadEnv ( ) ;
80
+ const region = env . AWS_REGION ! ; // Validated by environment variables schema.
81
+ const s3 = new S3 ( { region } ) ;
82
+
83
+ const params = {
84
+ Bucket : env . AWS_S3_BUCKET_NAME ,
85
+ Key : env . AWS_S3_BUCKET_PATH ,
86
+ } ;
87
+
88
+ logger . info ( `Fetching config from AWS S3 region.` , { region } ) ;
89
+ const res = await go ( async ( ) => s3 . getObject ( params ) , { retries : 1 } ) ;
90
+ if ( ! res . success ) {
91
+ logger . error ( 'Error fetching config from AWS S3.' , res . error ) ;
92
+ return null ;
93
+ }
94
+ logger . info ( 'Config fetched successfully from AWS S3.' ) ;
95
+ const stringifiedConfig = await res . data . Body ! . transformToString ( ) ;
96
+ return JSON . parse ( stringifiedConfig ) ;
97
+ } ) ;
98
+
99
+ // Check whether the config returned a truthy response, because false response assumes an error has been handled.
100
+ if ( ! goFetchConfig . success || ! goFetchConfig . data ) {
101
+ logger . error ( 'Unexpected error during fetching config from S3.' , goFetchConfig . error ) ;
102
+ return null ;
79
103
}
80
- logger . info ( 'Config fetched successfully from AWS S3.' ) ;
81
- const stringifiedConfig = await res . data . Body ! . transformToString ( ) ;
82
- return JSON . parse ( stringifiedConfig ) ;
104
+ return goFetchConfig . data ;
83
105
} ;
0 commit comments