@terreno/rtk 0.19.0 → 0.20.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 +6 -0
- package/dist/emptyApi.d.ts +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/openFeatureReactSdkSpike.test.d.ts +2 -0
- package/dist/openFeatureReactSdkSpike.test.d.ts.map +1 -0
- package/dist/openFeatureReactSdkSpike.test.js +29 -0
- package/dist/openFeatureReactSdkSpike.test.js.map +1 -0
- package/dist/useFeatureFlags.d.ts +15 -15
- package/dist/useFeatureFlags.d.ts.map +1 -1
- package/dist/useFeatureFlags.js +65 -78
- package/dist/useFeatureFlags.js.map +1 -1
- package/dist/useFeatureFlags.test.js +119 -53
- package/dist/useFeatureFlags.test.js.map +1 -1
- package/dist/useTerrenoFeatureFlags.d.ts +39 -0
- package/dist/useTerrenoFeatureFlags.d.ts.map +1 -0
- package/dist/useTerrenoFeatureFlags.js +157 -0
- package/dist/useTerrenoFeatureFlags.js.map +1 -0
- package/dist/useTerrenoFeatureFlags.test.d.ts +2 -0
- package/dist/useTerrenoFeatureFlags.test.d.ts.map +1 -0
- package/dist/useTerrenoFeatureFlags.test.js +160 -0
- package/dist/useTerrenoFeatureFlags.test.js.map +1 -0
- package/package.json +7 -2
- package/src/index.ts +1 -0
- package/src/openFeatureReactSdkSpike.test.ts +36 -0
- package/src/useFeatureFlags.test.ts +143 -57
- package/src/useFeatureFlags.ts +91 -95
- package/src/useTerrenoFeatureFlags.test.ts +222 -0
- package/src/useTerrenoFeatureFlags.ts +226 -0
package/README.md
CHANGED
|
@@ -95,3 +95,9 @@ const {socket, isSocketConnected} = useSocketConnection({
|
|
|
95
95
|
- `generateTags` - RTK Query tag generator for cache invalidation
|
|
96
96
|
- `ListResponse`, `populateId` - Mongoose list response utilities
|
|
97
97
|
|
|
98
|
+
## Feature flags (OpenFeature)
|
|
99
|
+
|
|
100
|
+
`useFeatureFlags` and **`useTerrenoFeatureFlags`** wire Terreno’s `GET /feature-flags/flagConfiguration` into OpenFeature. Peer dependencies: **`@openfeature/react-sdk`** and **`@openfeature/web-sdk`** (install them in your app; do not rely on transitive copies).
|
|
101
|
+
|
|
102
|
+
Full upgrade steps (backend + frontend + SDK regen) live in the **Terreno root README**: [Feature flags: OpenFeature migration](../README.md#feature-flags-openfeature-migration).
|
|
103
|
+
|
package/dist/emptyApi.d.ts
CHANGED
|
@@ -118,7 +118,7 @@ export declare const useGetVersionCheckQuery: <R extends Record<string, any> = i
|
|
|
118
118
|
isFetching: false;
|
|
119
119
|
isSuccess: false;
|
|
120
120
|
isError: false;
|
|
121
|
-
}, "error" | "data" | "fulfilledTimeStamp" | "
|
|
121
|
+
}, "error" | "data" | "fulfilledTimeStamp" | "isFetching" | "isSuccess" | "currentData"> & {
|
|
122
122
|
isSuccess: true;
|
|
123
123
|
isFetching: false;
|
|
124
124
|
error: undefined;
|
|
@@ -256,7 +256,7 @@ export declare const useGetVersionCheckQuery: <R extends Record<string, any> = i
|
|
|
256
256
|
isFetching: false;
|
|
257
257
|
isSuccess: false;
|
|
258
258
|
isError: false;
|
|
259
|
-
}, "error" | "data" | "fulfilledTimeStamp" | "
|
|
259
|
+
}, "error" | "data" | "fulfilledTimeStamp" | "isFetching" | "isSuccess" | "currentData"> & {
|
|
260
260
|
isSuccess: true;
|
|
261
261
|
isFetching: false;
|
|
262
262
|
error: undefined;
|
|
@@ -395,7 +395,7 @@ export declare const useGetVersionCheckQuery: <R extends Record<string, any> = i
|
|
|
395
395
|
isFetching: false;
|
|
396
396
|
isSuccess: false;
|
|
397
397
|
isError: false;
|
|
398
|
-
}, "error" | "data" | "fulfilledTimeStamp" | "
|
|
398
|
+
}, "error" | "data" | "fulfilledTimeStamp" | "isFetching" | "isSuccess" | "currentData"> & {
|
|
399
399
|
isSuccess: true;
|
|
400
400
|
isFetching: false;
|
|
401
401
|
error: undefined;
|
|
@@ -527,7 +527,7 @@ export declare const useGetVersionCheckQuery: <R extends Record<string, any> = i
|
|
|
527
527
|
isFetching: false;
|
|
528
528
|
isSuccess: false;
|
|
529
529
|
isError: false;
|
|
530
|
-
}, "error" | "data" | "fulfilledTimeStamp" | "
|
|
530
|
+
}, "error" | "data" | "fulfilledTimeStamp" | "isFetching" | "isSuccess" | "currentData"> & {
|
|
531
531
|
isSuccess: true;
|
|
532
532
|
isFetching: false;
|
|
533
533
|
error: undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -18,5 +18,6 @@ export * from "./useFeatureFlags";
|
|
|
18
18
|
export * from "./useOfflineStatus";
|
|
19
19
|
export * from "./useRealtimeDebug";
|
|
20
20
|
export * from "./useServerStatus";
|
|
21
|
+
export * from "./useTerrenoFeatureFlags";
|
|
21
22
|
export * from "./useUpgradeCheck";
|
|
22
23
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,5 +18,6 @@ export * from "./useFeatureFlags";
|
|
|
18
18
|
export * from "./useOfflineStatus";
|
|
19
19
|
export * from "./useRealtimeDebug";
|
|
20
20
|
export * from "./useServerStatus";
|
|
21
|
+
export * from "./useTerrenoFeatureFlags";
|
|
21
22
|
export * from "./useUpgradeCheck";
|
|
22
23
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openFeatureReactSdkSpike.test.d.ts","sourceRoot":"","sources":["../src/openFeatureReactSdkSpike.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
+
import { OpenFeatureProvider, useBooleanFlagValue } from "@openfeature/react-sdk";
|
|
3
|
+
import { NOOP_PROVIDER, OpenFeature, TypedInMemoryProvider } from "@openfeature/web-sdk";
|
|
4
|
+
import { renderHook, waitFor } from "@testing-library/react-native";
|
|
5
|
+
import React from "react";
|
|
6
|
+
const SPIKE_DOMAIN = "openfeature-rn-spike";
|
|
7
|
+
describe("@openfeature/react-sdk with React Native test renderer", () => {
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await OpenFeature.setProviderAndWait(SPIKE_DOMAIN, new TypedInMemoryProvider({
|
|
10
|
+
"demo-flag": {
|
|
11
|
+
defaultVariant: "on",
|
|
12
|
+
disabled: false,
|
|
13
|
+
variants: { off: false, on: true },
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
});
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await OpenFeature.setProviderAndWait(SPIKE_DOMAIN, NOOP_PROVIDER);
|
|
19
|
+
});
|
|
20
|
+
it("exposes useBooleanFlagValue when wrapped by OpenFeatureProvider", async () => {
|
|
21
|
+
const { result } = renderHook(() => useBooleanFlagValue("demo-flag", false), {
|
|
22
|
+
wrapper: ({ children }) => React.createElement(OpenFeatureProvider, { domain: SPIKE_DOMAIN }, children),
|
|
23
|
+
});
|
|
24
|
+
await waitFor(() => {
|
|
25
|
+
expect(result.current).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=openFeatureReactSdkSpike.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openFeatureReactSdkSpike.test.js","sourceRoot":"","sources":["../src/openFeatureReactSdkSpike.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAC,MAAM,UAAU,CAAC;AACrE,OAAO,EAAC,mBAAmB,EAAE,mBAAmB,EAAC,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAC,aAAa,EAAE,WAAW,EAAE,qBAAqB,EAAC,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAC,UAAU,EAAE,OAAO,EAAC,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAE5C,QAAQ,CAAC,wDAAwD,EAAE,GAAG,EAAE;IACtE,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,WAAW,CAAC,kBAAkB,CAClC,YAAY,EACZ,IAAI,qBAAqB,CAAC;YACxB,WAAW,EAAE;gBACX,cAAc,EAAE,IAAI;gBACpB,QAAQ,EAAE,KAAK;gBACf,QAAQ,EAAE,EAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAC;aACjC;SACF,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,WAAW,CAAC,kBAAkB,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,EAAC,MAAM,EAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE;YACzE,OAAO,EAAE,CAAC,EAAC,QAAQ,EAA8B,EAAE,EAAE,CACnD,KAAK,CAAC,aAAa,CAAC,mBAAmB,EAAE,EAAC,MAAM,EAAE,YAAY,EAAC,EAAE,QAAQ,CAAC;SAC7E,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -4,17 +4,17 @@ interface FlagValues {
|
|
|
4
4
|
}
|
|
5
5
|
type FlagsApi = Api<any, any, any, any>;
|
|
6
6
|
interface UseFeatureFlagsResult {
|
|
7
|
+
error: unknown;
|
|
7
8
|
flags: FlagValues;
|
|
8
9
|
getFlag: (key: string) => boolean;
|
|
9
10
|
getVariant: (key: string) => string | null;
|
|
10
11
|
isLoading: boolean;
|
|
11
|
-
error: unknown;
|
|
12
12
|
refetch: () => void;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* Creates feature flag accessors from an RTK Query API instance.
|
|
16
16
|
*
|
|
17
|
-
* Injects a `GET {basePath}/
|
|
17
|
+
* Injects a `GET {basePath}/flagConfiguration` endpoint into the API and returns
|
|
18
18
|
* accessors for reading flag values. Fetches once on mount and caches via
|
|
19
19
|
* RTK Query. Both `api` and `basePath` should be stable references.
|
|
20
20
|
*
|
|
@@ -27,29 +27,29 @@ interface UseFeatureFlagsResult {
|
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
29
|
export interface UseFeatureFlagsOptions {
|
|
30
|
-
/**
|
|
31
|
-
* Base path for the feature-flags endpoint. Defaults to "/feature-flags".
|
|
32
|
-
*/
|
|
33
30
|
basePath?: string;
|
|
34
|
-
|
|
35
|
-
* When true, the underlying evaluate query is not fired. Use this to avoid
|
|
36
|
-
* fetching before the user is authenticated.
|
|
37
|
-
*/
|
|
31
|
+
domain?: string;
|
|
38
32
|
skip?: boolean;
|
|
33
|
+
socket?: {
|
|
34
|
+
off: (event: string, handler: (...args: unknown[]) => void) => void;
|
|
35
|
+
on: (event: string, handler: (...args: unknown[]) => void) => void;
|
|
36
|
+
} | null;
|
|
37
|
+
socketEventName?: string;
|
|
38
|
+
userId?: string | null;
|
|
39
39
|
}
|
|
40
40
|
interface ResolvedFeatureFlagsOptions {
|
|
41
41
|
basePath: string;
|
|
42
|
+
domain: string;
|
|
42
43
|
skip: boolean;
|
|
44
|
+
socket?: UseFeatureFlagsOptions["socket"];
|
|
45
|
+
socketEventName?: string;
|
|
46
|
+
userId?: string | null;
|
|
43
47
|
}
|
|
44
48
|
/**
|
|
45
49
|
* Normalizes the legacy-compatible `basePathOrOptions` argument into a
|
|
46
|
-
* `{basePath, skip}` pair with defaults applied.
|
|
47
|
-
*
|
|
48
|
-
* - `undefined` -> `{basePath: "/feature-flags", skip: false}`
|
|
49
|
-
* - `string` -> `{basePath: <string>, skip: false}` (legacy form)
|
|
50
|
-
* - `object` -> `{basePath: opts.basePath ?? "/feature-flags", skip: opts.skip ?? false}`
|
|
50
|
+
* `{basePath, skip, ...}` pair with defaults applied.
|
|
51
51
|
*/
|
|
52
52
|
export declare const resolveFeatureFlagsOptions: (basePathOrOptions?: string | UseFeatureFlagsOptions) => ResolvedFeatureFlagsOptions;
|
|
53
|
-
export declare
|
|
53
|
+
export declare const useFeatureFlags: (api: FlagsApi, basePathOrOptions?: string | UseFeatureFlagsOptions) => UseFeatureFlagsResult;
|
|
54
54
|
export {};
|
|
55
55
|
//# sourceMappingURL=useFeatureFlags.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFeatureFlags.d.ts","sourceRoot":"","sources":["../src/useFeatureFlags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"useFeatureFlags.d.ts","sourceRoot":"","sources":["../src/useFeatureFlags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,8BAA8B,CAAC;AAItD,UAAU,UAAU;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;CACxC;AAGD,KAAK,QAAQ,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAExC,UAAU,qBAAqB;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC3C,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE;QACP,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;QACpE,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;KACpE,GAAG,IAAI,CAAC;IACT,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,UAAU,2BAA2B;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GACrC,oBAAoB,MAAM,GAAG,sBAAsB,KAClD,2BAaF,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,KAAK,QAAQ,EACb,oBAAoB,MAAM,GAAG,sBAAsB,KAClD,qBAoGF,CAAC"}
|
package/dist/useFeatureFlags.js
CHANGED
|
@@ -1,107 +1,94 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
2
|
-
|
|
3
|
-
* Cache the enhanced api per (api, basePath). `injectEndpoints` logs a console
|
|
4
|
-
* error in development whenever an endpoint with the same name is re-injected
|
|
5
|
-
* with `overrideExisting: false`, so calling it on every render of every
|
|
6
|
-
* consumer would flood the console. WeakMap-by-api lets the GC reclaim entries
|
|
7
|
-
* when the api object is unreachable.
|
|
8
|
-
*/
|
|
9
|
-
const enhancedApiCache = new WeakMap();
|
|
10
|
-
const getEnhancedApi = (api, basePath) => {
|
|
11
|
-
let byBase = enhancedApiCache.get(api);
|
|
12
|
-
if (!byBase) {
|
|
13
|
-
byBase = new Map();
|
|
14
|
-
enhancedApiCache.set(api, byBase);
|
|
15
|
-
}
|
|
16
|
-
const cached = byBase.get(basePath);
|
|
17
|
-
if (cached) {
|
|
18
|
-
return cached;
|
|
19
|
-
}
|
|
20
|
-
const enhanced = api.injectEndpoints({
|
|
21
|
-
endpoints: (builder) => ({
|
|
22
|
-
evaluateFeatureFlags: builder.query({
|
|
23
|
-
query: () => ({
|
|
24
|
-
method: "GET",
|
|
25
|
-
url: `${basePath}/evaluate`,
|
|
26
|
-
}),
|
|
27
|
-
}),
|
|
28
|
-
}),
|
|
29
|
-
overrideExisting: false,
|
|
30
|
-
});
|
|
31
|
-
byBase.set(basePath, enhanced);
|
|
32
|
-
return enhanced;
|
|
33
|
-
};
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { useTerrenoFeatureFlags } from "./useTerrenoFeatureFlags";
|
|
34
3
|
/**
|
|
35
4
|
* Normalizes the legacy-compatible `basePathOrOptions` argument into a
|
|
36
|
-
* `{basePath, skip}` pair with defaults applied.
|
|
37
|
-
*
|
|
38
|
-
* - `undefined` -> `{basePath: "/feature-flags", skip: false}`
|
|
39
|
-
* - `string` -> `{basePath: <string>, skip: false}` (legacy form)
|
|
40
|
-
* - `object` -> `{basePath: opts.basePath ?? "/feature-flags", skip: opts.skip ?? false}`
|
|
5
|
+
* `{basePath, skip, ...}` pair with defaults applied.
|
|
41
6
|
*/
|
|
42
7
|
export const resolveFeatureFlagsOptions = (basePathOrOptions) => {
|
|
43
|
-
const
|
|
8
|
+
const raw = typeof basePathOrOptions === "string"
|
|
44
9
|
? { basePath: basePathOrOptions, skip: false }
|
|
45
10
|
: (basePathOrOptions ?? {});
|
|
46
|
-
return {
|
|
11
|
+
return {
|
|
12
|
+
basePath: raw.basePath ?? "/feature-flags",
|
|
13
|
+
domain: raw.domain ?? "feature-flags",
|
|
14
|
+
skip: raw.skip ?? false,
|
|
15
|
+
socket: raw.socket,
|
|
16
|
+
socketEventName: raw.socketEventName,
|
|
17
|
+
userId: raw.userId,
|
|
18
|
+
};
|
|
47
19
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
20
|
+
export const useFeatureFlags = (api, basePathOrOptions) => {
|
|
21
|
+
const { basePath, domain, skip, socket, socketEventName, userId } = resolveFeatureFlagsOptions(basePathOrOptions);
|
|
22
|
+
const { client, error, flags: rawFlags, isLoading, refetch, } = useTerrenoFeatureFlags(api, {
|
|
23
|
+
basePath,
|
|
24
|
+
domain,
|
|
25
|
+
skip,
|
|
26
|
+
socket,
|
|
27
|
+
socketEventName,
|
|
28
|
+
userId,
|
|
29
|
+
});
|
|
30
|
+
const fetchStartedAtRef = useRef(null);
|
|
58
31
|
useEffect(() => {
|
|
59
|
-
if (!isLoading ||
|
|
32
|
+
if (!isLoading || fetchStartedAtRef.current !== null) {
|
|
60
33
|
return;
|
|
61
34
|
}
|
|
62
|
-
|
|
63
|
-
console.debug("[feature-flags]
|
|
35
|
+
fetchStartedAtRef.current = Date.now();
|
|
36
|
+
console.debug("[feature-flags] flagConfiguration request started", {
|
|
64
37
|
basePath,
|
|
65
38
|
});
|
|
66
39
|
}, [basePath, isLoading]);
|
|
67
|
-
// Log evaluate success with duration and number of resolved flag values.
|
|
68
40
|
useEffect(() => {
|
|
69
|
-
if (!
|
|
41
|
+
if (!error || fetchStartedAtRef.current === null) {
|
|
70
42
|
return;
|
|
71
43
|
}
|
|
72
|
-
const durationMs = Date.now() -
|
|
73
|
-
|
|
74
|
-
console.debug("[feature-flags]
|
|
44
|
+
const durationMs = Date.now() - fetchStartedAtRef.current;
|
|
45
|
+
fetchStartedAtRef.current = null;
|
|
46
|
+
console.debug("[feature-flags] flagConfiguration request failed", {
|
|
75
47
|
basePath,
|
|
76
48
|
durationMs,
|
|
77
|
-
|
|
78
|
-
evaluatedFlags: flags,
|
|
49
|
+
error,
|
|
79
50
|
});
|
|
80
|
-
}, [basePath,
|
|
81
|
-
|
|
51
|
+
}, [basePath, error]);
|
|
52
|
+
const flatFlags = useMemo(() => {
|
|
53
|
+
const out = {};
|
|
54
|
+
for (const [key, def] of Object.entries(rawFlags)) {
|
|
55
|
+
const value = def.variants[def.defaultVariant];
|
|
56
|
+
out[key] = value ?? null;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}, [rawFlags]);
|
|
82
60
|
useEffect(() => {
|
|
83
|
-
if (
|
|
61
|
+
if (Object.keys(flatFlags).length === 0 || fetchStartedAtRef.current === null) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (isLoading) {
|
|
84
65
|
return;
|
|
85
66
|
}
|
|
86
|
-
const durationMs = Date.now() -
|
|
87
|
-
|
|
88
|
-
console.debug("[feature-flags]
|
|
67
|
+
const durationMs = Date.now() - fetchStartedAtRef.current;
|
|
68
|
+
fetchStartedAtRef.current = null;
|
|
69
|
+
console.debug("[feature-flags] flagConfiguration request completed", {
|
|
89
70
|
basePath,
|
|
90
71
|
durationMs,
|
|
91
|
-
|
|
72
|
+
evaluatedFlagCount: Object.keys(flatFlags).length,
|
|
73
|
+
evaluatedFlags: flatFlags,
|
|
92
74
|
});
|
|
93
|
-
}, [basePath,
|
|
75
|
+
}, [basePath, flatFlags, isLoading]);
|
|
94
76
|
const getFlag = useCallback((key) => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}, [flags]);
|
|
77
|
+
return client.getBooleanValue(key, false);
|
|
78
|
+
}, [client]);
|
|
98
79
|
const getVariant = useCallback((key) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
80
|
+
if (!rawFlags[key]) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const value = client.getStringValue(key, "");
|
|
84
|
+
if (value === "") {
|
|
85
|
+
return null;
|
|
102
86
|
}
|
|
103
|
-
return
|
|
104
|
-
}, [
|
|
105
|
-
|
|
106
|
-
|
|
87
|
+
return value;
|
|
88
|
+
}, [client, rawFlags]);
|
|
89
|
+
const stableRefetch = useCallback(() => {
|
|
90
|
+
void refetch();
|
|
91
|
+
}, [refetch]);
|
|
92
|
+
return { error, flags: flatFlags, getFlag, getVariant, isLoading, refetch: stableRefetch };
|
|
93
|
+
};
|
|
107
94
|
//# sourceMappingURL=useFeatureFlags.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFeatureFlags.js","sourceRoot":"","sources":["../src/useFeatureFlags.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAE,SAAS,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useFeatureFlags.js","sourceRoot":"","sources":["../src/useFeatureFlags.ts"],"names":[],"mappings":"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"}
|