react-native-featureflags 0.1.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 +110 -0
- package/dist/client.d.ts +69 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +707 -0
- package/dist/client.js.map +1 -0
- package/dist/hooks.d.ts +5 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +44 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/core.d.ts +91 -0
- package/dist/internal/core.d.ts.map +1 -0
- package/dist/internal/core.js +185 -0
- package/dist/internal/core.js.map +1 -0
- package/dist/singleton.d.ts +23 -0
- package/dist/singleton.d.ts.map +1 -0
- package/dist/singleton.js +52 -0
- package/dist/singleton.js.map +1 -0
- package/dist/storage.d.ts +16 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +21 -0
- package/dist/storage.js.map +1 -0
- package/dist/store.d.ts +14 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +33 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# React Native Betsy SDK
|
|
2
|
+
|
|
3
|
+
Enterprise-grade feature flags for React Native.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install react-native-featureflags
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
No separate core package install is required.
|
|
12
|
+
Relay endpoint is baked into the SDK.
|
|
13
|
+
|
|
14
|
+
## Quickstart
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { useEffect } from 'react';
|
|
18
|
+
import Flags from 'react-native-featureflags';
|
|
19
|
+
|
|
20
|
+
export default function App() {
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
void Flags.configure({
|
|
23
|
+
apiKey: 'pk_live_xxx',
|
|
24
|
+
user: {
|
|
25
|
+
id: 'user-123',
|
|
26
|
+
attributes: { plan: 'pro', country: 'US' },
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
return <RootScreen />;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Login Later
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
await Flags.login({
|
|
39
|
+
id: 'user-123',
|
|
40
|
+
attributes: { plan: 'pro' },
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`Flags.identify(user)` is an alias for `Flags.login(user)`.
|
|
45
|
+
`Flags.login(user)` merges incoming attributes with existing attributes for that user ID.
|
|
46
|
+
Unspecified keys are preserved.
|
|
47
|
+
|
|
48
|
+
## Update Attributes
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
await Flags.setAttributes({
|
|
52
|
+
country: 'US',
|
|
53
|
+
role: 'admin',
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`Flags.setAttributes(attrs)` updates attributes for the current logged-in user and also preserves keys you do not pass.
|
|
58
|
+
|
|
59
|
+
## Evaluate Flags
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { useFeatureFlag, useFlagsReady } from 'react-native-featureflags';
|
|
63
|
+
|
|
64
|
+
export function CheckoutEntry() {
|
|
65
|
+
const ready = useFlagsReady();
|
|
66
|
+
const enabled = useFeatureFlag('new-checkout');
|
|
67
|
+
|
|
68
|
+
if (!ready) return <LoadingSkeleton />;
|
|
69
|
+
return enabled ? <CheckoutV2 /> : <CheckoutV1 />;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Non-hook usage:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const enabled = Flags.getFlag('new-checkout', false);
|
|
77
|
+
const all = Flags.getAllFlags();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Logout Semantics
|
|
81
|
+
|
|
82
|
+
`Flags.logout()` reverts to an anonymous user and immediately refreshes flags.
|
|
83
|
+
The anonymous ID is persisted and reused across launches.
|
|
84
|
+
|
|
85
|
+
## Persistence
|
|
86
|
+
|
|
87
|
+
Default persistence is in-memory only. For offline bootstrapping, pass an AsyncStorage adapter:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
91
|
+
import { createAsyncStorageAdapter } from 'react-native-featureflags';
|
|
92
|
+
|
|
93
|
+
await Flags.configure({
|
|
94
|
+
apiKey: 'pk_live_xxx',
|
|
95
|
+
storage: createAsyncStorageAdapter(AsyncStorage),
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Best Practices
|
|
100
|
+
|
|
101
|
+
- Configure once at app launch.
|
|
102
|
+
- Gate critical UI behind `useFlagsReady()`.
|
|
103
|
+
- Use public API keys only.
|
|
104
|
+
- Keep user attributes minimal and non-PII.
|
|
105
|
+
|
|
106
|
+
## FAQ
|
|
107
|
+
|
|
108
|
+
- Anonymous IDs: created when `user` is omitted in `configure`.
|
|
109
|
+
- Offline mode: cached flags are used if cache is valid, then refreshed.
|
|
110
|
+
- Retries/timeouts: fetch requests use timeout plus exponential backoff with jitter.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { BetsyUser, UserAttributes } from './internal/core.js';
|
|
2
|
+
import { ConfigureOptions, ExposeOptions, FlagsInternalState, TrackOptions } from './types.js';
|
|
3
|
+
export declare class ReactNativeFlagsClient {
|
|
4
|
+
private readonly store;
|
|
5
|
+
private readonly sdkSource;
|
|
6
|
+
private pollTimer;
|
|
7
|
+
private telemetryTimer;
|
|
8
|
+
private config?;
|
|
9
|
+
private requestSequence;
|
|
10
|
+
private anonymousDeviceId;
|
|
11
|
+
private readonly attributesByUserId;
|
|
12
|
+
private offlineFallbackFlags;
|
|
13
|
+
private telemetryQueue;
|
|
14
|
+
private readonly exposureKeys;
|
|
15
|
+
private readonly assignmentKeys;
|
|
16
|
+
private readonly readEvaluationKeys;
|
|
17
|
+
private streamSocket;
|
|
18
|
+
private streamReconnectTimer;
|
|
19
|
+
private latestConfigVersion;
|
|
20
|
+
private configureSignature;
|
|
21
|
+
private configureInFlight;
|
|
22
|
+
subscribe: (callback: () => void) => () => void;
|
|
23
|
+
getState: () => FlagsInternalState;
|
|
24
|
+
configure(options: ConfigureOptions): Promise<void>;
|
|
25
|
+
private configureInternal;
|
|
26
|
+
login(user: BetsyUser): Promise<void>;
|
|
27
|
+
setAttributes(attributes: UserAttributes): Promise<void>;
|
|
28
|
+
identify(user: BetsyUser): Promise<void>;
|
|
29
|
+
logout(): Promise<void>;
|
|
30
|
+
refresh(): Promise<void>;
|
|
31
|
+
track(eventName: string, properties?: Record<string, unknown>, options?: TrackOptions): Promise<void>;
|
|
32
|
+
expose(flagKey: string, options?: ExposeOptions): Promise<void>;
|
|
33
|
+
notifyFlagRead(flagKey: string): void;
|
|
34
|
+
getFlag(key: string, defaultValue?: boolean): boolean;
|
|
35
|
+
getFeatureFlagValue<T>(key: string, defaultValue: T): T;
|
|
36
|
+
getFeatureFlagPayload(key: string): Record<string, unknown> | null;
|
|
37
|
+
getAllFlags(): Record<string, unknown>;
|
|
38
|
+
isReady(): boolean;
|
|
39
|
+
destroy(): void;
|
|
40
|
+
private getStorage;
|
|
41
|
+
private getUser;
|
|
42
|
+
private getTransport;
|
|
43
|
+
private enqueueTelemetryEvent;
|
|
44
|
+
private buildConfigureSignature;
|
|
45
|
+
private requireConfigured;
|
|
46
|
+
private resolveAnonymousUser;
|
|
47
|
+
private ensureAnonymousDeviceId;
|
|
48
|
+
private loadCachedUser;
|
|
49
|
+
private persistCachedUser;
|
|
50
|
+
private normalizeUser;
|
|
51
|
+
private normalizeAttributes;
|
|
52
|
+
private mergeUser;
|
|
53
|
+
private startPolling;
|
|
54
|
+
private stopPolling;
|
|
55
|
+
private startStreamOrPolling;
|
|
56
|
+
private startStreaming;
|
|
57
|
+
private stopStreaming;
|
|
58
|
+
private scheduleStreamReconnect;
|
|
59
|
+
private handleStreamMessage;
|
|
60
|
+
private resolveStreamUrl;
|
|
61
|
+
private startTelemetryFlush;
|
|
62
|
+
private flushTelemetry;
|
|
63
|
+
private enqueueReadEvaluationEvents;
|
|
64
|
+
private enqueueAssignmentEvents;
|
|
65
|
+
private enqueueExposure;
|
|
66
|
+
private clearError;
|
|
67
|
+
private extractOfflineFallbackFlags;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAIT,cAAc,EAcf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,kBAAkB,EAAuB,YAAY,EAAE,MAAM,YAAY,CAAC;AA6BpH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,cAAc,CAA4C;IAClE,OAAO,CAAC,MAAM,CAAC,CAAmB;IAClC,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqC;IACxE,OAAO,CAAC,oBAAoB,CAAsC;IAClE,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,oBAAoB,CAA4C;IACxE,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,iBAAiB,CAA4B;IAErD,SAAS,GAAI,UAAU,MAAM,IAAI,gBAAoC;IACrE,QAAQ,QAAO,kBAAkB,CAA0B;IAErD,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;YAkB3C,iBAAiB;IAyCzB,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrC,aAAa,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxD,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAavB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwExB,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBrG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrE,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IASrC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,OAAO;IAInD,mBAAmB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC;IAIvD,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIlE,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAUtC,OAAO,IAAI,OAAO;IAIlB,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,uBAAuB;IAuB/B,OAAO,CAAC,iBAAiB;YAMX,oBAAoB;YAYpB,uBAAuB;YAYvB,cAAc;YAYd,iBAAiB;IAI/B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,cAAc;IAwCtB,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,mBAAmB;YAUb,cAAc;IAgC5B,OAAO,CAAC,2BAA2B;IAqDnC,OAAO,CAAC,uBAAuB;YAiCjB,eAAe;IAkC7B,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,2BAA2B;CAoBpC"}
|