Skip to content

Configuration Load Flow

Configuration Load Flow

The diagram below shows how ConfigurationManager.load() processes sources from lowest to highest priority.

flowchart TD
    A["1. FileConfigurationSource\n(or ObjectSource, etc.)\n← --config path.json"]
    B["2. EnvConfigurationSource\n← ADBLOCK_CONFIG_* env vars\n(skipped if --no-env-overrides)"]
    C["3. OverrideConfigurationSource\n← --override '{\"name\":\"...\"}'\n(optional, highest prio)"]
    D["ConfigurationManager.deepMerge(partials)\n· Scalars: last-defined wins\n· Arrays: last-defined fully replaces (no append)\n· undefined values do NOT override defined values"]
    E["Limit enforcement\n· sources.length > MAX_SOURCES(100) → truncate\n· exclusions.length > MAX_EXCLUSIONS(10 000) → truncate"]
    F["ConfigurationSchema.safeParse(merged)"]
    G["✓ return IConfiguration"]
    H["✗ throw ConfigurationValidationError"]

    A -->|"Partial<IConfiguration>"| B
    B -->|"Partial<IConfiguration>"| C
    C --> D
    D -->|"merged Partial<IConfiguration>"| E
    E --> F
    F -->|success| G
    F -->|failure| H

Worker API flow

flowchart TD
    Client["Client"]
    Turnstile["verifyTurnstile()"]
    Config["ConfigurationManager.fromSources(base, override, options)\n(same pipeline as above; EnvConfigurationSource is applied\nby default unless options.applyEnvOverrides === false)"]
    Response["200 OK — { config: IConfiguration }"]

    Client -->|"POST /api/configuration/resolve"| Turnstile
    Turnstile --> Config
    Config --> Response

Source interface

interface IConfigurationSource {
readonly sourceType: string;
load(): Promise<Partial<IConfiguration>>;
}

Any class implementing IConfigurationSource can be inserted into the pipeline, making it straightforward to add Terraform, remote API, or database-backed sources in the future.