@flic-sdk/node-server
v0.0.3
Published
Node.js Server SDK for Flic feature flags (local evaluation)
Downloads
37
Maintainers
Readme
@flic-sdk/node-server
Node.js server SDK for Flic feature flags. Designed for multi-user server environments.
Architecture
┌─────────────────┐ ┌─────────────┐
│ Node.js Server │ │ Flic API │
│ │ SSE │ │
│ node-server-sdk│◄─────│ configs │
│ │ │ (rules) │
│ [local eval] │ │ │
└─────────────────┘ └─────────────┘Local evaluation: Downloads flag configs (rules) and evaluates locally. Zero latency per evaluation.
Installation
npm install @flic-sdk/node-serverQuick Start
import { FlicServer } from "@flic-sdk/node-server";
const flic = new FlicServer({
apiKey: "flic_xxx",
baseUrl: "https://api.flic.dev",
project: "my-project",
environment: "production",
});
await flic.init(); // Fetches configs, starts streaming
// Evaluate for any user - instant, no network call
const enabled = flic.isEnabled("new-feature", {
key: "user-123",
attributes: { plan: "pro" }
});
const theme = flic.getValue("theme", "light", { key: "user-456" });
// Graceful shutdown
await flic.close();API
Constructor
new FlicServer({
apiKey: string; // Required - API key
baseUrl: string; // Required - API URL
project: string; // Required - Project slug
environment: string; // Required - Environment name
pollingInterval?: number; // Fallback polling interval (default: 30000ms)
streaming?: boolean | StreamConfig; // SSE for config updates (default: true)
analytics?: boolean | AnalyticsConfig; // Impression tracking (default: true)
});Methods
| Method | Returns | Description |
|--------|---------|-------------|
| init() | Promise<void> | Fetch configs, start updates. Must await before evaluating. |
| isEnabled(key, ctx?) | boolean | Evaluate boolean flag for context |
| getValue(key, default, ctx?) | T | Evaluate value flag for context |
| evaluate(key, ctx?) | EvaluatedFlag | Full evaluation result |
| getAllFlags() | Map<string, FlagConfig> | Get cached flag configs |
| close() | Promise<void> | Stop updates, flush analytics |
Context
Pass context per-call (different users per request):
type EvaluateContext = {
key?: string; // User ID for consistent rollouts
attributes?: Record<string, unknown>; // Targeting attributes
};
// Each call can have different context
flic.isEnabled("feature", { key: "user-1", attributes: { country: "US" } });
flic.isEnabled("feature", { key: "user-2", attributes: { country: "DE" } });Why Sync Evaluation?
This is the standard pattern used by LaunchDarkly, Unleash, and other SDKs:
┌─────────────────────────────────────────────────────────────┐
│ Lifecycle │
├─────────────────────────────────────────────────────────────┤
│ init() → Async. Fetches configs. Start SSE/polling. │
│ isEnabled() → Sync. Reads from in-memory cache. ~0ms. │
│ getValue() → Sync. Evaluates rules locally. ~0ms. │
│ close() → Async. Cleanup, flush analytics. │
└─────────────────────────────────────────────────────────────┘Benefits:
- Zero latency: No network call during request handling
- No async/await noise: Simple
if (flic.isEnabled(...)) - Consistent: Same flag value during entire request
- Resilient: Works even if API is temporarily unreachable
Resilience
What happens if the connection fails?
- Cached configs persist - All rules remain in memory
- Auto reconnect - SDK retries with exponential backoff
- Fallback to polling - After max retries, switches to polling
- Evaluations keep working - Using cached configs until reconnect
// This always works after init(), even if disconnected
flic.isEnabled("feature", { key: "user" }); // Uses cached rulesWhat about stale data?
- Configs are typically stable (don't change every second)
- SSE updates arrive in <100ms when connected
- Polling interval is configurable (default: 30s)
- For critical changes, use kill switches that default to "off"
Express Example
import express from "express";
import { FlicServer } from "@flic-sdk/node-server";
const flic = new FlicServer({
apiKey: process.env.FLIC_API_KEY,
baseUrl: "https://api.flic.dev",
project: "my-project",
environment: "production",
});
await flic.init();
const app = express();
app.get("/api/checkout", (req, res) => {
const userId = req.user.id;
if (flic.isEnabled("new-checkout", { key: userId })) {
return handleNewCheckout(req, res);
}
return handleLegacyCheckout(req, res);
});
// Graceful shutdown
process.on("SIGTERM", async () => {
await flic.close();
process.exit(0);
});Streaming Config
new FlicServer({
// ...
streaming: {
enabled: true,
reconnectDelay: 1000, // Initial retry delay
maxReconnectDelay: 30000, // Max retry delay
maxReconnectAttempts: 5, // Before fallback to polling
fallbackToPolling: true,
},
});Analytics
Tracks all evaluations for analytics:
new FlicServer({
// ...
analytics: {
enabled: true,
flushInterval: 10000, // Batch send interval
maxBatchSize: 100, // Max events before immediate flush
},
});Disable with analytics: false.
Client SDK vs Server SDK
| Aspect | Client SDK | Server SDK | |--------|------------|------------| | Runtime | Browser | Node.js | | Users | Single user | Multiple users | | Evaluation | Server-side | Local | | Context | Set once at init | Per evaluation call | | Cache | Evaluated results | Flag configs + rules | | Latency | Network per init | Network per init only |
Use client-sdk for browsers. Use node-server-sdk for servers.
TypeScript
import type {
EvaluateContext,
FlicServerConfig,
EvaluatedFlag,
FlagConfig
} from "@flic-sdk/node-server";