@databuddy/sdk 2.1.76 → 2.1.78

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.
@@ -1,233 +1,30 @@
1
1
  'use client';
2
2
 
3
- export { D as Databuddy } from '../shared/@databuddy/sdk.DrN7UcWM.mjs';
3
+ export { D as Databuddy } from '../shared/@databuddy/sdk.CHuEu0ou.mjs';
4
4
  import { createStore, atom, Provider, useAtom } from 'jotai';
5
- import { useEffect, createElement } from 'react';
6
- import '../shared/@databuddy/sdk.D3SKeeIX.mjs';
7
-
8
- class Logger {
9
- debugEnabled = false;
10
- /**
11
- * Enable or disable debug logging
12
- */
13
- setDebug(enabled) {
14
- this.debugEnabled = enabled;
15
- }
16
- /**
17
- * Log debug messages (only when debug is enabled)
18
- */
19
- debug(...args) {
20
- if (this.debugEnabled) {
21
- console.log("[Databuddy]", ...args);
22
- }
23
- }
24
- /**
25
- * Log info messages (always enabled)
26
- */
27
- info(...args) {
28
- console.info("[Databuddy]", ...args);
29
- }
30
- /**
31
- * Log warning messages (always enabled)
32
- */
33
- warn(...args) {
34
- console.warn("[Databuddy]", ...args);
35
- }
36
- /**
37
- * Log error messages (always enabled)
38
- */
39
- error(...args) {
40
- console.error("[Databuddy]", ...args);
41
- }
42
- /**
43
- * Log with table format (only when debug is enabled)
44
- */
45
- table(data) {
46
- if (this.debugEnabled) {
47
- console.table(data);
48
- }
49
- }
50
- /**
51
- * Time a function execution (only when debug is enabled)
52
- */
53
- time(label) {
54
- if (this.debugEnabled) {
55
- console.time(`[Databuddy] ${label}`);
56
- }
57
- }
58
- /**
59
- * End timing a function execution (only when debug is enabled)
60
- */
61
- timeEnd(label) {
62
- if (this.debugEnabled) {
63
- console.timeEnd(`[Databuddy] ${label}`);
64
- }
65
- }
66
- /**
67
- * Log JSON data (only when debug is enabled)
68
- */
69
- json(data) {
70
- if (this.debugEnabled) {
71
- console.log("[Databuddy]", JSON.stringify(data, null, 2));
72
- }
73
- }
74
- }
75
- const logger = new Logger();
76
-
77
- class FlagStorage {
78
- ttl = 24 * 60 * 60 * 1e3;
79
- // 24 hours in milliseconds
80
- get(key) {
81
- return this.getFromLocalStorage(key);
82
- }
83
- set(key, value) {
84
- this.setToLocalStorage(key, value);
85
- }
86
- getAll() {
87
- const result = {};
88
- const now = Date.now();
89
- const keys = Object.keys(localStorage).filter(
90
- (key) => key.startsWith("db-flag-")
91
- );
92
- for (const key of keys) {
93
- const flagKey = key.replace("db-flag-", "");
94
- try {
95
- const item = localStorage.getItem(key);
96
- if (item) {
97
- const parsed = JSON.parse(item);
98
- if (parsed.expiresAt && now > parsed.expiresAt) {
99
- localStorage.removeItem(key);
100
- } else {
101
- result[flagKey] = parsed.value || parsed;
102
- }
103
- }
104
- } catch {
105
- }
106
- }
107
- return result;
108
- }
109
- clear() {
110
- const keys = Object.keys(localStorage).filter(
111
- (key) => key.startsWith("db-flag-")
112
- );
113
- for (const key of keys) {
114
- localStorage.removeItem(key);
115
- }
116
- }
117
- getFromLocalStorage(key) {
118
- try {
119
- const item = localStorage.getItem(`db-flag-${key}`);
120
- if (!item) {
121
- return null;
122
- }
123
- const parsed = JSON.parse(item);
124
- if (parsed.expiresAt) {
125
- if (this.isExpired(parsed.expiresAt)) {
126
- localStorage.removeItem(`db-flag-${key}`);
127
- return null;
128
- }
129
- return parsed.value;
130
- }
131
- return parsed;
132
- } catch {
133
- return null;
134
- }
135
- }
136
- setToLocalStorage(key, value) {
137
- try {
138
- const item = {
139
- value,
140
- timestamp: Date.now(),
141
- expiresAt: Date.now() + this.ttl
142
- };
143
- localStorage.setItem(`db-flag-${key}`, JSON.stringify(item));
144
- } catch {
145
- }
146
- }
147
- isExpired(expiresAt) {
148
- if (!expiresAt) {
149
- return false;
150
- }
151
- return Date.now() > expiresAt;
152
- }
153
- delete(key) {
154
- localStorage.removeItem(`db-flag-${key}`);
155
- }
156
- deleteMultiple(keys) {
157
- for (const key of keys) {
158
- localStorage.removeItem(`db-flag-${key}`);
159
- }
160
- }
161
- setAll(flags) {
162
- const currentFlags = this.getAll();
163
- const currentKeys = Object.keys(currentFlags);
164
- const newKeys = Object.keys(flags);
165
- const removedKeys = currentKeys.filter((key) => !newKeys.includes(key));
166
- if (removedKeys.length > 0) {
167
- this.deleteMultiple(removedKeys);
168
- }
169
- for (const [key, value] of Object.entries(flags)) {
170
- this.set(key, value);
171
- }
172
- }
173
- cleanupExpired() {
174
- const now = Date.now();
175
- const keys = Object.keys(localStorage).filter(
176
- (key) => key.startsWith("db-flag-")
177
- );
178
- for (const key of keys) {
179
- try {
180
- const item = localStorage.getItem(key);
181
- if (item) {
182
- const parsed = JSON.parse(item);
183
- if (parsed.expiresAt && now > parsed.expiresAt) {
184
- localStorage.removeItem(key);
185
- }
186
- }
187
- } catch {
188
- localStorage.removeItem(key);
189
- }
190
- }
191
- }
192
- }
193
- const flagStorage = new FlagStorage();
5
+ import { useRef, useEffect, createElement } from 'react';
6
+ import { B as BrowserFlagStorage, C as CoreFlagsManager, l as logger } from '../shared/@databuddy/sdk.ItWNeH-Y.mjs';
194
7
 
195
8
  const flagsStore = createStore();
196
- const configAtom = atom(null);
9
+ const managerAtom = atom(null);
197
10
  const memoryFlagsAtom = atom({});
198
- const pendingFlagsAtom = atom(/* @__PURE__ */ new Set());
199
11
  function FlagsProvider({ children, ...config }) {
200
- const debug = config.debug ?? false;
201
- logger.setDebug(debug);
202
- logger.debug("Provider rendering with config:", {
203
- clientId: config.clientId,
204
- debug,
205
- isPending: config.isPending,
206
- hasUser: !!config.user
207
- });
12
+ const managerRef = useRef(null);
208
13
  useEffect(() => {
209
- const configWithDefaults = {
210
- clientId: config.clientId,
211
- apiUrl: config.apiUrl ?? "https://api.databuddy.cc",
212
- user: config.user,
213
- disabled: config.disabled ?? false,
214
- debug,
215
- skipStorage: config.skipStorage ?? false,
216
- isPending: config.isPending,
217
- autoFetch: config.autoFetch !== false
218
- };
219
- flagsStore.set(configAtom, configWithDefaults);
220
- logger.debug("Config set on store", {
221
- clientId: config.clientId,
222
- apiUrl: configWithDefaults.apiUrl,
223
- user: config.user,
224
- isPending: config.isPending,
225
- skipStorage: config.skipStorage ?? false
14
+ const storage = config.skipStorage ? void 0 : new BrowserFlagStorage();
15
+ const manager = new CoreFlagsManager({
16
+ config,
17
+ storage,
18
+ onFlagsUpdate: (flags) => {
19
+ flagsStore.set(memoryFlagsAtom, flags);
20
+ }
226
21
  });
227
- if (!(config.skipStorage ?? false)) {
228
- loadCachedFlagsImmediate(configWithDefaults);
229
- flagStorage.cleanupExpired();
230
- }
22
+ managerRef.current = manager;
23
+ flagsStore.set(managerAtom, manager);
24
+ return () => {
25
+ managerRef.current = null;
26
+ flagsStore.set(managerAtom, null);
27
+ };
231
28
  }, [
232
29
  config.clientId,
233
30
  config.apiUrl,
@@ -239,238 +36,64 @@ function FlagsProvider({ children, ...config }) {
239
36
  config.isPending,
240
37
  config.autoFetch
241
38
  ]);
242
- const loadCachedFlagsImmediate = (config2) => {
243
- if (config2.skipStorage) {
244
- return;
245
- }
246
- try {
247
- const cachedFlags = flagStorage.getAll();
248
- if (Object.keys(cachedFlags).length > 0) {
249
- flagsStore.set(
250
- memoryFlagsAtom,
251
- cachedFlags
252
- );
253
- logger.debug("Loaded cached flags:", Object.keys(cachedFlags));
254
- }
255
- } catch (err) {
256
- logger.warn("Error loading cached flags:", err);
39
+ useEffect(() => {
40
+ if (managerRef.current) {
41
+ managerRef.current.updateConfig(config);
257
42
  }
258
- };
43
+ }, [
44
+ config.clientId,
45
+ config.apiUrl,
46
+ config.user?.userId,
47
+ config.user?.email,
48
+ config.disabled,
49
+ config.debug,
50
+ config.skipStorage,
51
+ config.isPending,
52
+ config.autoFetch
53
+ ]);
259
54
  return createElement(Provider, { store: flagsStore }, children);
260
55
  }
261
56
  function useFlags() {
262
- const [config] = useAtom(configAtom, { store: flagsStore });
263
- const [memoryFlags, setMemoryFlags] = useAtom(memoryFlagsAtom, {
264
- store: flagsStore
265
- });
266
- const [pendingFlags, setPendingFlags] = useAtom(pendingFlagsAtom, {
57
+ const [manager] = useAtom(managerAtom, { store: flagsStore });
58
+ const [memoryFlags] = useAtom(memoryFlagsAtom, {
267
59
  store: flagsStore
268
60
  });
269
- logger.debug("useFlags called with config:", {
270
- hasConfig: !!config,
271
- clientId: config?.clientId,
272
- isPending: config?.isPending,
273
- debug: config?.debug,
274
- skipStorage: config?.skipStorage,
61
+ logger.debug("useFlags called with manager:", {
62
+ hasManager: !!manager,
275
63
  memoryFlagsCount: Object.keys(memoryFlags).length,
276
64
  memoryFlags: Object.keys(memoryFlags)
277
65
  });
278
- const fetchAllFlags = async () => {
279
- if (!config) {
280
- logger.warn("No config for bulk fetch");
281
- return;
282
- }
283
- if (config.isPending) {
284
- logger.debug("Session pending, skipping bulk fetch");
285
- return;
286
- }
287
- const params = new URLSearchParams();
288
- params.set("clientId", config.clientId);
289
- if (config.user?.userId) {
290
- params.set("userId", config.user.userId);
291
- }
292
- if (config.user?.email) {
293
- params.set("email", config.user.email);
294
- }
295
- if (config.user?.properties) {
296
- params.set("properties", JSON.stringify(config.user.properties));
297
- }
298
- const url = `${config.apiUrl}/public/v1/flags/bulk?${params.toString()}`;
299
- try {
300
- const response = await fetch(url);
301
- if (!response.ok) {
302
- throw new Error(`HTTP ${response.status}`);
303
- }
304
- const result = await response.json();
305
- logger.debug("Bulk fetch response:", result);
306
- if (result.flags) {
307
- setMemoryFlags(result.flags);
308
- if (!config.skipStorage) {
309
- try {
310
- flagStorage.setAll(result.flags);
311
- logger.debug("Bulk flags synced to cache");
312
- } catch (err) {
313
- logger.warn("Bulk storage error:", err);
314
- }
315
- }
316
- }
317
- } catch (err) {
318
- logger.error("Bulk fetch error:", err);
319
- }
320
- };
321
- const fetchFlag = async (key) => {
322
- if (!config) {
323
- logger.warn(`No config for flag: ${key}`);
324
- return {
325
- enabled: false,
326
- value: false,
327
- payload: null,
328
- reason: "NO_CONFIG"
329
- };
330
- }
331
- setPendingFlags((prev) => /* @__PURE__ */ new Set([...prev, key]));
332
- const params = new URLSearchParams();
333
- params.set("key", key);
334
- params.set("clientId", config.clientId);
335
- if (config.user?.userId) {
336
- params.set("userId", config.user.userId);
337
- }
338
- if (config.user?.email) {
339
- params.set("email", config.user.email);
340
- }
341
- if (config.user?.properties) {
342
- params.set("properties", JSON.stringify(config.user.properties));
343
- }
344
- const url = `${config.apiUrl}/public/v1/flags/evaluate?${params.toString()}`;
345
- logger.debug(`Fetching: ${key}`);
346
- try {
347
- const response = await fetch(url);
348
- if (!response.ok) {
349
- throw new Error(`HTTP ${response.status}`);
350
- }
351
- const result = await response.json();
352
- logger.debug(`Response for ${key}:`, result);
353
- setMemoryFlags((prev) => ({ ...prev, [key]: result }));
354
- if (!config.skipStorage) {
355
- try {
356
- flagStorage.set(key, result);
357
- logger.debug(`Cached: ${key}`);
358
- } catch (err) {
359
- logger.warn(`Cache error: ${key}`, err);
360
- }
361
- }
362
- return result;
363
- } catch (err) {
364
- logger.error(`Fetch error: ${key}`, err);
365
- const fallback = {
366
- enabled: false,
367
- value: false,
368
- payload: null,
369
- reason: "ERROR"
370
- };
371
- setMemoryFlags((prev) => ({ ...prev, [key]: fallback }));
372
- return fallback;
373
- } finally {
374
- setPendingFlags((prev) => {
375
- const newSet = new Set(prev);
376
- newSet.delete(key);
377
- return newSet;
378
- });
379
- }
380
- };
381
- const getFlag = async (key) => {
382
- logger.debug(`Getting: ${key}`);
383
- if (config?.isPending) {
384
- logger.debug(`Session pending for: ${key}`);
385
- return {
386
- enabled: false,
387
- value: false,
388
- payload: null,
389
- reason: "SESSION_PENDING"
390
- };
391
- }
392
- if (memoryFlags[key]) {
393
- logger.debug(`Memory: ${key}`);
394
- return memoryFlags[key];
395
- }
396
- if (pendingFlags.has(key)) {
397
- logger.debug(`Pending: ${key}`);
398
- return {
399
- enabled: false,
400
- value: false,
401
- payload: null,
402
- reason: "FETCHING"
403
- };
404
- }
405
- if (!config?.skipStorage) {
406
- try {
407
- const cached = await flagStorage.get(key);
408
- if (cached) {
409
- logger.debug(`Cache: ${key}`);
410
- setMemoryFlags((prev) => ({ ...prev, [key]: cached }));
411
- return cached;
412
- }
413
- } catch (err) {
414
- logger.warn(`Storage error: ${key}`, err);
415
- }
416
- }
417
- return fetchFlag(key);
418
- };
419
66
  const isEnabled = (key) => {
420
- if (memoryFlags[key]) {
421
- return {
422
- enabled: memoryFlags[key].enabled,
423
- isLoading: false,
424
- isReady: true
425
- };
426
- }
427
- if (pendingFlags.has(key)) {
67
+ if (!manager) {
428
68
  return {
429
69
  enabled: false,
430
- isLoading: true,
70
+ isLoading: false,
431
71
  isReady: false
432
72
  };
433
73
  }
434
- getFlag(key);
435
- return {
436
- enabled: false,
437
- isLoading: true,
438
- isReady: false
439
- };
74
+ return manager.isEnabled(key);
440
75
  };
441
- const refresh = (forceClear = false) => {
442
- logger.debug("Refreshing", { forceClear });
443
- if (forceClear) {
444
- setMemoryFlags({});
445
- if (!config?.skipStorage) {
446
- try {
447
- flagStorage.clear();
448
- logger.debug("Storage cleared");
449
- } catch (err) {
450
- logger.warn("Storage clear error:", err);
451
- }
452
- }
76
+ const fetchAllFlags = () => {
77
+ if (!manager) {
78
+ logger.warn("No manager for bulk fetch");
79
+ return;
453
80
  }
454
- fetchAllFlags();
81
+ return manager.fetchAllFlags();
455
82
  };
456
83
  const updateUser = (user) => {
457
- if (config) {
458
- flagsStore.set(configAtom, { ...config, user });
459
- refresh();
84
+ if (!manager) {
85
+ logger.warn("No manager for user update");
86
+ return;
460
87
  }
88
+ manager.updateUser(user);
461
89
  };
462
- useEffect(() => {
463
- if (config && !config.isPending && config.autoFetch !== false) {
464
- logger.debug("Auto-fetching");
465
- fetchAllFlags();
90
+ const refresh = (forceClear = false) => {
91
+ if (!manager) {
92
+ logger.warn("No manager for refresh");
93
+ return;
466
94
  }
467
- }, [
468
- config?.clientId,
469
- config?.user?.userId,
470
- config?.user?.email,
471
- config?.isPending,
472
- config?.autoFetch
473
- ]);
95
+ manager.refresh(forceClear);
96
+ };
474
97
  return {
475
98
  isEnabled,
476
99
  fetchAllFlags,
@@ -1,4 +1,4 @@
1
- import { i as isScriptInjected, c as createScript } from './sdk.D3SKeeIX.mjs';
1
+ import { i as isScriptInjected, c as createScript } from './sdk.ItWNeH-Y.mjs';
2
2
 
3
3
  function detectClientId(providedClientId) {
4
4
  if (providedClientId) {