flagly-sdk
v1.5.0
Published
Feature flag SDK for Flagly (boolean flags only, with projectKey support)
Maintainers
Readme
Perfect bro 👍 you already have a full-featured README draft. I’ll just tweak & polish it so it’s consistent, professional, and ready for publishing with your flagly-sdk.
Here’s the updated README.md:
# 🚩 Flagly SDK (JavaScript / ESM)
Lightweight **Feature Flag SDK** for Flagly.
Supports **boolean flags** ✅ and **percentage rollouts (0–100%)** 🎯 with deterministic bucketing based on a `userKey`.
Works in **Node.js (18+)** and all modern browsers.
📦 npm: [`flagly-sdk`](https://www.npmjs.com/package/flagly-sdk) • ESM-only
---
## ✨ Features
- ✅ Boolean flags (ON / OFF)
- 🎯 Percent rollouts (10%, 25%, 60%, 100%)
- 🔒 Deterministic bucketing (FNV-1a hash) per `userKey`
- 🔁 Polling of your `/flags` endpoint (configurable)
- 🧭 Anonymous user helper (`getOrCreateAnonKey`) for browsers
- 🧱 No app DB access required — evaluation happens client-side
---
## 📦 Install
```bash
npm i flagly-sdk
# or
yarn add flagly-sdk
# or
pnpm add flagly-sdk⚠️ Requires Node.js 18+ (or any modern browser) because it’s ESM-only.
🚀 Quick Start
Node / Express
import FlaglyClient from "flagly-sdk";
const flagly = new FlaglyClient({
apiUrl: "https://api.your-flagly.com", // your backend’s /flags base
pollInterval: 30000 // 30s polling (default 5s)
});
await flagly.init();
app.get("/checkout", async (req, res) => {
const userKey = req.user?.id || req.user?.email || req.ip;
const enabled = flagly.isEnabled("newCheckout", { userKey });
res.send(enabled ? "🧪 New Checkout" : "🛒 Old Checkout");
});Browser
import FlaglyClient from "flagly-sdk";
const flagly = new FlaglyClient({ apiUrl: "https://api.your-flagly.com" });
await flagly.init();
const anonKey = FlaglyClient.getOrCreateAnonKey();
if (flagly.isEnabled("betaUI", { userKey: anonKey })) {
enableBetaUI();
} else {
enableClassicUI();
}🧩 API
new FlaglyClient(options)
| Option | Type | Default | Description |
| ---------------- | ------ | ------- | ------------------------------------------------------ |
| apiUrl | string | — | Base URL of your Flagly backend (must expose /flags) |
| pollInterval | number | 5000 | Auto-refresh interval in ms (0 = no polling) |
| requestHeaders | object | {} | Extra HTTP headers (e.g. auth tokens) |
Methods
await init()→ Fetches flags once and starts pollingstop()→ Stops background pollingisEnabled(flagName, context?)→ Returnstrue/false
isEnabled(flagName, context?)
flagName: string → the flag keycontext: optional →{ userKey?, userId?, email? }- Required for percent rollouts (ensures deterministic bucketing)
Behavior:
- Plain boolean → returns
true/false - Percent rollout → buckets user deterministically into 0–99
- No
userKeyfor percent flag → returnsfalse(safe default) - Unknown flag → returns
false
FlaglyClient.getOrCreateAnonKey(storage?)
Generates & persists a stable anonymous key for browsers.
Useful when users are not logged in. Defaults to localStorage.
🗂️ Expected /flags Response
{
"flags": [
{ "flagName": "quickFix", "value": true },
{ "flagName": "newCheckout","value": true, "percent": 10 },
{ "flagName": "betaUI", "value": true, "rolloutPercent": 25 }
]
}value: boolean — global ON/OFFpercent: number (0–100) — rollout %rolloutPercent: alias forpercent
Rules
- If
value = false→ OFF for everyone (percent ignored) - If
value = true&percent = 100→ ON for everyone - If no
percent→ plain boolean flag
🧠 How Percent Rollout Works
- Pass a stable userKey (userId, email, anon id)
- SDK hashes
userKey + flagName→ bucket in0..99 - If
bucket < percent→ user is in rollout group
✅ Same user always gets the same result ✅ Approx. percentage accuracy across large populations
🔬 Local Testing
import FlaglyClient from "flagly-sdk";
const client = new FlaglyClient({ apiUrl: "http://mock", pollInterval: 0 });
// Inject test flags
client._ingest({
flags: [
{ flagName: "newCheckout", value: true, percent: 10 },
{ flagName: "quickFix", value: true }
]
});
let on = 0;
for (let i = 0; i < 1000; i++) {
if (client.isEnabled("newCheckout", { userKey: `user_${i}` })) on++;
}
console.log("10% rollout →", (on/1000*100).toFixed(1), "%");🔐 Auth Headers
If /flags requires auth:
const flagly = new FlaglyClient({
apiUrl: "https://api.your-flagly.com",
requestHeaders: { Authorization: `Bearer ${token}` }
});⚠️ Edge Cases
- Network failure → keeps old cache, logs error
- Percent flag without
userKey→ returns false percentvalues are clamped to0..100
🧪 Versioning
- Non-breaking →
minorbump (e.g. 1.2 → 1.3) - Breaking changes →
majorbump
Publishing:
npm version minor
npm publish --access public📄 License
MIT © Upendra Dommaraju
🙋 FAQ
Q. Do I need access to my users’ DB?
A. No. Just pass a stable userKey. Evaluation is client-side.
Q. Can I use this in a browser SPA?
A. Yes. Use getOrCreateAnonKey() for anonymous visitors.
Q. What about A/B tests?
A. Create multiple flags (e.g. layoutA, layoutB). Rollout logic stays the same.
---
