@zonekit/config-server
v0.2.0
Published
Config handler, manifest loader, server circuit breaker, and in-memory store for Zonekit
Maintainers
Readme
@zonekit/config-server
HTTP-facing config resolution for Zonekit.
Use @zonekit/config-server when you want a server endpoint that resolves configuration per request. It gives you a web-standard Request/Response handler, a manifest loader, circuit-breaker filtering for remotes, preview support, and in-memory stores for single-process deployments.
This package does not choose your framework or auth strategy. You mount the handler in Express, Fastify, Hono, Next, or any environment that can translate to web-standard Request and Response.
Installation
pnpm add @zonekit/config-serverQuick start
import { readFile } from "node:fs/promises";
import {
createConfigHandler,
createManifestLoader,
createServerCircuitBreaker,
createInMemoryCircuitBreakerStore,
} from "@zonekit/config-server";
const loader = createManifestLoader({
manifestDir: "./manifests",
readFile: (path) => readFile(path, "utf-8"),
buildFilePath: (dims) => `${dims.tenant}/${dims.product}/manifest.json`,
cache: true,
ttl: 60_000,
});
const breaker = createServerCircuitBreaker(
{ maxFailures: 5, resetTimeoutMs: 30_000 },
createInMemoryCircuitBreakerStore(),
);
const handler = createConfigHandler({
manifestLoader: loader,
circuitBreaker: breaker,
dimensionExtractor: (request) => {
const url = new URL(request.url);
return {
tenant: url.searchParams.get("tenant") ?? "default",
product: url.searchParams.get("product") ?? "default",
};
},
});
const response = await handler.handleResolve(
new Request("https://config.example.com/config/resolve?tenant=acme&product=default"),
);
void response;Recommended usage
- Use
createManifestLoader()to load tenant or product-specific manifest files. - Use
createServerCircuitBreaker()so unhealthy remotes can be filtered out of the response. - Use
createConfigHandler()as the framework-agnostic HTTP core. - Add auth or admin protection around preview and circuit-breaker inspection endpoints yourself.
Key exports
Core
createConfigHandler(options)for resolve, preview, health, circuit-breaker status, and version responses.createManifestLoader(options)for filesystem-backed manifest loading with cache and TTL support.createServerCircuitBreaker(options, store)for server-side remote health tracking.
In-memory stores
createInMemoryManifestCacheStore()for development or single-process deployments.createInMemoryCircuitBreakerStore()for development or single-process deployments.
Handler endpoints
handleResolve(request)returns tenant-filtered config, applies feature-flag guards from the manifestflags, and setsdegraded: truewhen remotes are filtered by circuit breaker state.handlePreview(request)accepts POST body input withdimensionsand optionalflagOverrides, bypasses the circuit breaker, and marks the response withpreview: true.handleHealth()returns{ status: "ok" }.handleCircuitBreakerStatus()returns all circuit-breaker statuses.handleVersion(request)returns the current config version for client polling. If you do not provide a customversionProvider, the handler hashes the manifest selected for that request's dimensions.
Operational notes
- Protect preview and circuit-breaker inspection endpoints before using this outside a trusted environment.
createManifestLoader()blocks path traversal outside the configured manifest directory.- Use the in-memory stores only for development or single-instance deployments. Multi-instance deployments should provide shared backing stores.
validateOutboundis enabled by default, so invalid responses fail fast before they leave the server.
License
MIT
Read more:
