@teracrafts/flagkit
v1.1.0
Published
FlagKit TypeScript SDK for feature flag evaluation
Maintainers
Readme
@teracrafts/flagkit
Official TypeScript SDK for FlagKit - Feature flag management made simple.
Features
- Zero runtime dependencies - No external packages required
- Universal - Browser and Node.js support
- TypeScript-first - Full type safety with comprehensive type definitions
- Tiny bundle - < 20KB gzipped
- Resilient - Automatic retry with exponential backoff, circuit breaker
- Event tracking - Analytics with batching
- Offline mode - Works without network
Installation
npm install @teracrafts/flagkit
# or
yarn add @teracrafts/flagkit
# or
pnpm add @teracrafts/flagkitQuick Start
import FlagKit from '@teracrafts/flagkit';
// Initialize the SDK
const client = await FlagKit.initialize({
apiKey: 'sdk_your_api_key',
onReady: () => console.log('FlagKit ready!'),
});
// Wait for SDK to be ready
await client.waitForReady();
// Identify user
client.identify('user-123', {
email: '[email protected]',
custom: { plan: 'premium' },
});
// Evaluate flags
const darkMode = client.getBooleanValue('dark-mode', false);
const welcomeMsg = client.getStringValue('welcome-message', 'Hello!');
const maxItems = client.getNumberValue('max-items', 10);
const config = client.getJsonValue('feature-config', { enabled: false });
// Track events
client.track('button_clicked', { button: 'signup' });
// Cleanup when done
await client.close();Configuration
const client = await FlagKit.initialize({
// Required
apiKey: 'sdk_your_api_key',
// Polling
pollingInterval: 30000, // Default: 30s
enablePolling: true, // Default: true
// Caching
cacheEnabled: true, // Default: true
cacheTTL: 300000, // Default: 5 minutes
// Network
timeout: 5000, // Default: 5s
retries: 3, // Default: 3
// Modes
offline: false, // Default: false
debug: false, // Default: false
// Bootstrap fallback values
bootstrap: {
'dark-mode': false,
'max-items': 10,
},
// Callbacks
onReady: () => {},
onError: (error) => {},
onUpdate: (flags) => {},
});Developer Tools
FlagKit includes built-in developer tools for inspecting and overriding feature flags during development. The DevTools render inside Shadow DOM for complete style isolation and will never affect your application's layout or CSS.
Quick Start
import { FlagKit, FlagKitDevToolsCore } from '@teracrafts/flagkit';
const client = await FlagKit.initialize({ apiKey: 'sdk_your_key' });
// Mount developer tools (development only)
if (import.meta.env.DEV) {
const devtools = new FlagKitDevToolsCore(client, {
theme: 'system',
buttonPosition: 'bottom-right',
});
devtools.mount(document.body);
}Or use the convenience method:
client.mountDevTools(document.body, { theme: 'dark' });React Integration
The React SDK provides components and a hook for DevTools:
import { FlagKitDevTools, FlagKitDevToolsLazy, useFlagKitDevTools } from '@teracrafts/flagkit-react';
// Component — auto-mounts/unmounts with lifecycle
function App() {
const { client } = useFlagKit();
return (
<>
<MyApp />
{client && <FlagKitDevTools client={client} theme="system" />}
</>
);
}
// Lazy-loaded variant — only downloads DevTools code when rendered
function App() {
const { client } = useFlagKit();
return (
<>
<MyApp />
{import.meta.env.DEV && client && <FlagKitDevToolsLazy client={client} />}
</>
);
}
// Hook — programmatic control
function DevToolsController() {
const { isOpen, open, close, toggle, overrideCount, devtools } = useFlagKitDevTools({
theme: 'system',
});
return <button onClick={toggle}>DevTools ({overrideCount} overrides)</button>;
}Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| theme | 'light' \| 'dark' \| 'system' | 'system' | Color theme (follows OS preference in system mode) |
| buttonPosition | 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' | 'bottom-right' | Initial toggle button position |
| panelPosition | 'top' \| 'bottom' \| 'left' \| 'right' | 'right' | Which viewport edge the panel anchors to |
| initialSize | number | 420 | Initial panel size in pixels |
| minSize | number | 280 | Minimum panel size in pixels |
| maxSize | number | 800 | Maximum panel size in pixels |
| storagePrefix | string | 'flagkit' | localStorage key prefix |
| defaultOpen | boolean | false | Start with panel open |
| dashboardUrl | string | — | URL for "View in Dashboard" links |
| allowUrlOverrides | boolean | true (dev) / false (prod) | Allow URL-based override sharing |
| autoCleanStaleOverrides | boolean | false | Remove overrides for deleted flags on init |
| styleNonce | string | — | CSP nonce for injected <style> elements |
| shadowDOMTarget | ShadowRoot | — | Use an existing Shadow DOM root instead of creating one |
| shortcuts | boolean | true | Enable keyboard shortcuts |
| logErrors | boolean | true | Log DevTools internal errors to console |
Panels
DevTools includes six panels, switchable via tabs or number keys 1-6:
Flags Panel
Two-column master/detail layout for inspecting and overriding flags.
- Search — Filter flags by key name
- Filter — All, Starred, Boolean, String, Number, JSON, Overridden, Enabled, Disabled
- Sort — Key A-Z, Key Z-A, Updated, Type
- Star flags — Pin frequently used flags to the top
- Quick toggle — Inline boolean switch for fast toggling
- Override with expiry — Set overrides that auto-expire after a duration
- Bulk expire — Set all active overrides to expire in 30 minutes
- Clean stale — Remove overrides for flags no longer in the flag set
- Flag detail — Full evaluation result, metadata, history, dependencies, and bug report generator
Context Panel
View and modify the evaluation context used for flag targeting.
- JSON tree viewer — Collapsible view of the current context
- Edit context — JSON editor with validation
- Apply as override — Override context without changing the SDK context
- Set as SDK context — Directly update the SDK's evaluation context
- Personas — Save, load, and manage named context configurations
- PII detection — Warns when context contains fields that look like email, phone, SSN, or other sensitive data
Events Panel
Timeline of SDK events with filtering and export.
- Event types — Flag Evaluated, Flags Changed, Custom, Identify, Override Set/Cleared, SDK Error, Init Complete
- Filter — By event type or free-text search
- Pause/Resume — Freeze the timeline while inspecting
- Expand — Click any event to see its full JSON payload
- Export — Copy all events to clipboard as JSON
- Efficient append-only DOM updates with
requestAnimationFramebatching
Network Panel
Monitor all HTTP requests made by the SDK.
- Request list — Method, URL path, status code, duration, response size
- Status indicators — Green (2xx), yellow (3xx), red (4xx/5xx)
- Retry tracking — Retried requests show a retry icon and link to the original
- Request detail — Full URL, method, status, duration, size, timestamp, and error info
- Copy URL — Copy the full request URL to clipboard
Status Panel
SDK health dashboard showing runtime configuration and state.
- SDK Info — SDK version, DevTools version, session ID, ready state, streaming status
- Configuration — Polling interval, cache TTL, timeout, retries, offline mode, debug mode
- Cache — Flag count, cache enabled/disabled, persistence status, stale/offline badges
- Security — Strict PII mode, evaluation jitter, error sanitization status
Settings Panel
DevTools preferences and override management.
- Theme selector — Light, Dark, or System (persisted across sessions)
- Override presets — Save named sets of overrides and apply them later
- Import/Export — Copy overrides to clipboard as JSON, or paste to import
- Clear all — Remove all active overrides at once
Override Engine
The override engine intercepts flag evaluations and returns your override values instead of server values. Overrides are persisted to localStorage and sync across browser tabs.
const devtools = new FlagKitDevToolsCore(client, options);
devtools.mount(document.body);
// Programmatic override access
devtools.overrides.setOverride('feature-x', true, 'boolean');
devtools.overrides.setOverride('max-items', 50, 'number', Date.now() + 3600000); // expires in 1 hour
devtools.overrides.clearOverride('feature-x');
devtools.overrides.clearAllOverrides();
devtools.overrides.getAllOverrides(); // { [key]: { value, type, setAt, expiresAt? } }
devtools.overrides.count; // number of active overrides
// Subscribe to changes
const unsubscribe = devtools.overrides.onOverrideChange((overrides) => {
console.log('Overrides changed:', overrides);
});URL Override Sharing
Share flag overrides with teammates via URL. Overrides are encoded as base64url JSON in the __fk_overrides query parameter.
// Generate a shareable URL with current overrides
const url = devtools.generateShareUrl?.();
// → https://app.example.com/page?__fk_overrides=eyJmZWF0dXJlLXgiOns...
// Overrides are automatically applied when the page loads with the parameter
// The parameter is stripped from the URL after applyingCommand Palette
Press Cmd+K (Mac) or Ctrl+K (Windows/Linux) when DevTools is open to launch the command palette. Search across:
- Tabs — Navigate to any panel ("Go to Flags panel", "Go to Network panel", etc.)
- Commands — "Clear all overrides", "Export overrides", "Refresh flags"
- Flags — Search and jump to any flag by key name
Use arrow keys to navigate and Enter to select.
Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| Ctrl/Cmd + Shift + F | Toggle DevTools panel |
| Escape | Close DevTools panel |
| Ctrl/Cmd + K | Open/close command palette |
| 1 - 6 | Switch panels (Flags, Context, Events, Network, Status, Settings) |
Console API
When mounted, DevTools registers window.__FLAGKIT_DEVTOOLS__ for use in the browser console:
// Flag inspection
__FLAGKIT_DEVTOOLS__.getFlag('show-marketplace') // Full evaluation result
// Override management
__FLAGKIT_DEVTOOLS__.setOverride('my-flag', true, 'boolean')
__FLAGKIT_DEVTOOLS__.clearOverride('my-flag')
__FLAGKIT_DEVTOOLS__.clearAllOverrides()
__FLAGKIT_DEVTOOLS__.getAllOverrides()
// Panel control
__FLAGKIT_DEVTOOLS__.open()
__FLAGKIT_DEVTOOLS__.close()
__FLAGKIT_DEVTOOLS__.toggle()
__FLAGKIT_DEVTOOLS__.reset() // Fully re-mount DevTools
// Status
__FLAGKIT_DEVTOOLS__.getStatus()
// → { isOpen, mounted, overrideCount, activeTab, theme }
__FLAGKIT_DEVTOOLS__.version // DevTools core version
__FLAGKIT_DEVTOOLS__.sdkVersion // SDK version
__FLAGKIT_DEVTOOLS__.mounted // trueProgrammatic API
const devtools = new FlagKitDevToolsCore(client, options);
devtools.mount(document.body);
devtools.open();
devtools.close();
devtools.toggle();
devtools.isOpen; // boolean
devtools.setActiveTab('network'); // Switch to a panel
devtools.showToast('Hello!'); // Show a toast notification
devtools.recordEvent('custom', { foo: 1 }); // Add to events timeline
devtools.recordNetworkRequest({...}); // Add to network panel
devtools.getStore(); // Access internal state store
devtools.getClient(); // Access the SDK client
devtools.unmount(); // Clean up all resourcesDirectory Structure
src/devtools/
├── devtools.core.ts # Main orchestrator class
├── index.ts # Public barrel exports
├── constants/
│ ├── theme-tokens.constants.ts # CSS custom properties (light/dark themes)
│ ├── shell-styles.constants.ts # Toggle, panel, header, tabs, resize CSS
│ ├── flag-styles.constants.ts # Flag list, switch, detail panel CSS
│ ├── common-styles.constants.ts # Buttons, inputs, toast, toolbar CSS
│ └── devtools.constants.ts # Numeric limits and intervals
├── stores/
│ ├── override-engine.store.ts # Override persistence, expiry, cross-tab sync
│ ├── devtools-state.store.ts # Reactive state container
│ ├── presets.store.ts # Named override preset management
│ ├── personas.store.ts # Saved context personas with PII detection
│ ├── flag-history.store.ts # Flag value change history
│ └── starred-flags.store.ts # Starred/pinned flags
├── types/
│ └── devtools.types.ts # DevToolsOptions, TabId, TabDefinition
├── ui/
│ ├── shell/components/
│ │ ├── floating-toggle.component.ts # Draggable FAB with edge snap
│ │ ├── panel-header.component.ts # Panel header with title and close
│ │ ├── tab-bar.component.ts # Tab navigation bar
│ │ └── resize-handle.component.ts # Panel resize drag handle
│ ├── shared/components/
│ │ ├── json-tree.component.ts # Collapsible JSON viewer
│ │ ├── json-diff.component.ts # Side-by-side JSON diff
│ │ ├── search-input.component.ts # Debounced search input
│ │ └── toast.component.ts # Toast notification system
│ └── panels/
│ ├── components/
│ │ ├── command-palette.component.ts # Cmd+K fuzzy search
│ │ ├── events-panel.component.ts # Event timeline
│ │ ├── network-panel.component.ts # HTTP request inspector
│ │ ├── settings-panel.component.ts # Theme, presets, import/export
│ │ └── status-panel.component.ts # SDK health dashboard
│ ├── flags/components/
│ │ ├── flags-panel.component.ts # Master/detail flag browser
│ │ ├── flags-panel-helpers.util.ts # Filter, sort, format helpers
│ │ ├── flag-detail.component.ts # Flag detail view
│ │ ├── flag-dependencies.component.ts # Flag dependency graph
│ │ └── evaluation-trace.component.ts # Evaluation rule trace
│ └── context/components/
│ ├── context-panel.component.ts # Context editor with JSON tree
│ └── persona-selector.component.ts # Persona save/load/apply
└── utils/
├── styles.util.ts # CSS injection into Shadow DOM
├── dom.util.ts # DOM element helpers (el, setText, svg)
├── devtools-integrations.util.ts # Keyboard shortcuts, console API, network hooks
├── devtools-panel-layout.util.ts # Panel shell DOM construction
├── devtools-panel-factory.util.ts# Panel creation and active panel rendering
├── url-overrides.util.ts # URL-based override sharing (__fk_overrides)
├── persisted-state.util.ts # localStorage read/write with validation
├── sanitize.util.ts # XSS prevention and payload limits
├── accessibility.util.ts # Focus trap, screen reader announcements
├── draggable.util.ts # Pointer-event drag handler
├── edge-snap.util.ts # Snap-to-nearest-edge positioning
├── bug-report-formatter.util.ts # Markdown bug report generator
└── virtual-scroll.util.ts # Virtual scrolling for large listsProduction Safety
DevTools automatically skip mounting in production (NODE_ENV === 'production') unless allowUrlOverrides is explicitly set. Use tree-shaking-friendly conditional imports:
// The DevTools code won't be included in production bundles
if (import.meta.env.DEV) {
const { FlagKitDevToolsCore } = await import('@teracrafts/flagkit');
const devtools = new FlagKitDevToolsCore(client);
devtools.mount(document.body);
}API Reference
Flag Evaluation
// Boolean flags
client.getBooleanValue('feature', false);
// String flags
client.getStringValue('welcome-msg', 'Hello!');
// Number flags
client.getNumberValue('max-items', 10);
// JSON flags
client.getJsonValue('config', { enabled: false });
// Full evaluation result
client.evaluate('feature');
// Evaluate all flags
client.evaluateAll();
// Check if flag exists
client.hasFlag('feature');
// Get all flag keys
client.getAllFlagKeys();Context Management
// Set evaluation context
client.setContext({ userId: 'user-123', country: 'US' });
// Identify user
client.identify('user-123', { custom: { plan: 'premium' } });
// Reset to anonymous
client.reset();Event Tracking
// Track custom event
client.track('button_clicked', { button: 'signup' });
// Flush events immediately
await client.flush();Lifecycle
client.isReady(); // Check if ready
await client.waitForReady(); // Wait for ready
await client.refresh(); // Force refresh flags
await client.close(); // CleanupEvaluation Context
client.setContext({
userId: 'user-123',
email: '[email protected]',
country: 'US',
custom: { plan: 'premium' },
privateAttributes: ['email'], // Not sent to server
});Error Handling
import {
FlagKitError,
AuthenticationError,
NetworkError,
} from '@teracrafts/flagkit';
try {
await FlagKit.initialize({ apiKey: 'invalid' });
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof NetworkError) {
console.error('Network issue:', error.message);
}
}Browser Usage
<script src="https://unpkg.com/@teracrafts/flagkit"></script>
<script>
FlagKit.initialize({ apiKey: 'sdk_your_api_key' })
.then(client => {
const darkMode = client.getBooleanValue('dark-mode', false);
});
</script>Requirements
- Node.js 18+ (for server-side)
- Modern browser with
fetchsupport (for client-side)
License
MIT
