@dr-sentry/react 1.0.0
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 +258 -0
- package/dist/cjs/client.d.ts +121 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +483 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/context.d.ts +10 -0
- package/dist/cjs/context.d.ts.map +1 -0
- package/dist/cjs/context.js +14 -0
- package/dist/cjs/context.js.map +1 -0
- package/dist/cjs/hooks.d.ts +86 -0
- package/dist/cjs/hooks.d.ts.map +1 -0
- package/dist/cjs/hooks.js +186 -0
- package/dist/cjs/hooks.js.map +1 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/local-evaluator.d.ts +12 -0
- package/dist/cjs/local-evaluator.d.ts.map +1 -0
- package/dist/cjs/local-evaluator.js +44 -0
- package/dist/cjs/local-evaluator.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/provider.d.ts +24 -0
- package/dist/cjs/provider.d.ts.map +1 -0
- package/dist/cjs/provider.js +97 -0
- package/dist/cjs/provider.js.map +1 -0
- package/dist/cjs/types.d.ts +163 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +9 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/client.d.ts +121 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +479 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/context.d.ts +10 -0
- package/dist/esm/context.d.ts.map +1 -0
- package/dist/esm/context.js +11 -0
- package/dist/esm/context.js.map +1 -0
- package/dist/esm/hooks.d.ts +86 -0
- package/dist/esm/hooks.d.ts.map +1 -0
- package/dist/esm/hooks.js +178 -0
- package/dist/esm/hooks.js.map +1 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/local-evaluator.d.ts +12 -0
- package/dist/esm/local-evaluator.d.ts.map +1 -0
- package/dist/esm/local-evaluator.js +41 -0
- package/dist/esm/local-evaluator.js.map +1 -0
- package/dist/esm/provider.d.ts +24 -0
- package/dist/esm/provider.d.ts.map +1 -0
- package/dist/esm/provider.js +94 -0
- package/dist/esm/provider.js.map +1 -0
- package/dist/esm/types.d.ts +163 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +8 -0
- package/dist/esm/types.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# @deploysentry/react
|
|
2
|
+
|
|
3
|
+
Official React SDK for the DeploySentry feature flag platform. Provides React hooks and a context provider for evaluating feature flags with real-time SSE updates.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @deploysentry/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
React 18 or later is required as a peer dependency.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
Wrap your application with `DeploySentryProvider` and use hooks anywhere in the tree:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { DeploySentryProvider, useFlag } from '@deploysentry/react';
|
|
19
|
+
|
|
20
|
+
function App() {
|
|
21
|
+
return (
|
|
22
|
+
<DeploySentryProvider
|
|
23
|
+
apiKey="ds_live_abc123"
|
|
24
|
+
baseURL="https://api.dr-sentry.com"
|
|
25
|
+
environment="production"
|
|
26
|
+
project="my-app"
|
|
27
|
+
application="my-web-app"
|
|
28
|
+
user={{ id: 'user-42' }}
|
|
29
|
+
>
|
|
30
|
+
<MyComponent />
|
|
31
|
+
</DeploySentryProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function MyComponent() {
|
|
36
|
+
const showBanner = useFlag('show-banner', false);
|
|
37
|
+
|
|
38
|
+
if (!showBanner) return null;
|
|
39
|
+
return <div>New feature banner!</div>;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Provider Props
|
|
44
|
+
|
|
45
|
+
| Prop | Type | Required | Description |
|
|
46
|
+
|---------------|--------------|----------|--------------------------------------------------|
|
|
47
|
+
| `apiKey` | `string` | Yes | API key for authenticating with DeploySentry. |
|
|
48
|
+
| `baseURL` | `string` | Yes | Base URL of the DeploySentry API. |
|
|
49
|
+
| `environment` | `string` | Yes | Environment identifier (e.g. `"production"`). |
|
|
50
|
+
| `project` | `string` | Yes | Project identifier. |
|
|
51
|
+
| `application` | `string` | Yes | Application identifier |
|
|
52
|
+
| `user` | `UserContext` | No | User context for targeting rules. |
|
|
53
|
+
| `children` | `ReactNode` | Yes | React children. |
|
|
54
|
+
| `mode` | `string` | No | SDK mode: `server`, `file`, or `server-with-fallback`. |
|
|
55
|
+
| `flagData` | `object` | No | Pre-loaded flag config for file/fallback mode. |
|
|
56
|
+
|
|
57
|
+
## Offline / File Mode
|
|
58
|
+
|
|
59
|
+
For offline use or testing, pass pre-loaded flag config via the `flagData` prop:
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import flagConfig from './.deploysentry/flags.json';
|
|
63
|
+
|
|
64
|
+
<DeploySentryProvider
|
|
65
|
+
apiKey="not-used"
|
|
66
|
+
baseURL=""
|
|
67
|
+
environment="staging"
|
|
68
|
+
project="my-project"
|
|
69
|
+
application="my-web-app"
|
|
70
|
+
mode="file"
|
|
71
|
+
flagData={flagConfig}
|
|
72
|
+
>
|
|
73
|
+
<App />
|
|
74
|
+
</DeploySentryProvider>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Modes
|
|
78
|
+
|
|
79
|
+
| Mode | Behavior |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `server` (default) | API calls + SSE streaming |
|
|
82
|
+
| `file` | Use `flagData` prop, evaluate locally. No server contact. |
|
|
83
|
+
| `server-with-fallback` | Try server first. If unavailable, use `flagData` as fallback. |
|
|
84
|
+
|
|
85
|
+
Export the config from the dashboard (App Settings → Export flags.yaml), then convert to JSON or import with a YAML plugin.
|
|
86
|
+
|
|
87
|
+
## Hooks
|
|
88
|
+
|
|
89
|
+
### `useFlag(key, defaultValue)`
|
|
90
|
+
|
|
91
|
+
Returns the resolved flag value. Falls back to `defaultValue` while loading or if the flag does not exist.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
const isEnabled = useFlag('dark-mode', false);
|
|
95
|
+
const variant = useFlag('checkout-flow', 'control');
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `useFlagDetail(key)`
|
|
99
|
+
|
|
100
|
+
Returns detailed evaluation information including metadata.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
const { value, enabled, metadata, loading } = useFlagDetail('new-checkout');
|
|
104
|
+
|
|
105
|
+
// metadata contains: category, purpose, owners, isPermanent, expiresAt, tags
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `useFlagsByCategory(category)`
|
|
109
|
+
|
|
110
|
+
Returns all flags matching the given category.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
const experiments = useFlagsByCategory('experiment');
|
|
114
|
+
const releases = useFlagsByCategory('release');
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Categories: `'release'` | `'feature'` | `'experiment'` | `'ops'` | `'permission'`
|
|
118
|
+
|
|
119
|
+
### `useExpiredFlags()`
|
|
120
|
+
|
|
121
|
+
Returns all non-permanent flags whose `expiresAt` date is in the past. Useful for admin dashboards.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
const expired = useExpiredFlags();
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `useDispatch(operation)`
|
|
128
|
+
|
|
129
|
+
Returns the resolved handler for a registered operation based on current flag state. See [Register / Dispatch Pattern](#register--dispatch-pattern) below.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
const checkout = useDispatch<() => Promise<void>>('checkout');
|
|
133
|
+
await checkout();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### `useDeploySentry()`
|
|
137
|
+
|
|
138
|
+
Returns the raw `DeploySentryClient` instance for advanced use-cases.
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
const client = useDeploySentry();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Register / Dispatch Pattern
|
|
145
|
+
|
|
146
|
+
The register/dispatch pattern centralizes all flag-gated behavior in one place instead of scattering `if/else` checks across components.
|
|
147
|
+
|
|
148
|
+
### Setup (single-point registration)
|
|
149
|
+
|
|
150
|
+
Create one registration file that runs at app initialization:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// src/flags/registrations.ts
|
|
154
|
+
import type { DeploySentryClient } from '@deploysentry/react';
|
|
155
|
+
import { legacySearch, vectorSearch } from '../search';
|
|
156
|
+
import { classicCheckout, newCheckout } from '../checkout';
|
|
157
|
+
|
|
158
|
+
export function registerFlags(client: DeploySentryClient) {
|
|
159
|
+
// Search — default handler, then flag-gated override
|
|
160
|
+
client.register('search', legacySearch);
|
|
161
|
+
client.register('search', vectorSearch, 'vector-search-v2');
|
|
162
|
+
|
|
163
|
+
// Checkout
|
|
164
|
+
client.register('checkout', classicCheckout);
|
|
165
|
+
client.register('checkout', newCheckout, 'new-checkout-flow');
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Call `registerFlags(client)` after the client initializes (e.g. in the provider setup or an app-level effect).
|
|
170
|
+
|
|
171
|
+
### Usage in components
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { useDispatch } from '@deploysentry/react';
|
|
175
|
+
|
|
176
|
+
function SearchBar() {
|
|
177
|
+
const search = useDispatch<(query: string) => Promise<Results>>('search');
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<input onChange={(e) => search(e.target.value).then(setResults)} />
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### How it works
|
|
186
|
+
|
|
187
|
+
1. **`client.register(operation, handler, flagKey?)`** — Register a handler for a named operation. With `flagKey`, it's only selected when that flag is enabled. Without `flagKey`, it's the default fallback.
|
|
188
|
+
2. **`useDispatch(operation)`** — Returns the first registered handler whose flag is enabled, or the default handler. The component never knows about flags.
|
|
189
|
+
|
|
190
|
+
### Why single-point registration
|
|
191
|
+
|
|
192
|
+
- One file shows every flag-gated behavior in the app
|
|
193
|
+
- Easy auditing — search for a flag key and find every behavior it controls
|
|
194
|
+
- Simple cleanup when a flag is retired (remove the registration, keep the handler)
|
|
195
|
+
- LLMs and code review tools can read one file to understand all flag-gated behavior
|
|
196
|
+
|
|
197
|
+
## Real-Time Updates
|
|
198
|
+
|
|
199
|
+
The provider automatically opens an SSE connection to receive flag updates in real time. When a flag changes on the server, all components consuming that flag re-render immediately. The connection reconnects automatically with exponential backoff if it drops.
|
|
200
|
+
|
|
201
|
+
## SSR Compatibility
|
|
202
|
+
|
|
203
|
+
Hooks return default/empty values during server-side rendering. Flags are fetched client-side after the provider mounts.
|
|
204
|
+
|
|
205
|
+
## Types
|
|
206
|
+
|
|
207
|
+
All types are exported from the package:
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
import type {
|
|
211
|
+
Flag,
|
|
212
|
+
FlagCategory,
|
|
213
|
+
FlagDetail,
|
|
214
|
+
FlagMetadata,
|
|
215
|
+
ProviderProps,
|
|
216
|
+
UserContext,
|
|
217
|
+
} from '@deploysentry/react';
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Authentication
|
|
221
|
+
|
|
222
|
+
All requests use an API key passed in the `Authorization` header:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
Authorization: ApiKey <your-api-key>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Pass the key via the provider's `apiKey` prop. The SDK sets the header automatically.
|
|
229
|
+
|
|
230
|
+
### Session Consistency
|
|
231
|
+
|
|
232
|
+
Bind evaluations to a session so the server caches results for a consistent user experience:
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
<DeploySentryProvider
|
|
236
|
+
apiKey="ds_key_xxxxxxxxxxxx"
|
|
237
|
+
baseURL="https://api.dr-sentry.com"
|
|
238
|
+
environment="production"
|
|
239
|
+
project="my-app"
|
|
240
|
+
application="my-web-app"
|
|
241
|
+
sessionId={`user:${userId}`}
|
|
242
|
+
>
|
|
243
|
+
<App />
|
|
244
|
+
</DeploySentryProvider>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
const client = useDeploySentry();
|
|
249
|
+
await client.refreshSession();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
- The session ID is sent as an `X-DeploySentry-Session` header on every request.
|
|
253
|
+
- The server caches evaluation results per session for 30 minutes (sliding TTL).
|
|
254
|
+
- Omit the session ID to always get fresh evaluations on each request.
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
Apache-2.0
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { EvaluationContext, Flag, FlagConfig, FlagDetail, FlagMetadata, UserContext } from './types';
|
|
2
|
+
/** Listener callback invoked whenever the flag store is updated. */
|
|
3
|
+
export type FlagChangeListener = () => void;
|
|
4
|
+
/**
|
|
5
|
+
* Lightweight HTTP + SSE client that manages the local flag store.
|
|
6
|
+
*
|
|
7
|
+
* This client is designed for browser environments. It uses the native
|
|
8
|
+
* `fetch` and `EventSource` APIs, so no polyfills are required in modern
|
|
9
|
+
* browsers.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DeploySentryClient {
|
|
12
|
+
private readonly apiKey;
|
|
13
|
+
private readonly baseURL;
|
|
14
|
+
private readonly environment;
|
|
15
|
+
private readonly project;
|
|
16
|
+
private readonly application;
|
|
17
|
+
private readonly sessionId;
|
|
18
|
+
private readonly mode;
|
|
19
|
+
private flagConfig;
|
|
20
|
+
private user;
|
|
21
|
+
/** In-memory flag store keyed by flag key. */
|
|
22
|
+
private readonly flags;
|
|
23
|
+
/** Registry of operation handlers for the register/dispatch pattern. */
|
|
24
|
+
private registry;
|
|
25
|
+
/** Subscribed listeners notified on any flag change. */
|
|
26
|
+
private readonly listeners;
|
|
27
|
+
/** Active SSE connection, if any. */
|
|
28
|
+
private eventSource;
|
|
29
|
+
/** Whether the initial fetch has completed at least once. */
|
|
30
|
+
private initialised;
|
|
31
|
+
/** Whether the client has been destroyed. */
|
|
32
|
+
private destroyed;
|
|
33
|
+
/** Retry state for SSE reconnection. */
|
|
34
|
+
private sseRetryTimer;
|
|
35
|
+
private sseRetryCount;
|
|
36
|
+
private static readonly SSE_MAX_RETRY_DELAY_MS;
|
|
37
|
+
constructor(options: {
|
|
38
|
+
apiKey: string;
|
|
39
|
+
baseURL: string;
|
|
40
|
+
environment: string;
|
|
41
|
+
project: string;
|
|
42
|
+
application: string;
|
|
43
|
+
user?: UserContext;
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
mode?: 'server' | 'file' | 'server-with-fallback';
|
|
46
|
+
flagConfig?: FlagConfig;
|
|
47
|
+
});
|
|
48
|
+
/** Fetch all flags from the API and start listening for SSE updates. */
|
|
49
|
+
init(): Promise<void>;
|
|
50
|
+
/** Stop the SSE connection and release resources. */
|
|
51
|
+
destroy(): void;
|
|
52
|
+
/** Clear the local flag store and re-fetch all flags from the API. */
|
|
53
|
+
refreshSession(): Promise<void>;
|
|
54
|
+
/** Update the user context and re-fetch flags. */
|
|
55
|
+
identify(user: UserContext | undefined): Promise<void>;
|
|
56
|
+
/** Subscribe to flag changes. Returns an unsubscribe function. */
|
|
57
|
+
subscribe(listener: FlagChangeListener): () => void;
|
|
58
|
+
/** True once the first successful fetch has completed. */
|
|
59
|
+
get isInitialised(): boolean;
|
|
60
|
+
/** Return the stored {@link Flag} for the given key, or `undefined`. */
|
|
61
|
+
getFlag(key: string): Flag | undefined;
|
|
62
|
+
/** Return all stored flags. */
|
|
63
|
+
getAllFlags(): Flag[];
|
|
64
|
+
/** Build a {@link FlagMetadata} object for a stored flag. */
|
|
65
|
+
getFlagMetadata(key: string): FlagMetadata | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Register a handler for the given operation name.
|
|
68
|
+
*
|
|
69
|
+
* When `flagKey` is provided the handler is used only when that flag is
|
|
70
|
+
* enabled. Omit `flagKey` to register the default (fallback) handler.
|
|
71
|
+
*/
|
|
72
|
+
register<T extends (...args: any[]) => any>(operation: string, handler: T, flagKey?: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Dispatch the appropriate handler for the given operation.
|
|
75
|
+
*
|
|
76
|
+
* Returns the first registered handler whose flag is enabled. Falls back
|
|
77
|
+
* to the default (no-flagKey) handler if no flagged handler matches.
|
|
78
|
+
*
|
|
79
|
+
* @throws If no handlers are registered for the operation.
|
|
80
|
+
* @throws If no flagged handler matches and no default is registered.
|
|
81
|
+
*/
|
|
82
|
+
dispatch<T extends (...args: any[]) => any>(operation: string, _context?: EvaluationContext): T;
|
|
83
|
+
/**
|
|
84
|
+
* Evaluate a boolean flag from the in-memory store.
|
|
85
|
+
*
|
|
86
|
+
* No API call is made -- the value comes from the flags already fetched
|
|
87
|
+
* via {@link init} and kept up-to-date by SSE.
|
|
88
|
+
*/
|
|
89
|
+
boolValue(key: string, defaultValue: boolean): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Evaluate a string flag from the in-memory store.
|
|
92
|
+
*/
|
|
93
|
+
stringValue(key: string, defaultValue: string): string;
|
|
94
|
+
/**
|
|
95
|
+
* Evaluate a number flag from the in-memory store.
|
|
96
|
+
*
|
|
97
|
+
* TypeScript has no separate `int` type -- this returns `number` and is
|
|
98
|
+
* the idiomatic equivalent of `intValue` / `floatValue` in other SDKs.
|
|
99
|
+
*/
|
|
100
|
+
numberValue(key: string, defaultValue: number): number;
|
|
101
|
+
/**
|
|
102
|
+
* Evaluate a JSON (object) flag from the in-memory store.
|
|
103
|
+
*/
|
|
104
|
+
jsonValue<T extends object = object>(key: string, defaultValue: T): T;
|
|
105
|
+
/**
|
|
106
|
+
* Return the full evaluation detail for a flag from the in-memory store.
|
|
107
|
+
*
|
|
108
|
+
* Returns `{ value, enabled, metadata, loading }` matching the
|
|
109
|
+
* {@link FlagDetail} interface used by the `useFlagDetail` hook.
|
|
110
|
+
*/
|
|
111
|
+
detail(key: string): FlagDetail;
|
|
112
|
+
private get headers();
|
|
113
|
+
private buildQueryParams;
|
|
114
|
+
private fetchFlags;
|
|
115
|
+
private connectSSE;
|
|
116
|
+
private handleSSEMessage;
|
|
117
|
+
private disconnectSSE;
|
|
118
|
+
private scheduleReconnect;
|
|
119
|
+
private emit;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|