flagcraft 0.1.0 โ 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# ๐ฆ FlagCraft SDK (`flagcraft`)
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/flagcraft)
|
|
4
|
+
[](https://bundlephobia.com/package/flagcraft)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
|
|
8
|
+
The official, ultra-fast, universal **TypeScript / JavaScript SDK** for [FlagCraft](https://github.com/Akash-1808/feature-flag), engineered for high-concurrency environments, zero-latency local evaluations, conditional ETag polling, and fail-open resilience.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## โจ Why FlagCraft SDK?
|
|
13
|
+
|
|
14
|
+
Standard feature flag SDKs make blocking HTTP requests on every evaluation or download massive JSON payloads repeatedly. **`flagcraft`** is built differently:
|
|
15
|
+
|
|
16
|
+
- **โก Zero-Latency Local Evaluations (`0ms`)**: Rulesets are stored in an ultra-fast in-memory cache (`InMemoryCache`). Calling `flagcraft.evaluate()` executes entirely in local CPU memory without blocking network calls or disk I/O.
|
|
17
|
+
- **๐ ETag Conditional Polling (`>95% Bandwidth Saved`)**: When background polling checks for updates, the SDK sends an `If-None-Match: W/"hash"` header. If no flag rules changed in the management dashboard, the FlagCraft server returns a zero-byte **`HTTP 304 Not Modified`** response instantly.
|
|
18
|
+
- **๐ฏ Deterministic MurmurHash3 Bucketing**: When rolling out a feature to `30%` of users (`rollout_percentage = 30`), `flagcraft` calculates `MurmurHash3(flagKey + userId) % 100`. This guarantees the exact same user gets the identical experience across all distributed servers with **zero UI flickering**.
|
|
19
|
+
- **๐ก๏ธ Fail-Open & Tiered Fallback Cache**: If your central FlagCraft API or database goes offline during a major cloud outage, the SDK falls back to cached local rules or your safe code defaults (`isEnabled = false`). Your application **never crashes** due to flag evaluation failures.
|
|
20
|
+
- **๐ Auto-Rollback Telemetry**: Automatically batches and reports evaluation metrics and error cohorts back to FlagCraft (`MetricsWatcher`), allowing automated circuit breakers to trip within seconds if an anomaly occurs.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## ๐ฆ Installation
|
|
25
|
+
|
|
26
|
+
Install `flagcraft` via your preferred package manager:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install flagcraft
|
|
30
|
+
```
|
|
31
|
+
```bash
|
|
32
|
+
yarn add flagcraft
|
|
33
|
+
```
|
|
34
|
+
```bash
|
|
35
|
+
pnpm add flagcraft
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ๐ Quickstart Guide
|
|
41
|
+
|
|
42
|
+
### 1. Initialize the SDK
|
|
43
|
+
Create a single instance of `FlagCraft` during your server or application startup:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { FlagCraft } from 'flagcraft';
|
|
47
|
+
|
|
48
|
+
// Initialize with your Environment API Key from FlagCraft Dashboard
|
|
49
|
+
const flagcraft = new FlagCraft({
|
|
50
|
+
apiKey: 'server_abc123_your_secret_key', // Or client_... for frontend apps
|
|
51
|
+
baseUrl: 'http://localhost:3001', // Your running FlagCraft API server
|
|
52
|
+
pollingInterval: 30000, // Check for rule changes every 30 seconds
|
|
53
|
+
fallbackFlags: {
|
|
54
|
+
'new-ai-search': false, // Safe defaults if API is unreachable on initial boot
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Start the background ETag polling engine
|
|
59
|
+
await flagcraft.init();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### 2. Evaluate Feature Flags Instantly (`0ms` Latency)
|
|
65
|
+
|
|
66
|
+
Pass the flag key and targeting context (`userId`, `attributes`):
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Example: Inside an Express, Next.js, or Fastify route controller
|
|
70
|
+
app.get('/search', async (req, res) => {
|
|
71
|
+
const userId = req.headers['x-user-id'] || 'guest_user';
|
|
72
|
+
|
|
73
|
+
// Instant local memory check (Zero network latency!)
|
|
74
|
+
const useAiSearch = flagcraft.evaluate('new-ai-search', {
|
|
75
|
+
userId: userId,
|
|
76
|
+
attributes: {
|
|
77
|
+
country: 'US',
|
|
78
|
+
plan: 'pro',
|
|
79
|
+
appVersion: '2.4.0',
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (useAiSearch) {
|
|
84
|
+
return res.json({ status: 'success', engine: 'AI Search Engine v2 โจ' });
|
|
85
|
+
} else {
|
|
86
|
+
return res.json({ status: 'success', engine: 'Standard SQL Search Engine' });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### 3. Evaluate All Flags for a User (e.g., Initializing Frontend State)
|
|
94
|
+
|
|
95
|
+
If you need to return all flag states for a specific user in a single request:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
app.get('/api/user/flags', (req, res) => {
|
|
99
|
+
const allFlags = flagcraft.evaluateFlags({
|
|
100
|
+
userId: req.query.userId as string,
|
|
101
|
+
attributes: { country: 'UK' },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Returns: { 'new-ai-search': true, 'dark-mode-v2': false, ... }
|
|
105
|
+
res.json(allFlags);
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## โ๏ธ Configuration Options
|
|
112
|
+
|
|
113
|
+
| Option | Type | Default | Description |
|
|
114
|
+
| :--- | :--- | :--- | :--- |
|
|
115
|
+
| **`apiKey`** *(required)* | `string` | โ | Your FlagCraft environment API key (`server_...` or `client_...`). |
|
|
116
|
+
| **`baseUrl`** | `string` | `'http://localhost:3001'` | The HTTP URL where your FlagCraft control-plane API is deployed. |
|
|
117
|
+
| **`pollingInterval`** | `number` | `30000` | Frequency in milliseconds for ETag background polling (`min: 1000ms`). |
|
|
118
|
+
| **`fallbackFlags`** | `Record<string, boolean>` | `{}` | Static fallbacks used before initial fetch or during network outages. |
|
|
119
|
+
| **`onError`** | `(err: Error) => void` | `console.error` | Custom error callback for background polling failures or network timeouts. |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## ๐ API Reference
|
|
124
|
+
|
|
125
|
+
### `flagcraft.init(): Promise<void>`
|
|
126
|
+
Boots the background `Poller` and performs the initial ruleset fetch. Resolves immediately when the initial ruleset is loaded into the `InMemoryCache` or gracefully falls back to `fallbackFlags`.
|
|
127
|
+
|
|
128
|
+
### `flagcraft.evaluate(flagKey: string, context?: EvaluationContext): boolean`
|
|
129
|
+
Evaluates a single feature flag synchronously using the cached ruleset.
|
|
130
|
+
- **`flagKey`**: The unique identifier of the flag (e.g., `'new-checkout'`).
|
|
131
|
+
- **`context.userId`**: Required for percentage-based rollouts to ensure deterministic hashing.
|
|
132
|
+
- **`context.attributes`**: Key-value pairs (`{ country: 'US', tier: 'gold' }`) evaluated against custom targeting rules (`CONTAINS`, `EQUALS`, `IN`, `GREATER_THAN`).
|
|
133
|
+
|
|
134
|
+
### `flagcraft.evaluateFlags(context?: EvaluationContext): Record<string, boolean>`
|
|
135
|
+
Evaluates every active feature flag in the environment for the provided context and returns a dictionary mapping flag keys to boolean outcomes.
|
|
136
|
+
|
|
137
|
+
### `flagcraft.close(): void`
|
|
138
|
+
Stops background polling intervals and clears the memory cache. Call this during graceful server shutdown (`SIGTERM` / `SIGINT`).
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## ๐งช Advanced: ETag Polling Under the Hood
|
|
143
|
+
|
|
144
|
+
When `flagcraft` polls your FlagCraft server (`GET /sdk/flags`), it passes the MD5 hash of the active ruleset inside the `If-None-Match` HTTP header:
|
|
145
|
+
|
|
146
|
+
```http
|
|
147
|
+
GET /sdk/flags HTTP/1.1
|
|
148
|
+
Host: localhost:3001
|
|
149
|
+
x-api-key: server_e24dfb98_secret
|
|
150
|
+
If-None-Match: W/"a9f8c7e6b5d4c3b2a1"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
If the ruleset hasn't changed since the last fetch, the server replies with:
|
|
154
|
+
```http
|
|
155
|
+
HTTP/1.1 304 Not Modified
|
|
156
|
+
```
|
|
157
|
+
This design allows thousands of distributed servers or serverless containers to poll frequently (`e.g., every 5-10s`) with **near-zero CPU and network overhead**.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## ๐ License
|
|
162
|
+
|
|
163
|
+
Distributed under the MIT License. Built with โค๏ธ for enterprise reliability and speed.
|
package/package.json
CHANGED