@toglio/js 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 +235 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# @toglio/js
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@toglio/js)
|
|
4
|
+
[](https://github.com/rbragadev/toglio)
|
|
5
|
+
|
|
6
|
+
JavaScript/TypeScript SDK for [Toglio](https://toglio.io) — evaluate feature flags in any JS runtime: browser, Node.js, Deno, or edge functions.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @toglio/js
|
|
12
|
+
# or
|
|
13
|
+
yarn add @toglio/js
|
|
14
|
+
# or
|
|
15
|
+
pnpm add @toglio/js
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { FeatureFlagsClient } from '@toglio/js';
|
|
22
|
+
|
|
23
|
+
const client = new FeatureFlagsClient({
|
|
24
|
+
baseUrl: 'https://api.toglio.io',
|
|
25
|
+
organization: 'my-org',
|
|
26
|
+
project: 'my-project',
|
|
27
|
+
environment: 'production',
|
|
28
|
+
apiKey: process.env.TOGLIO_SDK_TOKEN!,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await client.initialize();
|
|
32
|
+
|
|
33
|
+
if (client.isEnabled('checkout.new-flow')) {
|
|
34
|
+
// new checkout
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## How It Works
|
|
39
|
+
|
|
40
|
+
1. `initialize()` loads the flag cache from `localStorage` (instant), then fetches fresh flags from the server.
|
|
41
|
+
2. All reads (`isEnabled`, `getString`, etc.) are **synchronous and sub-millisecond** — no `await` needed.
|
|
42
|
+
3. A background poller refreshes flags every 30 seconds by default.
|
|
43
|
+
4. If the server is unreachable, the SDK falls back to the local cache, then to the `defaults` you provided. **It never throws to your application.**
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const client = new FeatureFlagsClient({
|
|
49
|
+
// Required
|
|
50
|
+
baseUrl: 'https://api.toglio.io', // Your Toglio API URL
|
|
51
|
+
organization: 'my-org', // Organization slug
|
|
52
|
+
project: 'my-project', // Project slug
|
|
53
|
+
environment: 'production', // Environment slug (dev / staging / production)
|
|
54
|
+
apiKey: 'sdk_token_here', // SDK token from Settings → API Keys
|
|
55
|
+
|
|
56
|
+
// Optional
|
|
57
|
+
userId: 'user_123', // End-user ID — required for gradual rollout & targeting
|
|
58
|
+
attributes: { // End-user attributes for targeting rules
|
|
59
|
+
city: 'New York',
|
|
60
|
+
plan: 'pro',
|
|
61
|
+
role: 'admin',
|
|
62
|
+
},
|
|
63
|
+
pollingInterval: 30_000, // Refresh interval in ms (0 = disable polling)
|
|
64
|
+
defaults: { // Fallback values when offline or flag not found
|
|
65
|
+
'checkout.new-flow': false,
|
|
66
|
+
'pricing.variant': 'control',
|
|
67
|
+
},
|
|
68
|
+
onChange: (changes) => { // Called after each poll when flags change
|
|
69
|
+
console.log('Flags updated:', changes);
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## API Reference
|
|
75
|
+
|
|
76
|
+
### `initialize(): Promise<void>`
|
|
77
|
+
|
|
78
|
+
Fetches flags from the server and starts the background poller. Call once at app startup before reading any flags.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
await client.initialize();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `isEnabled(key, defaultValue?): boolean`
|
|
85
|
+
|
|
86
|
+
Returns `true` if the flag is enabled. Evaluates targeting rules if `userId` is set.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
client.isEnabled('dark-mode'); // false if not found
|
|
90
|
+
client.isEnabled('dark-mode', true); // true if not found
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `getString(key, defaultValue?): string`
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
client.getString('ui.theme', 'light'); // 'dark' | 'light' | ...
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `getNumber(key, defaultValue?): number`
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
client.getNumber('cart.max-items', 10); // 5 | 10 | ...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `getVariant(key, defaultValue?): string`
|
|
106
|
+
|
|
107
|
+
Returns the active variant key for a `VARIANT` type flag. Evaluates targeting rules if `userId` is set.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
client.getVariant('pricing-page', 'control'); // 'control' | 'variant_a' | 'variant_b'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### `getVariantPayload(key): unknown`
|
|
114
|
+
|
|
115
|
+
Returns the JSON payload attached to the active variant, or `null`.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const payload = client.getVariantPayload('pricing-page');
|
|
119
|
+
// { cta: 'Start free trial', color: '#4f46e5' }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `getAll(): FlagMap`
|
|
123
|
+
|
|
124
|
+
Returns all resolved flags as a plain object.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const flags = client.getAll();
|
|
128
|
+
// { 'dark-mode': true, 'pricing-page': 'variant_a', ... }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `getStatus(): ClientStatus`
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const { initialized, lastFetchAt, fetchError } = client.getStatus();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `addOnChange(callback): () => void`
|
|
138
|
+
|
|
139
|
+
Subscribes to flag changes. Returns an unsubscribe function.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const unsubscribe = client.addOnChange((changes) => {
|
|
143
|
+
changes.forEach(({ key, previous, current }) => {
|
|
144
|
+
console.log(`${key}: ${previous} → ${current}`);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Later:
|
|
149
|
+
unsubscribe();
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `destroy(): void`
|
|
153
|
+
|
|
154
|
+
Stops the background poller. Call when shutting down the app.
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
client.destroy();
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Targeting & Rollout
|
|
161
|
+
|
|
162
|
+
### Gradual Rollout
|
|
163
|
+
|
|
164
|
+
Set `userId` to enable deterministic rollout. The SDK sends it as `X-Toglio-User-Id` on every request. The server uses `flagKey + userId` to place users in stable buckets.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const client = new FeatureFlagsClient({
|
|
168
|
+
// ...
|
|
169
|
+
userId: currentUser.id, // stable identifier — not related to Toglio admin users
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
- `rolloutPercentage = 100`: all users get the flag.
|
|
174
|
+
- `rolloutPercentage = 0`: no users get the flag.
|
|
175
|
+
- `1–99`: deterministic bucket per user.
|
|
176
|
+
|
|
177
|
+
### Targeting Rules
|
|
178
|
+
|
|
179
|
+
Set `attributes` to enable client-side targeting rule evaluation. Rules are created in the Toglio dashboard and shipped in the SDK response.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const client = new FeatureFlagsClient({
|
|
183
|
+
// ...
|
|
184
|
+
userId: currentUser.id,
|
|
185
|
+
attributes: {
|
|
186
|
+
city: currentUser.city, // string
|
|
187
|
+
tags: currentUser.tags, // string[]
|
|
188
|
+
plan: currentUser.plan,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Supported operators: `IN`, `NOT_IN`, `EQUALS`, `NOT_EQUALS`, `CONTAINS`, `MATCHES_REGEX`.
|
|
194
|
+
|
|
195
|
+
## SSR / Server-Side Usage
|
|
196
|
+
|
|
197
|
+
The SDK uses `localStorage` for caching when available and silently skips it in environments where it is not (Node.js, edge runtimes). Everything else works the same.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// pages/index.tsx (Next.js)
|
|
201
|
+
export async function getServerSideProps() {
|
|
202
|
+
const client = new FeatureFlagsClient({ /* ... */ });
|
|
203
|
+
await client.initialize();
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
props: {
|
|
207
|
+
showBanner: client.isEnabled('homepage.banner'),
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
For server-side usage, set `pollingInterval: 0` to disable the poller and call `client.destroy()` after reading flags.
|
|
214
|
+
|
|
215
|
+
## TypeScript
|
|
216
|
+
|
|
217
|
+
All types are exported:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import type {
|
|
221
|
+
FeatureFlagsClientConfig,
|
|
222
|
+
FlagMap,
|
|
223
|
+
FlagValue,
|
|
224
|
+
FlagChange,
|
|
225
|
+
ClientStatus,
|
|
226
|
+
} from '@toglio/js';
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## React
|
|
230
|
+
|
|
231
|
+
For React projects, use [`@toglio/react`](https://www.npmjs.com/package/@toglio/react) which provides a context Provider and hooks (`useFlag`, `useVariant`, `useFlagsReady`).
|
|
232
|
+
|
|
233
|
+
## License
|
|
234
|
+
|
|
235
|
+
MIT
|