Skip to content

Commit 2c7416a

Browse files
committed
feat: better flags
1 parent 9506271 commit 2c7416a

File tree

5 files changed

+73
-97
lines changed

5 files changed

+73
-97
lines changed

apps/dashboard/app/(main)/websites/[id]/flags/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client';
22

3+
import { useFlags } from '@databuddy/sdk/react';
34
import { FlagIcon } from '@phosphor-icons/react';
45
import { useAtom } from 'jotai';
56
import { useParams } from 'next/navigation';
@@ -13,8 +14,6 @@ import { FlagSheet } from './_components/flag-sheet';
1314
import { FlagsList } from './_components/flags-list';
1415
import type { Flag } from './_components/types';
1516

16-
type FlagStatus = 'active' | 'inactive' | 'archived';
17-
1817
const FlagsListSkeleton = () => (
1918
<div className="space-y-3">
2019
{[...new Array(3)].map((_, i) => (

apps/dashboard/app/providers.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,14 @@ function FlagsProviderWrapper({ children }: { children: React.ReactNode }) {
8484
const { data: session, isPending, error } = authClient.useSession();
8585
const isLocalhost = process.env.NODE_ENV === 'development';
8686

87-
if (isLocalhost && !isPending && session) {
88-
console.log('[Dashboard] Session loaded for flags:', {
89-
userId: session.user?.id,
90-
email: session.user?.email,
91-
});
92-
}
93-
9487
return (
9588
<FlagsProvider
96-
apiUrl={
97-
isLocalhost ? 'http://localhost:3001' : 'https://api.databuddy.cc'
98-
}
89+
// apiUrl={
90+
// isLocalhost ? 'http://localhost:3001' : 'https://api.databuddy.cc'
91+
// }
9992
clientId={
10093
isLocalhost
101-
? '5ced32e5-0219-4e75-a18a-ad9826f85698'
94+
? 'OXmNQsViBT-FOS_wZCTHc'
10295
: '3ed1fce1-5a56-4cb6-a977-66864f6d18e3'
10396
}
10497
isPending={isPending}

packages/sdk/src/core/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export interface DatabuddyConfig {
4747
*/
4848
disabled?: boolean;
4949

50+
/**
51+
* Enable debug logging (default: false).
52+
*/
53+
debug?: boolean;
54+
5055
/**
5156
* Wait for user profile before sending events (advanced, default: false).
5257
*/

packages/sdk/src/react/Databuddy.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,15 @@ import { detectClientId } from '../utils';
1111
export function Databuddy(props: DatabuddyConfig) {
1212
const clientId = detectClientId(props.clientId);
1313

14-
// Don't inject if no client ID is available
1514
if (!clientId) {
16-
if (typeof window !== 'undefined' && !props.disabled) {
15+
if (typeof window !== 'undefined' && !props.disabled && props.debug) {
1716
console.warn(
1817
'Databuddy: No client ID found. Please provide clientId prop or set NEXT_PUBLIC_DATABUDDY_CLIENT_ID environment variable.'
1918
);
2019
}
2120
return null;
2221
}
2322

24-
// Only inject script on client-side and if not already injected
2523
if (typeof window !== 'undefined' && !props.disabled && !isScriptInjected()) {
2624
const script = createScript({ ...props, clientId });
2725
document.head.appendChild(script);

packages/sdk/src/react/flags-provider.tsx

Lines changed: 62 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,43 @@ export interface FlagsProviderProps extends FlagsConfig {
1515
}
1616

1717
export function FlagsProvider({ children, ...config }: FlagsProviderProps) {
18-
console.log('[Databuddy Flags] Provider rendering with config:', {
19-
clientId: config.clientId,
20-
debug: config.debug,
21-
isPending: config.isPending,
22-
hasUser: !!config.user,
23-
});
18+
const debug = config.debug ?? false;
19+
20+
if (debug) {
21+
console.log('[Databuddy Flags] Provider rendering with config:', {
22+
clientId: config.clientId,
23+
debug,
24+
isPending: config.isPending,
25+
hasUser: !!config.user,
26+
});
27+
}
28+
2429
useEffect(() => {
25-
const newConfig = {
30+
const configWithDefaults = {
2631
clientId: config.clientId,
27-
apiUrl: config.apiUrl,
32+
apiUrl: config.apiUrl ?? 'https://api.databuddy.cc',
2833
user: config.user,
29-
disabled: config.disabled,
30-
debug: config.debug,
31-
skipStorage: config.skipStorage,
34+
disabled: config.disabled ?? false,
35+
debug,
36+
skipStorage: config.skipStorage ?? false,
3237
isPending: config.isPending,
33-
autoFetch: config.autoFetch,
38+
autoFetch: config.autoFetch !== false,
3439
};
3540

36-
flagsStore.set(configAtom, newConfig);
41+
flagsStore.set(configAtom, configWithDefaults);
3742

38-
console.log('[Databuddy Flags] Config set on store', {
39-
clientId: config.clientId,
40-
apiUrl: config.apiUrl,
41-
user: config.user,
42-
isPending: config.isPending,
43-
skipStorage: config.skipStorage,
44-
});
43+
if (debug) {
44+
console.log('[Databuddy Flags] Config set on store', {
45+
clientId: config.clientId,
46+
apiUrl: configWithDefaults.apiUrl,
47+
user: config.user,
48+
isPending: config.isPending,
49+
skipStorage: config.skipStorage ?? false,
50+
});
51+
}
4552

46-
if (!config.skipStorage) {
47-
loadCachedFlagsImmediate(newConfig);
53+
if (!(config.skipStorage ?? false)) {
54+
loadCachedFlagsImmediate(configWithDefaults);
4855
flagStorage.cleanupExpired().catch(() => {});
4956
}
5057
}, [
@@ -59,8 +66,8 @@ export function FlagsProvider({ children, ...config }: FlagsProviderProps) {
5966
config.autoFetch,
6067
]);
6168

62-
const loadCachedFlagsImmediate = (configToUse: FlagsConfig) => {
63-
if (configToUse.skipStorage) {
69+
const loadCachedFlagsImmediate = (config: FlagsConfig) => {
70+
if (config.skipStorage) {
6471
return;
6572
}
6673

@@ -82,15 +89,15 @@ export function FlagsProvider({ children, ...config }: FlagsProviderProps) {
8289

8390
if (Object.keys(cachedFlags).length > 0) {
8491
flagsStore.set(memoryFlagsAtom, cachedFlags);
85-
if (configToUse.debug) {
92+
if (config.debug) {
8693
console.log(
8794
'[Databuddy Flags] Loaded cached flags immediately:',
8895
Object.keys(cachedFlags)
8996
);
9097
}
9198
}
9299
} catch (err) {
93-
if (configToUse.debug) {
100+
if (config.debug) {
94101
console.warn(
95102
'[Databuddy Flags] Error loading cached flags immediately:',
96103
err
@@ -106,7 +113,7 @@ export function FlagsProvider({ children, ...config }: FlagsProviderProps) {
106113
...prev,
107114
...(cachedFlags as Record<string, FlagResult>),
108115
}));
109-
if (configToUse.debug) {
116+
if (config.debug) {
110117
console.log(
111118
'[Databuddy Flags] Loaded cached flags from IndexedDB:',
112119
Object.keys(cachedFlags)
@@ -115,7 +122,7 @@ export function FlagsProvider({ children, ...config }: FlagsProviderProps) {
115122
}
116123
})
117124
.catch((err) => {
118-
if (configToUse.debug) {
125+
if (config.debug) {
119126
console.warn('[Databuddy Flags] Error loading from IndexedDB:', err);
120127
}
121128
});
@@ -133,15 +140,17 @@ export function useFlags() {
133140
store: flagsStore,
134141
});
135142

136-
console.log('[Databuddy Flags] useFlags called with config:', {
137-
hasConfig: !!config,
138-
clientId: config?.clientId,
139-
isPending: config?.isPending,
140-
debug: config?.debug,
141-
skipStorage: config?.skipStorage,
142-
memoryFlagsCount: Object.keys(memoryFlags).length,
143-
memoryFlags: Object.keys(memoryFlags),
144-
});
143+
if (config?.debug) {
144+
console.log('[Databuddy Flags] useFlags called with config:', {
145+
hasConfig: !!config,
146+
clientId: config?.clientId,
147+
isPending: config?.isPending,
148+
debug: config?.debug,
149+
skipStorage: config?.skipStorage,
150+
memoryFlagsCount: Object.keys(memoryFlags).length,
151+
memoryFlags: Object.keys(memoryFlags),
152+
});
153+
}
145154

146155
const fetchAllFlags = async (): Promise<void> => {
147156
if (!config) {
@@ -171,11 +180,7 @@ export function useFlags() {
171180
const url = `${config.apiUrl}/public/v1/flags/bulk?${params.toString()}`;
172181

173182
try {
174-
const response = await fetch(url, {
175-
method: 'GET',
176-
headers: { Accept: 'application/json' },
177-
});
178-
183+
const response = await fetch(url);
179184
if (!response.ok) {
180185
throw new Error(`HTTP ${response.status}`);
181186
}
@@ -191,12 +196,9 @@ export function useFlags() {
191196

192197
if (!config.skipStorage) {
193198
try {
194-
// Use setAll to properly sync cache (removes old flags)
195199
await flagStorage.setAll(result.flags);
196200
if (config.debug) {
197-
console.log(
198-
'[Databuddy Flags] Bulk flags synced to cache, removed old flags'
199-
);
201+
console.log('[Databuddy Flags] Bulk flags synced to cache');
200202
}
201203
} catch (err) {
202204
if (config.debug) {
@@ -241,53 +243,40 @@ export function useFlags() {
241243
const url = `${config.apiUrl}/public/v1/flags/evaluate?${params.toString()}`;
242244

243245
if (config.debug) {
244-
console.log(`[Databuddy Flags] Fetching from server: ${key}`, { url });
245-
console.log(`[Databuddy Flags] Request details for ${key}:`, {
246-
hasConfig: !!config,
247-
hasUser: !!config.user,
248-
userId: config.user?.userId || 'MISSING',
249-
email: config.user?.email || 'MISSING',
250-
clientId: config.clientId || 'MISSING',
251-
});
246+
console.log(`[Databuddy Flags] Fetching: ${key}`);
252247
}
253248

254249
try {
255-
const response = await fetch(url, {
256-
method: 'GET',
257-
headers: { Accept: 'application/json' },
258-
});
259-
250+
const response = await fetch(url);
260251
if (!response.ok) {
261252
throw new Error(`HTTP ${response.status}`);
262253
}
263254

264255
const result: FlagResult = await response.json();
265256

266257
if (config.debug) {
267-
console.log(`[Databuddy Flags] Server response for: ${key}`, result);
258+
console.log(`[Databuddy Flags] Response for ${key}:`, result);
268259
}
269260

270-
// Store in memory
271261
setMemoryFlags((prev) => ({ ...prev, [key]: result }));
272262

273-
// Store in persistent storage (if not skipped)
274263
if (!config.skipStorage) {
275264
try {
276265
await flagStorage.set(key, result);
277266
if (config.debug) {
278-
console.log(`[Databuddy Flags] Stored in cache: ${key}`);
267+
console.log(`[Databuddy Flags] Cached: ${key}`);
279268
}
280269
} catch (err) {
281270
if (config.debug) {
282-
console.warn(`[Databuddy Flags] Storage save error: ${key}`, err);
271+
console.warn(`[Databuddy Flags] Cache error: ${key}`, err);
283272
}
284273
}
285274
}
286275

287276
return result;
288277
} catch (err) {
289278
if (config.debug) {
290-
console.error(`[Databuddy Flags] Fetch error for: ${key}`, err);
279+
console.error(`[Databuddy Flags] Fetch error: ${key}`, err);
291280
}
292281

293282
const fallback = {
@@ -299,7 +288,6 @@ export function useFlags() {
299288
setMemoryFlags((prev) => ({ ...prev, [key]: fallback }));
300289
return fallback;
301290
} finally {
302-
// Remove from pending flags
303291
setPendingFlags((prev: Set<string>) => {
304292
const newSet = new Set(prev);
305293
newSet.delete(key);
@@ -310,14 +298,12 @@ export function useFlags() {
310298

311299
const getFlag = async (key: string): Promise<FlagResult> => {
312300
if (config?.debug) {
313-
console.log(`[Databuddy Flags] Getting flag: ${key}`);
301+
console.log(`[Databuddy Flags] Getting: ${key}`);
314302
}
315303

316304
if (config?.isPending) {
317305
if (config?.debug) {
318-
console.log(
319-
`[Databuddy Flags] Session pending, returning default for: ${key}`
320-
);
306+
console.log(`[Databuddy Flags] Session pending for: ${key}`);
321307
}
322308
return {
323309
enabled: false,
@@ -329,19 +315,14 @@ export function useFlags() {
329315

330316
if (memoryFlags[key]) {
331317
if (config?.debug) {
332-
console.log(
333-
`[Databuddy Flags] Found in memory: ${key}`,
334-
memoryFlags[key]
335-
);
318+
console.log(`[Databuddy Flags] Memory: ${key}`);
336319
}
337320
return memoryFlags[key];
338321
}
339322

340323
if (pendingFlags.has(key)) {
341324
if (config?.debug) {
342-
console.log(
343-
`[Databuddy Flags] Already fetching: ${key}, returning default`
344-
);
325+
console.log(`[Databuddy Flags] Pending: ${key}`);
345326
}
346327
return {
347328
enabled: false,
@@ -356,14 +337,14 @@ export function useFlags() {
356337
const cached = await flagStorage.get(key);
357338
if (cached) {
358339
if (config?.debug) {
359-
console.log(`[Databuddy Flags] Found in storage: ${key}`, cached);
340+
console.log(`[Databuddy Flags] Cache: ${key}`);
360341
}
361342
setMemoryFlags((prev) => ({ ...prev, [key]: cached }));
362343
return cached;
363344
}
364345
} catch (err) {
365346
if (config?.debug) {
366-
console.warn(`[Databuddy Flags] Storage error for: ${key}`, err);
347+
console.warn(`[Databuddy Flags] Storage error: ${key}`, err);
367348
}
368349
}
369350
}
@@ -389,7 +370,7 @@ export function useFlags() {
389370

390371
const refresh = async (forceClear = false): Promise<void> => {
391372
if (config?.debug) {
392-
console.log('[Databuddy Flags] Refreshing all flags', { forceClear });
373+
console.log('[Databuddy Flags] Refreshing', { forceClear });
393374
}
394375

395376
if (forceClear) {
@@ -421,7 +402,7 @@ export function useFlags() {
421402
useEffect(() => {
422403
if (config && !config.isPending && config.autoFetch !== false) {
423404
if (config.debug) {
424-
console.log('[Databuddy Flags] Auto-fetching flags in background');
405+
console.log('[Databuddy Flags] Auto-fetching');
425406
}
426407
fetchAllFlags();
427408
}

0 commit comments

Comments
 (0)