@ops-ai/react-router-toggly 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/CHANGELOG.md +17 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/client.cjs +832 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +603 -0
- package/dist/client.d.ts +603 -0
- package/dist/client.js +787 -0
- package/dist/client.js.map +1 -0
- package/dist/server.cjs +2324 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +645 -0
- package/dist/server.d.ts +645 -0
- package/dist/server.js +2294 -0
- package/dist/server.js.map +1 -0
- package/dist/telemetry/grpc.cjs +159 -0
- package/dist/telemetry/grpc.cjs.map +1 -0
- package/dist/telemetry/grpc.d.cts +29 -0
- package/dist/telemetry/grpc.d.ts +29 -0
- package/dist/telemetry/grpc.js +149 -0
- package/dist/telemetry/grpc.js.map +1 -0
- package/package.json +107 -0
- package/proto/google/protobuf/timestamp.proto +17 -0
- package/proto/metrics.proto +54 -0
- package/proto/usage.proto +49 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
import { LocalGate } from '@ops-ai/toggly-local-gates';
|
|
2
|
+
import { EvaluatedDefinitions, TogglyEntityContext } from '@ops-ai/toggly-hooks-types';
|
|
3
|
+
export { TogglyEntityContext, normalizeEntityContext, registerContext } from '@ops-ai/toggly-hooks-types';
|
|
4
|
+
import * as react from 'react';
|
|
5
|
+
import { ReactNode, ReactElement } from 'react';
|
|
6
|
+
|
|
7
|
+
interface UsageSender {
|
|
8
|
+
sendStats(request: Record<string, unknown>): Promise<unknown>;
|
|
9
|
+
close?(): void;
|
|
10
|
+
}
|
|
11
|
+
interface MetricsSender {
|
|
12
|
+
sendMetrics(request: Record<string, unknown>): Promise<unknown>;
|
|
13
|
+
close?(): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Feature requirement - whether all or any features must be enabled
|
|
18
|
+
*/
|
|
19
|
+
type FeatureRequirement = 'all' | 'any';
|
|
20
|
+
/**
|
|
21
|
+
* Where feature evaluation happens for definitions fetches.
|
|
22
|
+
* - `remote` (default): fetch `evaluated-signed` with context query params
|
|
23
|
+
* - `local`: fetch `definitions-signed` (rules only) and evaluate with `@ops-ai/toggly-eval`
|
|
24
|
+
*/
|
|
25
|
+
type EvaluationMode = 'local' | 'remote';
|
|
26
|
+
/**
|
|
27
|
+
* Configuration options for Toggly
|
|
28
|
+
*/
|
|
29
|
+
interface TogglyConfig {
|
|
30
|
+
/** Toggly application key */
|
|
31
|
+
appKey?: string;
|
|
32
|
+
/** Environment name (e.g., 'Production', 'Staging') */
|
|
33
|
+
environment?: string;
|
|
34
|
+
/** Base URL for Toggly API */
|
|
35
|
+
baseUrl?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Evaluation rail. Defaults to `remote` for backward compatibility.
|
|
38
|
+
* Use `local` for definitions-signed + call-site evaluation (server multi-tenant).
|
|
39
|
+
*/
|
|
40
|
+
evaluationMode?: EvaluationMode;
|
|
41
|
+
/** Default feature values for offline/fallback mode */
|
|
42
|
+
featureDefaults?: Record<string, boolean>;
|
|
43
|
+
/** Request timeout in milliseconds */
|
|
44
|
+
timeout?: number;
|
|
45
|
+
/** Enable debug logging */
|
|
46
|
+
debug?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* When true, verify ES256 signed definition envelopes via JWKS before applying flags.
|
|
49
|
+
*/
|
|
50
|
+
verifySignatures?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Optional allow-list of JWKS `kid` values when verifySignatures is enabled.
|
|
53
|
+
*/
|
|
54
|
+
allowedKeyIds?: string[];
|
|
55
|
+
/**
|
|
56
|
+
* Reject envelopes whose `timestamp` is older than this many seconds.
|
|
57
|
+
* Unset or <= 0 disables freshness checks.
|
|
58
|
+
*/
|
|
59
|
+
maxSignatureAgeSeconds?: number;
|
|
60
|
+
/** Device-local gates applied as a read-time AND on worker-evaluated booleans */
|
|
61
|
+
localGates?: LocalGate[];
|
|
62
|
+
/** Optional SDK error callback for reporting fetch/evaluation failures. */
|
|
63
|
+
onError?: (message: string, error?: unknown) => void;
|
|
64
|
+
/** Initial browser identity; hydrated server identity takes precedence. */
|
|
65
|
+
identity?: string;
|
|
66
|
+
/** User groups for targeting */
|
|
67
|
+
groups?: string[];
|
|
68
|
+
/** Custom claims for targeting */
|
|
69
|
+
claims?: Record<string, string>;
|
|
70
|
+
/**
|
|
71
|
+
* Base URL for usage/metrics transport (default: https://app.toggly.io/).
|
|
72
|
+
* Separate from `baseUrl`, which is for definitions/JWKS.
|
|
73
|
+
*/
|
|
74
|
+
metricsBaseUrl?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Enable feature usage tracking (Usage.SendStats / api/usage/stats).
|
|
77
|
+
* Defaults to false in core; react-router-toggly server enables when appKey is set.
|
|
78
|
+
*/
|
|
79
|
+
enableUsageTracking?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Enable business metrics (Metrics.SendMetrics / api/metrics).
|
|
82
|
+
* Defaults to false in core; react-router-toggly server enables when appKey is set.
|
|
83
|
+
*/
|
|
84
|
+
enableMetrics?: boolean;
|
|
85
|
+
/** Usage flush interval in ms (default: 60000). 0 disables the timer. */
|
|
86
|
+
usageFlushInterval?: number;
|
|
87
|
+
/** Metrics flush interval in ms (default: 60000). 0 disables the timer. */
|
|
88
|
+
metricsFlushInterval?: number;
|
|
89
|
+
/** Hostname/instance name reported with usage/metrics payloads. */
|
|
90
|
+
instanceName?: string;
|
|
91
|
+
/** Application version reported with usage payloads. */
|
|
92
|
+
appVersion?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Telemetry transport when clients are not injected.
|
|
95
|
+
* Server should use `grpc` with injected clients; edge adapters use `https`.
|
|
96
|
+
*/
|
|
97
|
+
telemetryTransport?: 'grpc' | 'https';
|
|
98
|
+
/**
|
|
99
|
+
* Attach Node process signal handlers for best-effort flush (default: true for grpc).
|
|
100
|
+
* Edge adapters must set false.
|
|
101
|
+
*/
|
|
102
|
+
telemetryAttachProcessHandlers?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Injected usage sender (gRPC stub or test double).
|
|
105
|
+
* @internal
|
|
106
|
+
*/
|
|
107
|
+
usageClient?: UsageSender | null;
|
|
108
|
+
/**
|
|
109
|
+
* Injected metrics sender (gRPC stub or test double).
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
metricsClient?: MetricsSender | null;
|
|
113
|
+
/** Optional fetch override for HTTPS telemetry (edge/tests). */
|
|
114
|
+
telemetryFetch?: typeof fetch;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* User identity context for feature targeting
|
|
118
|
+
*/
|
|
119
|
+
interface IdentityContext {
|
|
120
|
+
/** Unique user identifier */
|
|
121
|
+
identity?: string;
|
|
122
|
+
/** User groups for targeting */
|
|
123
|
+
groups?: string[];
|
|
124
|
+
/** Custom traits for targeting */
|
|
125
|
+
traits?: Record<string, string | number | boolean>;
|
|
126
|
+
/** Custom claims for targeting */
|
|
127
|
+
claims?: Record<string, string>;
|
|
128
|
+
/** HTTP request segment fields (UA / Accept-Language / country) */
|
|
129
|
+
request?: {
|
|
130
|
+
userAgent?: string;
|
|
131
|
+
acceptLanguage?: string;
|
|
132
|
+
country?: string;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Feature flags state (boolean or entity gate per flag)
|
|
137
|
+
*/
|
|
138
|
+
type FeatureFlags = EvaluatedDefinitions;
|
|
139
|
+
/**
|
|
140
|
+
* Feature evaluation result
|
|
141
|
+
*/
|
|
142
|
+
interface EvaluationResult {
|
|
143
|
+
/** Whether the feature(s) are enabled */
|
|
144
|
+
enabled: boolean;
|
|
145
|
+
/** The feature keys that were evaluated */
|
|
146
|
+
featureKeys: string[];
|
|
147
|
+
/** The requirement type used */
|
|
148
|
+
requirement: FeatureRequirement;
|
|
149
|
+
/** Whether the result was negated */
|
|
150
|
+
negated: boolean;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Server-side feature context passed to client
|
|
154
|
+
*/
|
|
155
|
+
interface ServerFeatureContext {
|
|
156
|
+
/** Pre-fetched feature flags */
|
|
157
|
+
flags: FeatureFlags;
|
|
158
|
+
/** User identity (if any) */
|
|
159
|
+
identity?: string;
|
|
160
|
+
/** App key (for client-side refresh) */
|
|
161
|
+
appKey?: string;
|
|
162
|
+
/** Environment */
|
|
163
|
+
environment?: string;
|
|
164
|
+
/** Timestamp when flags were fetched */
|
|
165
|
+
fetchedAt: number;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Hook metadata
|
|
169
|
+
*/
|
|
170
|
+
interface HookMetadata {
|
|
171
|
+
name: string;
|
|
172
|
+
version?: string;
|
|
173
|
+
description?: string;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Evaluation series data passed between before/after hooks
|
|
177
|
+
*/
|
|
178
|
+
interface EvaluationSeriesData {
|
|
179
|
+
[key: string]: unknown;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Identity series data passed between before/after hooks
|
|
183
|
+
*/
|
|
184
|
+
interface IdentitySeriesData {
|
|
185
|
+
[key: string]: unknown;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Hook interface for extending SDK behavior
|
|
189
|
+
*/
|
|
190
|
+
interface TogglyHook {
|
|
191
|
+
/** Get hook metadata */
|
|
192
|
+
getMetadata(): HookMetadata;
|
|
193
|
+
/** Called before feature evaluation */
|
|
194
|
+
beforeEvaluation?(flagKey: string, defaultValue?: boolean): Promise<EvaluationSeriesData | void> | EvaluationSeriesData | void;
|
|
195
|
+
/** Called after feature evaluation */
|
|
196
|
+
afterEvaluation?(flagKey: string, data: EvaluationSeriesData | void, result: boolean): Promise<void> | void;
|
|
197
|
+
/** Called before user identification */
|
|
198
|
+
beforeIdentify?(identity: string): Promise<IdentitySeriesData | void> | IdentitySeriesData | void;
|
|
199
|
+
/** Called after user identification */
|
|
200
|
+
afterIdentify?(identity: string, data: IdentitySeriesData | void): Promise<void> | void;
|
|
201
|
+
/** Called after feature flags are refreshed */
|
|
202
|
+
afterRefresh?(flags: FeatureFlags): Promise<void> | void;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Error types for Toggly SDK
|
|
206
|
+
*/
|
|
207
|
+
declare class TogglyError extends Error {
|
|
208
|
+
readonly code: string;
|
|
209
|
+
readonly cause?: unknown | undefined;
|
|
210
|
+
constructor(message: string, code: string, cause?: unknown | undefined);
|
|
211
|
+
}
|
|
212
|
+
declare class TogglyNetworkError extends TogglyError {
|
|
213
|
+
constructor(message: string, cause?: unknown);
|
|
214
|
+
}
|
|
215
|
+
declare class TogglyConfigError extends TogglyError {
|
|
216
|
+
constructor(message: string);
|
|
217
|
+
}
|
|
218
|
+
declare class TogglyTimeoutError extends TogglyError {
|
|
219
|
+
constructor(message: string);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Cookie/storage key names */
|
|
223
|
+
declare const STORAGE_KEYS: {
|
|
224
|
+
/** Identity cookie/storage key */
|
|
225
|
+
readonly IDENTITY: "toggly_identity";
|
|
226
|
+
/** Feature flags cache key */
|
|
227
|
+
readonly FLAGS: "toggly_flags";
|
|
228
|
+
/** Config cache key */
|
|
229
|
+
readonly CONFIG: "toggly_config";
|
|
230
|
+
/** Last fetch timestamp key */
|
|
231
|
+
readonly LAST_FETCH: "toggly_last_fetch";
|
|
232
|
+
};
|
|
233
|
+
/** HTTP header names */
|
|
234
|
+
declare const HEADERS: {
|
|
235
|
+
/** Identity header */
|
|
236
|
+
readonly IDENTITY: "x-toggly-identity";
|
|
237
|
+
/** Feature flags header */
|
|
238
|
+
readonly FLAGS: "x-toggly-flags";
|
|
239
|
+
/** Cache control */
|
|
240
|
+
readonly CACHE_CONTROL: "cache-control";
|
|
241
|
+
};
|
|
242
|
+
/** Meta key for loader data */
|
|
243
|
+
declare const TOGGLY_LOADER_KEY: "__toggly";
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Toggly context value
|
|
247
|
+
*/
|
|
248
|
+
interface TogglyContextValue {
|
|
249
|
+
/** Current feature flags */
|
|
250
|
+
flags: FeatureFlags;
|
|
251
|
+
/** Whether the client is initialized */
|
|
252
|
+
isReady: boolean;
|
|
253
|
+
/** Current identity */
|
|
254
|
+
identity?: string;
|
|
255
|
+
/** Check if a feature is enabled */
|
|
256
|
+
isEnabled: (featureKey: string, defaultValue?: boolean, entity?: TogglyEntityContext | Record<string, unknown> | null, kind?: string) => boolean;
|
|
257
|
+
/** Check if a feature is disabled */
|
|
258
|
+
isDisabled: (featureKey: string, defaultValue?: boolean, entity?: TogglyEntityContext | Record<string, unknown> | null, kind?: string) => boolean;
|
|
259
|
+
/** Evaluate a feature gate */
|
|
260
|
+
evaluateGate: (featureKeys: string[], requirement?: 'all' | 'any', negate?: boolean, entity?: TogglyEntityContext | Record<string, unknown> | null, kind?: string) => boolean;
|
|
261
|
+
/** Register a domain-object mapper for entity-context evaluation */
|
|
262
|
+
registerContext: <T>(kind: string, mapper: (entity: T) => TogglyEntityContext) => void;
|
|
263
|
+
/** Set user identity */
|
|
264
|
+
identify: (identity: string, context?: IdentityContext) => Promise<void>;
|
|
265
|
+
/** Clear user identity */
|
|
266
|
+
reset: () => Promise<void>;
|
|
267
|
+
/** Refresh feature flags */
|
|
268
|
+
refresh: () => Promise<void>;
|
|
269
|
+
/** Add a hook */
|
|
270
|
+
addHook: (hook: TogglyHook) => void;
|
|
271
|
+
/** Remove a hook by name */
|
|
272
|
+
removeHook: (name: string) => boolean;
|
|
273
|
+
/** Register device-local post-filter gates */
|
|
274
|
+
setLocalGates: (gates: LocalGate[]) => void;
|
|
275
|
+
/** Notify subscribers that local gate state changed (no network) */
|
|
276
|
+
notifyLocalGatesChanged: () => void;
|
|
277
|
+
/** Subscribe to local gate changes */
|
|
278
|
+
subscribeLocalGatesChanged: (listener: () => void) => () => void;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Toggly provider props
|
|
282
|
+
*/
|
|
283
|
+
interface TogglyProviderProps {
|
|
284
|
+
/** Child components */
|
|
285
|
+
children: ReactNode;
|
|
286
|
+
/** Server-side feature context for hydration */
|
|
287
|
+
serverContext?: ServerFeatureContext;
|
|
288
|
+
/** Toggly configuration */
|
|
289
|
+
config?: TogglyConfig;
|
|
290
|
+
/** Enable client-side refresh */
|
|
291
|
+
enableRefresh?: boolean;
|
|
292
|
+
/** Refresh interval in milliseconds */
|
|
293
|
+
refreshInterval?: number;
|
|
294
|
+
/** Callback when flags are updated */
|
|
295
|
+
onFlagsChange?: (flags: FeatureFlags) => void;
|
|
296
|
+
}
|
|
297
|
+
declare const TogglyContext: react.Context<TogglyContextValue | undefined>;
|
|
298
|
+
/**
|
|
299
|
+
* Toggly Provider component
|
|
300
|
+
*/
|
|
301
|
+
declare function TogglyProvider({ children, serverContext, config, enableRefresh, refreshInterval, onFlagsChange, }: TogglyProviderProps): ReactElement;
|
|
302
|
+
/**
|
|
303
|
+
* Hook to access Toggly context
|
|
304
|
+
*/
|
|
305
|
+
declare function useTogglyContext(): TogglyContextValue;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Hook to access the Toggly context
|
|
309
|
+
*/
|
|
310
|
+
declare function useToggly(): TogglyContextValue;
|
|
311
|
+
/**
|
|
312
|
+
* Hook to check if a feature is enabled
|
|
313
|
+
*/
|
|
314
|
+
declare function useFeature(featureKey: string, defaultValue?: boolean, entity?: TogglyEntityContext | Record<string, unknown> | null, kind?: string): boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Hook to check if a feature is disabled
|
|
317
|
+
*/
|
|
318
|
+
declare function useFeatureDisabled(featureKey: string, defaultValue?: boolean, entity?: TogglyEntityContext | Record<string, unknown> | null, kind?: string): boolean;
|
|
319
|
+
/**
|
|
320
|
+
* Hook to evaluate a feature gate (multiple features)
|
|
321
|
+
*/
|
|
322
|
+
declare function useFeatureGate(featureKeys: string[], requirement?: FeatureRequirement, negate?: boolean, entity?: TogglyEntityContext | Record<string, unknown> | null, kind?: string): boolean;
|
|
323
|
+
/**
|
|
324
|
+
* Hook to get all feature flags
|
|
325
|
+
*/
|
|
326
|
+
declare function useFeatureFlags(): FeatureFlags;
|
|
327
|
+
/**
|
|
328
|
+
* Hook to check multiple features at once
|
|
329
|
+
*/
|
|
330
|
+
declare function useFeatures(featureKeys: string[], defaultValue?: boolean): Record<string, boolean>;
|
|
331
|
+
/**
|
|
332
|
+
* Hook for feature flag with callback
|
|
333
|
+
*/
|
|
334
|
+
declare function useFeatureCallback<T>(featureKey: string, enabledCallback: () => T, disabledCallback: () => T, defaultValue?: boolean): T;
|
|
335
|
+
/**
|
|
336
|
+
* Hook to get feature value with typing
|
|
337
|
+
*/
|
|
338
|
+
declare function useFeatureValue<T>(featureKey: string, enabledValue: T, disabledValue: T, defaultValue?: boolean): T;
|
|
339
|
+
/**
|
|
340
|
+
* Hook to track feature flag changes
|
|
341
|
+
*/
|
|
342
|
+
declare function useFeatureChange(featureKey: string, _onChange: (enabled: boolean) => void): boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Hook for identity management
|
|
345
|
+
*/
|
|
346
|
+
declare function useIdentity(): {
|
|
347
|
+
identity: string | undefined;
|
|
348
|
+
identify: (identity: string, context?: IdentityContext) => Promise<void>;
|
|
349
|
+
reset: () => Promise<void>;
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* Hook to check if Toggly is ready
|
|
353
|
+
*/
|
|
354
|
+
declare function useTogglyReady(): boolean;
|
|
355
|
+
/**
|
|
356
|
+
* Hook for refreshing flags
|
|
357
|
+
*/
|
|
358
|
+
declare function useRefreshFlags(): () => Promise<void>;
|
|
359
|
+
/**
|
|
360
|
+
* Hook for conditional rendering based on feature
|
|
361
|
+
*/
|
|
362
|
+
declare function useFeatureRender<T>(featureKey: string, enabled: T, disabled: T, defaultValue?: boolean): T;
|
|
363
|
+
/**
|
|
364
|
+
* Hook for A/B testing with feature flags
|
|
365
|
+
*/
|
|
366
|
+
declare function useABTest(featureKey: string, variantA: string, variantB: string, defaultVariant?: 'A' | 'B'): string;
|
|
367
|
+
/**
|
|
368
|
+
* Hook to get a feature with loading state
|
|
369
|
+
*/
|
|
370
|
+
declare function useFeatureWithLoading(featureKey: string, defaultValue?: boolean): {
|
|
371
|
+
enabled: boolean;
|
|
372
|
+
isLoading: boolean;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Feature component for declarative feature flag rendering
|
|
377
|
+
*/
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Props for Feature component
|
|
381
|
+
*/
|
|
382
|
+
interface FeatureProps {
|
|
383
|
+
/** Feature key to check */
|
|
384
|
+
featureKey?: string;
|
|
385
|
+
/** Multiple feature keys to check */
|
|
386
|
+
featureKeys?: string[];
|
|
387
|
+
/** Requirement type when using multiple features */
|
|
388
|
+
requirement?: FeatureRequirement;
|
|
389
|
+
/** Negate the feature check — use for the off path (same as .NET `<feature negate>`) */
|
|
390
|
+
negate?: boolean;
|
|
391
|
+
/** Default value if feature is not found */
|
|
392
|
+
defaultValue?: boolean;
|
|
393
|
+
/** Content to render when the gate passes */
|
|
394
|
+
children?: ReactNode;
|
|
395
|
+
/** Render prop for custom rendering */
|
|
396
|
+
render?: (enabled: boolean) => ReactNode;
|
|
397
|
+
/** Entity context for mixed evaluated-signed gates */
|
|
398
|
+
context?: TogglyEntityContext | Record<string, unknown> | null;
|
|
399
|
+
/** Context kind for registerContext mapper lookup */
|
|
400
|
+
contextKind?: string;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Feature component for conditional rendering based on feature flags
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* // Simple usage
|
|
407
|
+
* <Feature featureKey="new-dashboard">
|
|
408
|
+
* <NewDashboard />
|
|
409
|
+
* </Feature>
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* // Off path with negate
|
|
413
|
+
* <Feature featureKey="maintenance-mode" negate>
|
|
414
|
+
* <MainContent />
|
|
415
|
+
* </Feature>
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* // Multiple features (all required)
|
|
419
|
+
* <Feature featureKeys={["premium", "analytics"]} requirement="all">
|
|
420
|
+
* <PremiumAnalytics />
|
|
421
|
+
* </Feature>
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* // Render prop
|
|
425
|
+
* <Feature featureKey="dark-mode" render={(enabled) => (
|
|
426
|
+
* <div className={enabled ? 'dark' : 'light'}>Content</div>
|
|
427
|
+
* )} />
|
|
428
|
+
*/
|
|
429
|
+
declare function Feature({ featureKey, featureKeys, requirement, negate, defaultValue, children, render, context, contextKind, }: FeatureProps): ReactElement | null;
|
|
430
|
+
/**
|
|
431
|
+
* Props for FeatureEnabled component.
|
|
432
|
+
* Component is deprecated — prefer `<Feature featureKey="…">`.
|
|
433
|
+
*/
|
|
434
|
+
interface FeatureEnabledProps {
|
|
435
|
+
/** Feature key to check */
|
|
436
|
+
featureKey: string;
|
|
437
|
+
/** Default value if feature is not found */
|
|
438
|
+
defaultValue?: boolean;
|
|
439
|
+
/** Content to render when feature is enabled */
|
|
440
|
+
children: ReactNode;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Component that only renders children when feature is enabled
|
|
444
|
+
*
|
|
445
|
+
* @deprecated Use `<Feature featureKey="…">` instead
|
|
446
|
+
*
|
|
447
|
+
* @example
|
|
448
|
+
* <Feature featureKey="premium">
|
|
449
|
+
* <PremiumContent />
|
|
450
|
+
* </Feature>
|
|
451
|
+
*/
|
|
452
|
+
declare function FeatureEnabled({ featureKey, defaultValue, children, }: Readonly<FeatureEnabledProps>): ReactElement | null;
|
|
453
|
+
/**
|
|
454
|
+
* Props for FeatureDisabled component.
|
|
455
|
+
* Component is deprecated — prefer `<Feature featureKey="…" negate>`.
|
|
456
|
+
*/
|
|
457
|
+
interface FeatureDisabledProps {
|
|
458
|
+
/** Feature key to check */
|
|
459
|
+
featureKey: string;
|
|
460
|
+
/** Default value if feature is not found */
|
|
461
|
+
defaultValue?: boolean;
|
|
462
|
+
/** Content to render when feature is disabled */
|
|
463
|
+
children: ReactNode;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Component that only renders children when feature is disabled
|
|
467
|
+
*
|
|
468
|
+
* @deprecated Use `<Feature featureKey="…" negate>` instead
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* <Feature featureKey="new-ui" negate>
|
|
472
|
+
* <LegacyUI />
|
|
473
|
+
* </Feature>
|
|
474
|
+
*/
|
|
475
|
+
declare function FeatureDisabled({ featureKey, defaultValue, children, }: Readonly<FeatureDisabledProps>): ReactElement | null;
|
|
476
|
+
/**
|
|
477
|
+
* Props for FeatureSwitch component
|
|
478
|
+
*/
|
|
479
|
+
interface FeatureSwitchProps {
|
|
480
|
+
/** Feature key to check */
|
|
481
|
+
featureKey: string;
|
|
482
|
+
/** Default value if feature is not found */
|
|
483
|
+
defaultValue?: boolean;
|
|
484
|
+
/** Content to render when feature is enabled */
|
|
485
|
+
enabled: ReactNode;
|
|
486
|
+
/** Content to render when feature is disabled */
|
|
487
|
+
disabled: ReactNode;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Component that renders different content based on feature state
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* <FeatureSwitch
|
|
494
|
+
* featureKey="new-pricing"
|
|
495
|
+
* enabled={<NewPricing />}
|
|
496
|
+
* disabled={<OldPricing />}
|
|
497
|
+
* />
|
|
498
|
+
*/
|
|
499
|
+
declare function FeatureSwitch({ featureKey, defaultValue, enabled, disabled, }: FeatureSwitchProps): ReactElement;
|
|
500
|
+
/**
|
|
501
|
+
* Props for FeatureGate component
|
|
502
|
+
*/
|
|
503
|
+
interface FeatureGateProps {
|
|
504
|
+
/** Feature keys to check */
|
|
505
|
+
featureKeys: string[];
|
|
506
|
+
/** Requirement type */
|
|
507
|
+
requirement?: FeatureRequirement;
|
|
508
|
+
/** Negate the check */
|
|
509
|
+
negate?: boolean;
|
|
510
|
+
/** Content to render when gate passes */
|
|
511
|
+
children: ReactNode;
|
|
512
|
+
/** Entity context for mixed evaluated-signed gates */
|
|
513
|
+
context?: TogglyEntityContext | Record<string, unknown> | null;
|
|
514
|
+
/** Context kind for registerContext mapper lookup */
|
|
515
|
+
contextKind?: string;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Component for checking multiple features
|
|
519
|
+
*
|
|
520
|
+
* @example
|
|
521
|
+
* <FeatureGate featureKeys={["premium", "beta"]} requirement="all">
|
|
522
|
+
* <BetaFeature />
|
|
523
|
+
* </FeatureGate>
|
|
524
|
+
*/
|
|
525
|
+
declare function FeatureGate({ featureKeys, requirement, negate, children, context, contextKind, }: FeatureGateProps): ReactElement | null;
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* React Router-specific utilities for Toggly
|
|
529
|
+
*/
|
|
530
|
+
type SerializeFrom<T> = T;
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Props for RouterTogglyProvider
|
|
534
|
+
*/
|
|
535
|
+
interface RouterTogglyProviderProps extends Omit<TogglyProviderProps, 'serverContext'> {
|
|
536
|
+
/** Route ID to get loader data from (optional) */
|
|
537
|
+
routeId?: string;
|
|
538
|
+
/** Fallback server context if not in loader data */
|
|
539
|
+
fallbackContext?: ServerFeatureContext;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* React Router-specific Toggly Provider that automatically hydrates from loader data
|
|
543
|
+
*
|
|
544
|
+
* @example
|
|
545
|
+
* // In root.tsx
|
|
546
|
+
* export default function App() {
|
|
547
|
+
* return (
|
|
548
|
+
* <RouterTogglyProvider>
|
|
549
|
+
* <Outlet />
|
|
550
|
+
* </RouterTogglyProvider>
|
|
551
|
+
* );
|
|
552
|
+
* }
|
|
553
|
+
*/
|
|
554
|
+
declare function RouterTogglyProvider({ children, routeId, fallbackContext, config, ...props }: RouterTogglyProviderProps): ReactElement;
|
|
555
|
+
/**
|
|
556
|
+
* Hook to get Toggly context from loader data
|
|
557
|
+
*/
|
|
558
|
+
declare function useTogglyLoaderData<T extends Record<string, unknown> = Record<string, unknown>>(): {
|
|
559
|
+
data: SerializeFrom<T>;
|
|
560
|
+
toggly: ServerFeatureContext | undefined;
|
|
561
|
+
};
|
|
562
|
+
/**
|
|
563
|
+
* Hook to get Toggly context from a specific route's loader data
|
|
564
|
+
*/
|
|
565
|
+
declare function useTogglyRouteLoaderData<T extends Record<string, unknown> = Record<string, unknown>>(routeId: string): {
|
|
566
|
+
data: SerializeFrom<T> | undefined;
|
|
567
|
+
toggly: ServerFeatureContext | undefined;
|
|
568
|
+
};
|
|
569
|
+
/**
|
|
570
|
+
* Helper to extract server context from loader data
|
|
571
|
+
*/
|
|
572
|
+
declare function extractServerContext<T extends Record<string, unknown>>(loaderData: T & {
|
|
573
|
+
[TOGGLY_LOADER_KEY]?: ServerFeatureContext;
|
|
574
|
+
}): ServerFeatureContext | undefined;
|
|
575
|
+
/**
|
|
576
|
+
* Helper to check if loader data has Toggly context
|
|
577
|
+
*/
|
|
578
|
+
declare function hasTogglyContext<T extends Record<string, unknown>>(loaderData: T): loaderData is T & {
|
|
579
|
+
[TOGGLY_LOADER_KEY]: ServerFeatureContext;
|
|
580
|
+
};
|
|
581
|
+
/**
|
|
582
|
+
* Type helper for loader data with Toggly context
|
|
583
|
+
*/
|
|
584
|
+
type LoaderDataWithToggly<T extends Record<string, unknown>> = T & {
|
|
585
|
+
[TOGGLY_LOADER_KEY]: ServerFeatureContext;
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* Script component to inject Toggly flags for client-side hydration
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* // In root.tsx head
|
|
592
|
+
* <TogglyScript serverContext={togglyContext} />
|
|
593
|
+
*/
|
|
594
|
+
declare function TogglyScript({ serverContext, nonce, }: {
|
|
595
|
+
serverContext?: ServerFeatureContext;
|
|
596
|
+
nonce?: string;
|
|
597
|
+
}): ReactElement | null;
|
|
598
|
+
/**
|
|
599
|
+
* Get server context from window for client-side hydration
|
|
600
|
+
*/
|
|
601
|
+
declare function getWindowTogglyData(): ServerFeatureContext | undefined;
|
|
602
|
+
|
|
603
|
+
export { type EvaluationResult, type EvaluationSeriesData, Feature, FeatureDisabled, type FeatureDisabledProps, FeatureEnabled, type FeatureEnabledProps, type FeatureFlags, FeatureGate, type FeatureGateProps, type FeatureProps, type FeatureRequirement, FeatureSwitch, type FeatureSwitchProps, HEADERS, type HookMetadata, type IdentityContext, type IdentitySeriesData, type LoaderDataWithToggly, RouterTogglyProvider, type RouterTogglyProviderProps, STORAGE_KEYS, type ServerFeatureContext, TOGGLY_LOADER_KEY, type TogglyConfig, TogglyConfigError, TogglyContext, type TogglyContextValue, TogglyError, type TogglyHook, TogglyNetworkError, TogglyProvider, type TogglyProviderProps, TogglyScript, TogglyTimeoutError, extractServerContext, getWindowTogglyData, hasTogglyContext, useABTest, useFeature, useFeatureCallback, useFeatureChange, useFeatureDisabled, useFeatureFlags, useFeatureGate, useFeatureRender, useFeatureValue, useFeatureWithLoading, useFeatures, useIdentity, useRefreshFlags, useToggly, useTogglyContext, useTogglyLoaderData, useTogglyReady, useTogglyRouteLoaderData };
|