Skip to content

Commit ac756f6

Browse files
authored
Merge branch 'main' into feat/browser-sdk-bulk-queue
2 parents 36e4c57 + 76439a3 commit ac756f6

9 files changed

Lines changed: 189 additions & 48 deletions

File tree

packages/react-sdk/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,8 @@ The `<ReflagProvider>` initializes the Reflag SDK, fetches flags and starts list
541541
- `apiBaseUrl`: Optional base URL for the Reflag API. Use this to override the default API endpoint,
542542
- `appBaseUrl`: Optional base URL for the Reflag application. Use this to override the default app URL,
543543
- `sseBaseUrl`: Optional base URL for Server-Sent Events. Use this to override the default SSE endpoint,
544-
- `debug`: Set to `true` to enable debug logging to the console,
544+
- `logger`: Optional custom logger implementation (`debug`, `info`, `warn`, `error`) used by the underlying client,
545+
- `debug`: Set to `true` to enable debug logging to the console. If both `logger` and `debug` are provided, `logger` takes precedence,
545546
- `toolbar`: Optional [configuration](https://docs.reflag.com/supported-languages/browser-sdk/globals#toolbaroptions) for the Reflag toolbar,
546547
- `feedback`: Optional configuration for feedback collection
547548

packages/react-sdk/src/index.tsx

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
CompanyContext,
1515
HookArgs,
1616
InitOptions,
17+
Logger,
1718
RawFlag,
1819
ReflagClient,
1920
ReflagContext,
@@ -152,6 +153,13 @@ export type ReflagPropsBase = {
152153
*/
153154
initialLoading?: boolean;
154155

156+
/**
157+
* A custom logger to use for SDK logs.
158+
* Use this for advanced control or filtering of SDK logs.
159+
* If both `logger` and `debug` are provided, `logger` takes precedence.
160+
*/
161+
logger?: Logger;
162+
155163
/**
156164
* Set to `true` to enable debug logging to the console,
157165
*/
@@ -164,7 +172,7 @@ export type ReflagPropsBase = {
164172
*/
165173
export type ReflagInitOptionsBase = Omit<
166174
InitOptions,
167-
"user" | "company" | "other" | "otherContext" | "bootstrappedFlags"
175+
"user" | "company" | "other" | "otherContext" | "bootstrappedFlags" | "logger"
168176
>;
169177

170178
/**
@@ -178,20 +186,28 @@ const reflagClients = new Map<string, ReflagClient>();
178186
* Only creates a new ReflagClient is not already created or if it hook is run on the server.
179187
* @internal
180188
*/
181-
function useReflagClient(initOptions: InitOptions, debug = false) {
189+
function useReflagClient(initOptions: InitOptions & { debug?: boolean }) {
190+
const {
191+
debug = false,
192+
logger,
193+
publishableKey,
194+
sdkVersion,
195+
...clientOptions
196+
} = initOptions;
182197
const isServer = typeof window === "undefined";
183-
if (isServer || !reflagClients.has(initOptions.publishableKey)) {
198+
if (isServer || !reflagClients.has(publishableKey)) {
184199
const client = new ReflagClient({
185-
...initOptions,
186-
logger: debug ? console : undefined,
187-
sdkVersion: initOptions.sdkVersion ?? SDK_VERSION,
200+
...clientOptions,
201+
publishableKey,
202+
logger: logger ?? (debug ? console : undefined),
203+
sdkVersion: sdkVersion ?? SDK_VERSION,
188204
});
189205
if (!isServer) {
190-
reflagClients.set(initOptions.publishableKey, client);
206+
reflagClients.set(publishableKey, client);
191207
}
192208
return client;
193209
}
194-
return reflagClients.get(initOptions.publishableKey)!;
210+
return reflagClients.get(publishableKey)!;
195211
}
196212

197213
type ProviderContextType = {
@@ -204,7 +220,10 @@ const ProviderContext = createContext<ProviderContextType | null>(null);
204220
/**
205221
* Props for the ReflagClientProvider.
206222
*/
207-
export type ReflagClientProviderProps = Omit<ReflagPropsBase, "debug"> & {
223+
export type ReflagClientProviderProps = Omit<
224+
ReflagPropsBase,
225+
"debug" | "logger"
226+
> & {
208227
client: ReflagClient;
209228
};
210229

@@ -282,20 +301,20 @@ export function ReflagProvider({
282301
otherContext,
283302
loadingComponent,
284303
initialLoading = true,
304+
logger,
285305
debug,
286306
...config
287307
}: ReflagProps) {
288308
const resolvedContext = useMemo(
289309
() => ({ user, company, other: otherContext, ...context }),
290310
[user, company, otherContext, context],
291311
);
292-
const client = useReflagClient(
293-
{
294-
...config,
295-
...resolvedContext,
296-
},
312+
const client = useReflagClient({
313+
...config,
314+
...resolvedContext,
297315
debug,
298-
);
316+
logger,
317+
});
299318

300319
// Initialize the client if it is not already initialized
301320
useEffect(() => {
@@ -340,17 +359,17 @@ export function ReflagBootstrappedProvider({
340359
children,
341360
loadingComponent,
342361
initialLoading = false,
362+
logger,
343363
debug,
344364
...config
345365
}: ReflagBootstrappedProps) {
346-
const client = useReflagClient(
347-
{
348-
...config,
349-
...flags.context,
350-
bootstrappedFlags: flags.flags,
351-
},
366+
const client = useReflagClient({
367+
...config,
368+
...flags.context,
369+
bootstrappedFlags: flags.flags,
352370
debug,
353-
);
371+
logger,
372+
});
354373

355374
// Initialize the client if it is not already initialized
356375
useEffect(() => {

packages/react-sdk/test/usage.test.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,44 @@ describe("<ReflagProvider />", () => {
228228
});
229229
});
230230

231+
test("uses provided logger", async () => {
232+
const logger = {
233+
debug: vi.fn(),
234+
info: vi.fn(),
235+
warn: vi.fn(),
236+
error: vi.fn(),
237+
};
238+
239+
const { result, unmount } = renderHook(() => useClient(), {
240+
wrapper: ({ children }) => getProvider({ children, logger }),
241+
});
242+
243+
await waitFor(() => {
244+
expect(result.current.logger).toBe(logger);
245+
});
246+
247+
unmount();
248+
});
249+
250+
test("prefers logger over debug mode", async () => {
251+
const logger = {
252+
debug: vi.fn(),
253+
info: vi.fn(),
254+
warn: vi.fn(),
255+
error: vi.fn(),
256+
};
257+
258+
const { result, unmount } = renderHook(() => useClient(), {
259+
wrapper: ({ children }) => getProvider({ children, logger, debug: true }),
260+
});
261+
262+
await waitFor(() => {
263+
expect(result.current.logger).toBe(logger);
264+
});
265+
266+
unmount();
267+
});
268+
231269
test("only calls init once with the same args", () => {
232270
const node = getProvider();
233271
const initialize = vi.spyOn(ReflagClient.prototype, "initialize");

packages/vue-sdk/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ The `<ReflagProvider>` initializes the Reflag SDK, fetches flags and starts list
185185
- `apiBaseUrl`: Optional base URL for the Reflag API. Use this to override the default API endpoint,
186186
- `appBaseUrl`: Optional base URL for the Reflag application. Use this to override the default app URL,
187187
- `sseBaseUrl`: Optional base URL for Server-Sent Events. Use this to override the default SSE endpoint,
188-
- `debug`: Set to `true` to enable debug logging to the console,
188+
- `debug`: Set to `true` to enable debug logging to the console. If both `logger` and `debug` are provided, `logger` takes precedence,
189+
- `logger`: Optional custom logger implementation (`debug`, `info`, `warn`, `error`) used by the underlying client,
189190
- `toolbar`: Optional [configuration](https://docs.reflag.com/supported-languages/browser-sdk/globals#toolbaroptions) for the Reflag toolbar,
190191
- `feedback`: Optional configuration for feedback collection
191192

packages/vue-sdk/src/ReflagBootstrappedProvider.vue

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ const {
88
flags,
99
initialLoading = false,
1010
enableTracking = true,
11+
logger,
1112
debug,
1213
...config
1314
} = defineProps<ReflagBootstrappedProps>();
1415
15-
const client = useReflagClient(
16-
{
17-
...config,
18-
...flags?.context,
19-
enableTracking,
20-
bootstrappedFlags: flags?.flags,
21-
},
16+
const client = useReflagClient({
17+
...config,
18+
...flags?.context,
19+
enableTracking,
20+
bootstrappedFlags: flags?.flags,
2221
debug,
23-
);
22+
logger,
23+
});
2424
2525
const isLoading = ref(
2626
client.getState() !== "initialized" ? initialLoading : false,

packages/vue-sdk/src/ReflagProvider.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const {
1414
otherContext,
1515
initialLoading = true,
1616
enableTracking = true,
17+
logger,
1718
debug,
1819
...config
1920
} = defineProps<ReflagProps>();
@@ -25,14 +26,13 @@ const resolvedContext = computed(() => ({
2526
...context,
2627
}));
2728
28-
const client = useReflagClient(
29-
{
30-
...config,
31-
...resolvedContext.value,
32-
enableTracking,
33-
},
29+
const client = useReflagClient({
30+
...config,
31+
...resolvedContext.value,
32+
enableTracking,
3433
debug,
35-
);
34+
logger,
35+
});
3636
3737
const isLoading = ref(
3838
client.getState() !== "initialized" ? initialLoading : false,

packages/vue-sdk/src/hooks.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,28 @@ const reflagClients = new Map<string, ReflagClient>();
3838
* @internal
3939
*/
4040
export function useReflagClient(
41-
initOptions: InitOptions,
42-
debug = false,
41+
initOptions: InitOptions & { debug?: boolean },
4342
): ReflagClient {
43+
const {
44+
debug = false,
45+
logger,
46+
publishableKey,
47+
...clientOptions
48+
} = initOptions;
4449
const isServer = typeof window === "undefined";
45-
if (isServer || !reflagClients.has(initOptions.publishableKey)) {
50+
if (isServer || !reflagClients.has(publishableKey)) {
4651
const client = new ReflagClient({
47-
...initOptions,
52+
...clientOptions,
53+
publishableKey,
4854
sdkVersion: SDK_VERSION,
49-
logger: debug ? console : undefined,
55+
logger: logger ?? (debug ? console : undefined),
5056
});
5157
if (!isServer) {
52-
reflagClients.set(initOptions.publishableKey, client);
58+
reflagClients.set(publishableKey, client);
5359
}
5460
return client;
5561
}
56-
return reflagClients.get(initOptions.publishableKey)!;
62+
return reflagClients.get(publishableKey)!;
5763
}
5864

5965
/**

packages/vue-sdk/src/types.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { Ref } from "vue";
33
import type {
44
CompanyContext,
55
InitOptions,
6+
Logger,
67
RawFlags,
78
ReflagClient,
89
ReflagContext,
@@ -70,7 +71,7 @@ export type RequestFlagFeedbackOptions = Omit<
7071
*/
7172
export type ReflagInitOptionsBase = Omit<
7273
InitOptions,
73-
"user" | "company" | "other" | "otherContext" | "bootstrappedFlags"
74+
"user" | "company" | "other" | "otherContext" | "bootstrappedFlags" | "logger"
7475
>;
7576

7677
/**
@@ -83,6 +84,13 @@ export type ReflagBaseProps = {
8384
*/
8485
initialLoading?: boolean;
8586

87+
/**
88+
* A custom logger to use for SDK logs.
89+
* Use this for advanced control or filtering of SDK logs.
90+
* If both `logger` and `debug` are provided, `logger` takes precedence.
91+
*/
92+
logger?: Logger;
93+
8694
/**
8795
* Set to `true` to enable debug logging to the console.
8896
*/
@@ -92,7 +100,10 @@ export type ReflagBaseProps = {
92100
/**
93101
* Props for the ReflagClientProvider.
94102
*/
95-
export type ReflagClientProviderProps = Omit<ReflagBaseProps, "debug"> & {
103+
export type ReflagClientProviderProps = Omit<
104+
ReflagBaseProps,
105+
"debug" | "logger"
106+
> & {
96107
/**
97108
* A pre-initialized ReflagClient to use.
98109
*/

0 commit comments

Comments
 (0)