@sixbell-telco/sdk
Version:
A collection of reusable components designed for use in Sixbell Telco Angular projects
236 lines (170 loc) • 5.08 kB
Markdown
# Runtime Config Utility
Shared runtime loader and update adapter used by Theme and Translation. It loads JSON at boot, checks updates, and stores last-known-good configs in IndexedDB (Dexie).
This doc covers:
- RuntimeConfigLoader flow
- Cache and schema versioning
- Update adapters (SSE/stream)
- RuntimeHttpClient behavior
- Examples for custom resources
## Core Concepts
### RuntimeConfigLoader
Responsibilities:
- Load a JSON config at boot (cache-first)
- Store last-known-good in Dexie
- Compare hash to detect updates
- Refresh on demand
### RuntimeConfigStore
Dexie-backed store that persists last-known-good config entries.
### RuntimeUpdateAdapter
Optional SSE/Observable wiring that signals when updates are available.
## Basic Usage
```ts
import { RuntimeConfigLoader, RuntimeConfigStore } from '@sixbell-telco/sdk/utils/runtime-config';
const store = new RuntimeConfigStore<MyConfig>('my-runtime-config', 'my-app');
const loader = new RuntimeConfigLoader<MyConfig>('/assets/config.json', {
fallbackData: { enabled: true },
resource: 'theme',
store,
schemaVersion: '1',
});
const result = await loader.loadLatest();
const check = await loader.checkForUpdates(result.hash);
if (check.updated) {
// show a "Refresh" CTA
}
const refreshed = await loader.refresh();
```
## Mermaid: Load Flow
```mermaid
sequenceDiagram
participant Loader
participant Store as RuntimeConfigStore
participant Net as Network
Loader->>Store: get(cacheKey)
alt cached & schema ok
Store-->>Loader: cached
Loader-->>Loader: return cached
else cache miss / schema mismatch
Loader->>Net: fetch(configPath)
Net-->>Loader: JSON
Loader->>Store: set(cacheKey)
Loader-->>Loader: return network
end
```
## Schema Versioning
If cached JSON is not compatible with the current code, set a schema version:
```ts
const loader = new RuntimeConfigLoader<MyConfig>(path, {
fallbackData,
resource: 'theme',
store,
schemaVersion: '2',
});
```
Add the version in JSON:
```json
{
"meta": {
"schemaVersion": "2"
}
}
```
If the schema version mismatches, cached entries are removed and a fresh network fetch occurs.
Hash requirements:
- `meta.hash` is mandatory and used for update detection.
- If `meta.hash` is missing, the loader treats the config as invalid and falls back.
Cache keys also include the schema version when provided, so new schema versions always
create a fresh cache namespace.
## RuntimeUpdateAdapter (SSE/Stream)
### SSE
````ts
import { RuntimeUpdateAdapter } from '@sixbell-telco/sdk/utils/runtime-config';
const adapter = new RuntimeUpdateAdapter(async (event) => {
if (event.resource !== 'theme' && event.resource !== 'both') return;
const check = await loader.checkForUpdates(currentHash);
if (check.updated) {
// show CTA
}
});
adapter.connectSse('/api/updates', {
resource: 'both',
eventType: 'message',
});
### Update payload requirements
Translation updates must include `lang` so clients can refresh the affected locale only.
```json
{
"resource": "translation",
"version": "translation-update",
"hash": "translations-1700000000000",
"url": "/api/runtime/translation/config",
"lang": "es"
}
````
```json
{
"resource": "theme",
"version": "theme-update",
"hash": "theme-1700000000000",
"url": "/api/runtime/theme/config",
"theme": "sixbell_telco"
}
```
If `lang` is missing, the update is rejected to avoid stale caches.
For theme updates, `theme` is required so clients can refresh the affected theme only.
````
### Observable
```ts
adapter.connectStream(update$);
````
### Observable from a polling endpoint
```ts
import { from, timer } from 'rxjs';
import { switchMap } from 'rxjs/operators';
const update$ = timer(0, 8000).pipe(
switchMap(() => from(fetch('http://localhost:4000/api/runtime/updates/poll'))),
switchMap((response) => from(response.json())),
);
adapter.connectStream(update$);
```
## RuntimeHttpClient
Built-in fetch with retries and timeouts:
```ts
const client = new RuntimeHttpClient({
retries: 2,
retryDelayMs: 400,
timeoutMs: 8000,
});
const response = await client.fetch('/assets/config.json', { cache: 'no-store' });
```
## Resource Loader Example (Custom Resource)
```ts
type FeatureFlags = {
meta?: { hash?: string; schemaVersion?: string };
flags: Record<string, boolean>;
};
const store = new RuntimeConfigStore<FeatureFlags>('flags-runtime-config', 'host');
const loader = new RuntimeConfigLoader<FeatureFlags>('/assets/flags.json', {
fallbackData: { flags: {} },
resource: 'both',
store,
schemaVersion: '1',
});
const result = await loader.loadLatest();
const flags = result.data.flags;
```
## Notes
- Fetch uses `cache: 'no-store'` to avoid stale responses.
- Dexie cache is last-known-good only, not an aggressive cache.
- When meta.hash is missing, a stable hash is computed from JSON.
## Related Utilities
- `@sixbell-telco/sdk/utils/theme` - Runtime theme system
- `@sixbell-telco/sdk/utils/translation` - Runtime translation system