npm package: @onlineapps/runtime-config
Description: Runtime configuration resolver with schema-driven priority (explicit config → ENV → owner defaults)
Author: OnlineApps
Latest version: 1.0.2

# @onlineapps/runtime-config

Runtime configuration resolver with schema-driven priority.

## Features

- **Single mechanism**: One resolver for all runtime config resolution
- **Schema-driven**: Each module declares its config schema once
- **Priority order**: explicit config → ENV → owner defaults
- **Fail-fast**: `required: true` throws if value missing
- **Type coercion**: Auto-parses strings to number/boolean

## Installation

```bash
npm install @onlineapps/runtime-config
```

## Usage

```javascript
const { createRuntimeConfig } = require('@onlineapps/runtime-config');
const DEFAULTS = require('./defaults');

const runtimeCfg = createRuntimeConfig({
  defaults: DEFAULTS,
  schema: {
    host:     { env: 'REDIS_HOST', defaultKey: 'defaultHost' },
    port:     { env: 'REDIS_PORT', defaultKey: 'defaultPort', type: 'number' },
    password: { env: 'REDIS_PASSWORD' },
    ttl:      { env: 'CACHE_TTL', defaultKey: 'defaultTTLSeconds', type: 'number' },
    // Infra topology - FAIL-FAST (no default)
    url:      { env: 'REDIS_URL', required: true },
  }
});

// Get single value
const host = runtimeCfg.get('host');

// Resolve all with explicit overrides
const config = runtimeCfg.resolve({ password: 'secret' });
```

## Priority Order

1. **Explicit config**: Value passed to `resolve()` or `get()`
2. **Environment variable**: `process.env[spec.env]`
3. **Owner defaults**: Value from `defaults` object

## Schema Spec Properties

| Property | Type | Description |
|----------|------|-------------|
| `env` | string | Environment variable name |
| `defaultKey` | string | Key in `defaults` object |
| `default` | any | Inline default value |
| `type` | string | Value type: `'string'`, `'number'`, `'float'`, `'boolean'` |
| `required` | boolean | If `true`, throws when value is missing |

## Type Coercion

- `number`: Parses with `parseInt()`, throws on invalid
- `float`: Parses with `parseFloat()`, throws on invalid
- `boolean`: Accepts `true`, `false`, `'true'`, `'false'`, `'1'`, `'0'`
- `string`: Converts to string

## Fail-Fast for Infra Topology

For infrastructure URLs/hosts, use `required: true` without defaults:

```javascript
const runtimeCfg = createRuntimeConfig({
  defaults: {},
  schema: {
    rabbitmqUrl: { env: 'RABBITMQ_URL', required: true },
    redisUrl: { env: 'REDIS_URL', required: true },
  }
});

// Throws if RABBITMQ_URL or REDIS_URL are not set
const config = runtimeCfg.resolve();
```

## Naming Convention

- **ServiceConfig** = biz-specific config (per-service, loaded by `ServiceConfigLoader`)
- **RuntimeConfig** = runtime config (env/defaults, resolved by this library)

## API

### `createRuntimeConfig(options)`

Creates a new resolver instance.

**Options:**
- `defaults` (Object): Owner defaults object
- `schema` (Object): Config schema definition
- `env` (Object): Environment object (defaults to `process.env`)

**Returns:** `RuntimeConfigResolver` instance

### `resolver.get(key, [explicitValue])`

Get a single config value.

**Parameters:**
- `key` (string): Config key name
- `explicitValue` (any): Explicit value (highest priority)

**Returns:** Resolved value

**Throws:** Error if key is unknown or required value is missing

### `resolver.resolve([explicitConfig])`

Resolve all config values at once.

**Parameters:**
- `explicitConfig` (Object): Explicit config object (highest priority)

**Returns:** Object with all resolved config values

**Throws:** Error if any required value is missing

### `resolver.keys()`

Get all schema keys.

**Returns:** Array of config key names

### `resolver.has(key)`

Check if a key exists in schema.

**Returns:** Boolean