This commit is contained in:
2025-09-11 17:15:02 +02:00
parent ecd439dcd1
commit f1898ff0fc
4 changed files with 77 additions and 74 deletions
+21 -21
View File
@@ -4,35 +4,35 @@ import fs from 'node:fs/promises'
import type {Ok} from './helpers'
const log = logger('config:env')
const FILE_EXT = "__FILE"
const FILE_EXT = '__FILE'
// Read from env or file
export async function read_env(key: string): Promise<Ok<string | undefined>> {
const path = process.env[key + FILE_EXT]
if (path !== undefined) return from_file(path)
else return {ok: true, data: process.env[key]}
const path = process.env[key + FILE_EXT]
if (path !== undefined) return from_file(path)
else return {ok: true, data: process.env[key]}
}
async function from_file(path: string): Promise<Ok<string>> {
log.debug("Read a key from a file")
log.trace("Path :", path)
log.debug('Read a key from a file')
log.trace('Path :', path)
let content = await get_file_content(path)
if (!content.ok) return content
let content = await get_file_content(path)
if (!content.ok) return content
content.data = content.data.trim()
content.data = content.data.trim()
return content
return content
}
async function get_file_content(path: string) : Promise<Ok<string>> {
log.debug('Read file content')
log.trace('Path :', path)
async function get_file_content(path: string): Promise<Ok<string>> {
log.debug('Read file content')
log.trace('Path :', path)
try {
const data = await fs.readFile(path, {encoding: 'utf-8'})
return {ok: true, data}
} catch (e) {
log.warn('Failed to read file', path)
log.debug('Error :', e)
return {ok: false}
}
try {
const data = await fs.readFile(path, {encoding: 'utf-8'})
return {ok: true, data}
} catch (e) {
log.warn('Failed to read file', path)
log.debug('Error :', e)
return {ok: false}
}
}
+1 -1
View File
@@ -1 +1 @@
export type Ok<T> = {ok: true, data: T} | {ok?: false}
export type Ok<T> = {ok: true; data: T} | {ok?: false}
+12 -12
View File
@@ -9,19 +9,19 @@ export * as yup from 'yup'
const log = logger('config')
export async function parse<S extends yup.Maybe<yup.AnyObject>>(schema: yup.ObjectSchema<S>): Promise<Ok<S>> {
log.info("Parse from env")
log.info('Parse from env')
log.trace("Start parsing")
const config = await parsing.object(schema)
if (!config.ok) return config
log.trace('Start parsing')
const config = await parsing.object(schema)
if (!config.ok) return config
log.trace("double-check")
const res = await schema.isValid(config.data, {strict: true})
if (!res) {
log.error("Double-check failed")
log.debug('Config', config.data)
return {ok: false}
}
log.trace('double-check')
const res = await schema.isValid(config.data, {strict: true})
if (!res) {
log.error('Double-check failed')
log.debug('Config', config.data)
return {ok: false}
}
return config
return config
}
+43 -40
View File
@@ -6,57 +6,60 @@ import type {Ok} from './helpers'
const log = logger('config:parsing')
export async function object<S extends yup.Maybe<yup.AnyObject>>(schema: yup.ObjectSchema<S>, base_name: string = ""): Promise<Ok<S>> {
log.debug("Object")
if (base_name.length !== 0) base_name = base_name + "_"
export async function object<S extends yup.Maybe<yup.AnyObject>>(
schema: yup.ObjectSchema<S>,
base_name: string = ''
): Promise<Ok<S>> {
log.debug('Object')
if (base_name.length !== 0) base_name = base_name + '_'
// @ts-expect-error Ugly hack with type S
const data: S = {}
for (const key in schema.fields) {
const sub_key = base_name + key.toUpperCase()
// @ts-expect-error Ugly hack with type S
const data: S = {}
const sub_scheme = schema.fields[key]
let value: Ok<unknown>
for (const key in schema.fields) {
const sub_key = base_name + key.toUpperCase()
// TODO : If array, add a transform
if (sub_scheme.describe().type === 'object') {
value = await object(sub_scheme, sub_key)
} else {
value = await generic(sub_scheme, sub_key)
}
const sub_scheme = schema.fields[key]
let value: Ok<unknown>
if (!value.ok) return value
if (value.data === undefined) continue
data[key] = value.data
// TODO : If array, add a transform
if (sub_scheme.describe().type === 'object') {
value = await object(sub_scheme, sub_key)
} else {
value = await generic(sub_scheme, sub_key)
}
return {ok: true, data}
if (!value.ok) return value
if (value.data === undefined) continue
data[key] = value.data
}
return {ok: true, data}
}
export async function generic<S>(scheme: yup.AnySchema<S>, key: string): Promise<Ok<S | undefined>> {
log.debug('Generic', scheme.describe().type)
log.debug('Generic', scheme.describe().type)
const value = await read_env(key)
if (!value.ok) return value
const value = await read_env(key)
if (!value.ok) return value
if (value.data === undefined) {
const def = scheme.getDefault()
if (def !== undefined) return {ok: true, data: def}
else if (scheme.spec.optional) return {ok: true, data: undefined}
log.warn('Missing value for', key)
return {}
}
if (value.data === undefined) {
const def = scheme.getDefault()
if (def !== undefined) return {ok: true, data: def}
else if (scheme.spec.optional) return {ok: true, data: undefined}
if (!(await scheme.isValid(value.data))) {
log.warn('Invaid value for', key)
log.debug('Value:', value.data)
return {}
}
const res = scheme.cast(value.data)
log.warn('Missing value for', key)
return {}
}
return {ok: true, data: res}
if (!(await scheme.isValid(value.data))) {
log.warn('Invaid value for', key)
log.debug('Value:', value.data)
return {}
}
const res = scheme.cast(value.data)
return {ok: true, data: res}
}