NODEDC_PLATFORM/services/gelios-gateway/src/config.mjs

81 lines
2.8 KiB
JavaScript

export function readConfig(env = process.env) {
const rawRetentionDays = integer(env.GELIOS_RAW_RETENTION_DAYS, 14, 1, 3650);
return {
nodeEnv: string(env.NODE_ENV, "development"),
port: integer(env.PORT, 18105, 1, 65535),
databaseUrl: required(env.DATABASE_URL, "DATABASE_URL"),
databasePoolSize: integer(env.GELIOS_DATABASE_POOL_SIZE, 10, 1, 50),
internalAccessToken: optional(env.NODEDC_INTERNAL_ACCESS_TOKEN),
tenantId: slug(required(env.GELIOS_TENANT_ID, "GELIOS_TENANT_ID"), "GELIOS_TENANT_ID"),
connectionId: slug(required(env.GELIOS_CONNECTION_ID, "GELIOS_CONNECTION_ID"), "GELIOS_CONNECTION_ID"),
unitScope: collectionScope(env.GELIOS_UNIT_SCOPE),
allowedUnitIds: intList(env.GELIOS_ALLOWED_UNIT_IDS),
intakeEnabled: boolean(env.GELIOS_INTAKE_ENABLED, false),
rawRetentionDays,
positionStaleAfterMs: integer(env.GELIOS_POSITION_STALE_AFTER_MS, 300_000, 1_000, 86_400_000),
};
}
function collectionScope(value) {
const candidate = optional(value).toLowerCase() || "allowlist";
if (["allowlist", "all"].includes(candidate)) return candidate;
throw new Error("GELIOS_UNIT_SCOPE_must_be_allowlist_or_all");
}
export function unitIsInScope(config, sourceUnitId) {
return config?.unitScope === "all" || config?.allowedUnitIds?.includes(sourceUnitId) === true;
}
function required(value, name) {
const normalized = optional(value);
if (!normalized) throw new Error(`${name}_required`);
return normalized;
}
function optional(value) {
const normalized = String(value ?? "").trim();
return normalized || "";
}
function string(value, fallback) {
return optional(value) || fallback;
}
function integer(value, fallback, min, max) {
const candidate = optional(value);
if (!candidate) return fallback;
const number = Number.parseInt(candidate, 10);
if (!Number.isInteger(number) || number < min || number > max) {
throw new Error(`invalid_integer:${candidate}`);
}
return number;
}
function boolean(value, fallback) {
const candidate = optional(value).toLowerCase();
if (!candidate) return fallback;
if (["1", "true", "yes", "on"].includes(candidate)) return true;
if (["0", "false", "no", "off"].includes(candidate)) return false;
throw new Error(`invalid_boolean:${candidate}`);
}
function intList(value) {
const values = optional(value)
.split(",")
.map((item) => item.trim())
.filter(Boolean)
.map((item) => Number.parseInt(item, 10));
if (values.some((item) => !Number.isInteger(item) || item <= 0)) {
throw new Error("GELIOS_ALLOWED_UNIT_IDS_must_contain_positive_integers");
}
return [...new Set(values)].sort((left, right) => left - right);
}
function slug(value, name) {
if (!/^[a-z0-9][a-z0-9_-]{0,95}$/i.test(value)) {
throw new Error(`${name}_invalid`);
}
return value;
}