diff --git a/docker/run.sh b/docker/run.sh index 9cecd88f63..fdb1742a07 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -16,7 +16,7 @@ function inject_config() { with_entries(select(.key | startswith("APP_CONFIG_")) | .key |= sub("APP_CONFIG_"; "")) | to_entries | reduce .[] as $item ( - {}; setpath($item.key | split("_"); $item.value | fromjson) + {}; setpath($item.key | split("_"); $item.value | try fromjson catch $item.value) )')" >&2 echo "Runtime app config: $config" diff --git a/packages/config-loader/src/lib/env.test.ts b/packages/config-loader/src/lib/env.test.ts index 9ecc80d29a..93bd962596 100644 --- a/packages/config-loader/src/lib/env.test.ts +++ b/packages/config-loader/src/lib/env.test.ts @@ -40,14 +40,15 @@ describe('readEnv', () => { APP_CONFIG_numbers_a: '1', APP_CONFIG_numbers_b: '2', APP_CONFIG_numbers_c: 'false', - APP_CONFIG_numbers_d: undefined, + APP_CONFIG_numbers_d: 'abc', + APP_CONFIG_numbers_e: undefined, APP_CONFIG_very_deep_nested_config_object: '{}', }), ).toEqual([ { data: { foo: 'bar', - numbers: { a: 1, b: 2, c: false }, + numbers: { a: 1, b: 2, c: false, d: 'abc' }, very: { deep: { nested: { config: { object: {} } } } }, }, context: 'env', @@ -55,6 +56,37 @@ describe('readEnv', () => { ]); }); + it('should accept string values', () => { + expect(readEnv({ APP_CONFIG_foo: '"abc"', APP_CONFIG_bar: 'xyz' })).toEqual( + [ + { + data: { + foo: 'abc', + bar: 'xyz', + }, + context: 'env', + }, + ], + ); + }); + + it('should accept complex objects', () => { + expect( + readEnv({ + APP_CONFIG_foo: '{ "a": 123, "b": "123", "c": [] }', + APP_CONFIG_bar: '[123, "abc", {}]', + }), + ).toEqual([ + { + data: { + foo: { a: 123, b: '123', c: [] }, + bar: [123, 'abc', {}], + }, + context: 'env', + }, + ]); + }); + it.each([ ['APP_CONFIG__foo'], ['APP_CONFIG_foo_'], @@ -68,12 +100,17 @@ describe('readEnv', () => { ); }); - it.each([['hello'], ['"hello'], ['{'], ['}'], ['123abc']])( - 'should reject invalid value %p', + it.each([['hello'], ['"hello'], ['{'], ['}']])( + 'should fallback to string when invalid json value %p', value => { - expect(() => readEnv({ APP_CONFIG_foo: value })).toThrow( - /^Failed to parse JSON-serialized config value for key 'foo', SyntaxError: /, - ); + expect(readEnv({ APP_CONFIG_foo: value })).toEqual([ + { + data: { + foo: value, + }, + context: 'env', + }, + ]); }, ); diff --git a/packages/config-loader/src/lib/env.ts b/packages/config-loader/src/lib/env.ts index aa986931ff..53c6d6c63b 100644 --- a/packages/config-loader/src/lib/env.ts +++ b/packages/config-loader/src/lib/env.ts @@ -72,7 +72,7 @@ export function readEnv(env: { ); } try { - const parsedValue = JSON.parse(value); + const [, parsedValue] = safeJsonParse(value); if (parsedValue === null) { throw new Error('value may not be null'); } @@ -89,3 +89,11 @@ export function readEnv(env: { return data ? [{ data, context: 'env' }] : []; } + +function safeJsonParse(str: string): [Error | null, any] { + try { + return [null, JSON.parse(str)]; + } catch (err) { + return [err, str]; + } +}