@databuddy/sdk 2.0.0 → 2.1.1
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 +3 -2
- package/dist/core/index.d.mts +9 -3
- package/dist/core/index.d.ts +9 -3
- package/dist/core/index.mjs +3 -2
- package/dist/react/index.d.mts +61 -1
- package/dist/react/index.d.ts +61 -1
- package/dist/react/index.mjs +606 -7
- package/dist/shared/@databuddy/sdk.B1Fz4Gpw.mjs +44 -0
- package/dist/shared/@databuddy/{sdk.Sqo9i0iN.d.mts → sdk.ClgMzRh8.d.mts} +32 -2
- package/dist/shared/@databuddy/{sdk.Sqo9i0iN.d.ts → sdk.ClgMzRh8.d.ts} +32 -2
- package/dist/shared/@databuddy/{sdk.CtTNAIIE.mjs → sdk.DqscWwcO.mjs} +1 -1
- package/dist/vue/index.d.mts +41 -7
- package/dist/vue/index.d.ts +41 -7
- package/dist/vue/index.mjs +1 -1
- package/package.json +62 -58
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@databuddy/sdk)
|
|
4
4
|
[](./LICENSE)
|
|
5
|
-
[](https://
|
|
5
|
+
[](https://www.databuddy.cc/docs)
|
|
6
6
|
|
|
7
7
|
> **The easiest, privacy-first way to add analytics to your web app.**
|
|
8
8
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
- 🧩 **Drop-in React/Next.js component: `<Databuddy />`**
|
|
17
17
|
- 🛡️ **Privacy-first: anonymized by default, sampling, batching, and more**
|
|
18
18
|
- 🛠️ **Type-safe config and autocompletion**
|
|
19
|
+
- 📋 **Observability: logging, error tracking, and distributed tracing**
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
@@ -120,7 +121,7 @@ A: In your [Databuddy dashboard](https://app.databuddy.cc).
|
|
|
120
121
|
|
|
121
122
|
## 📚 Documentation & Support
|
|
122
123
|
|
|
123
|
-
- [Databuddy Docs](https://
|
|
124
|
+
- [Databuddy Docs](https://www.databuddy.cc/docs)
|
|
124
125
|
- [Dashboard](https://app.databuddy.cc)
|
|
125
126
|
- [Contact Support](https://www.databuddy.cc/contact)
|
|
126
127
|
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { D as DatabuddyConfig, a as DatabuddyTracker, T as TrackFunction, b as Databuddy$1 } from '../shared/@databuddy/sdk.
|
|
2
|
-
export { B as BaseEventProperties, e as DataAttributes, d as EventName, E as EventProperties, c as EventTypeMap, P as PropertiesForEvent, S as ScreenViewFunction, f as SetGlobalPropertiesFunction } from '../shared/@databuddy/sdk.
|
|
1
|
+
import { D as DatabuddyConfig, a as DatabuddyTracker, T as TrackFunction, b as Databuddy$1 } from '../shared/@databuddy/sdk.ClgMzRh8.mjs';
|
|
2
|
+
export { B as BaseEventProperties, e as DataAttributes, d as EventName, E as EventProperties, c as EventTypeMap, P as PropertiesForEvent, S as ScreenViewFunction, f as SetGlobalPropertiesFunction } from '../shared/@databuddy/sdk.ClgMzRh8.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Auto-detect Databuddy client ID from environment variables
|
|
6
|
+
* Supports Next.js, Nuxt, and other frameworks
|
|
7
|
+
*/
|
|
8
|
+
declare function detectClientId(providedClientId?: string): string | undefined;
|
|
3
9
|
|
|
4
10
|
declare function isScriptInjected(): boolean;
|
|
5
11
|
declare function createScript({ scriptUrl, sdkVersion, ...props }: DatabuddyConfig): HTMLScriptElement;
|
|
@@ -46,4 +52,4 @@ declare function trackError(message: string, properties?: {
|
|
|
46
52
|
*/
|
|
47
53
|
declare const Databuddy: typeof Databuddy$1;
|
|
48
54
|
|
|
49
|
-
export { Databuddy, DatabuddyConfig, DatabuddyTracker, TrackFunction, clear, createScript, flush, getTracker, isScriptInjected, isTrackerAvailable, track, trackError };
|
|
55
|
+
export { Databuddy, DatabuddyConfig, DatabuddyTracker, TrackFunction, clear, createScript, detectClientId, flush, getTracker, isScriptInjected, isTrackerAvailable, track, trackError };
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { D as DatabuddyConfig, a as DatabuddyTracker, T as TrackFunction, b as Databuddy$1 } from '../shared/@databuddy/sdk.
|
|
2
|
-
export { B as BaseEventProperties, e as DataAttributes, d as EventName, E as EventProperties, c as EventTypeMap, P as PropertiesForEvent, S as ScreenViewFunction, f as SetGlobalPropertiesFunction } from '../shared/@databuddy/sdk.
|
|
1
|
+
import { D as DatabuddyConfig, a as DatabuddyTracker, T as TrackFunction, b as Databuddy$1 } from '../shared/@databuddy/sdk.ClgMzRh8.js';
|
|
2
|
+
export { B as BaseEventProperties, e as DataAttributes, d as EventName, E as EventProperties, c as EventTypeMap, P as PropertiesForEvent, S as ScreenViewFunction, f as SetGlobalPropertiesFunction } from '../shared/@databuddy/sdk.ClgMzRh8.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Auto-detect Databuddy client ID from environment variables
|
|
6
|
+
* Supports Next.js, Nuxt, and other frameworks
|
|
7
|
+
*/
|
|
8
|
+
declare function detectClientId(providedClientId?: string): string | undefined;
|
|
3
9
|
|
|
4
10
|
declare function isScriptInjected(): boolean;
|
|
5
11
|
declare function createScript({ scriptUrl, sdkVersion, ...props }: DatabuddyConfig): HTMLScriptElement;
|
|
@@ -46,4 +52,4 @@ declare function trackError(message: string, properties?: {
|
|
|
46
52
|
*/
|
|
47
53
|
declare const Databuddy: typeof Databuddy$1;
|
|
48
54
|
|
|
49
|
-
export { Databuddy, DatabuddyConfig, DatabuddyTracker, TrackFunction, clear, createScript, flush, getTracker, isScriptInjected, isTrackerAvailable, track, trackError };
|
|
55
|
+
export { Databuddy, DatabuddyConfig, DatabuddyTracker, TrackFunction, clear, createScript, detectClientId, flush, getTracker, isScriptInjected, isTrackerAvailable, track, trackError };
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { D as Databuddy$1 } from '../shared/@databuddy/sdk.B1Fz4Gpw.mjs';
|
|
2
|
+
export { d as detectClientId } from '../shared/@databuddy/sdk.B1Fz4Gpw.mjs';
|
|
3
|
+
export { c as createScript, i as isScriptInjected } from '../shared/@databuddy/sdk.DqscWwcO.mjs';
|
|
3
4
|
|
|
4
5
|
function isTrackerAvailable() {
|
|
5
6
|
return typeof window !== "undefined" && (!!window.databuddy || !!window.db);
|
package/dist/react/index.d.mts
CHANGED
|
@@ -1 +1,61 @@
|
|
|
1
|
-
export { b as Databuddy } from '../shared/@databuddy/sdk.
|
|
1
|
+
export { b as Databuddy } from '../shared/@databuddy/sdk.ClgMzRh8.mjs';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import * as jotai from 'jotai';
|
|
5
|
+
|
|
6
|
+
interface FlagResult {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
value: boolean;
|
|
9
|
+
payload: any;
|
|
10
|
+
reason: string;
|
|
11
|
+
flagId?: string;
|
|
12
|
+
flagType?: 'boolean' | 'rollout';
|
|
13
|
+
}
|
|
14
|
+
interface FlagsConfig {
|
|
15
|
+
/** Client ID for flag evaluation */
|
|
16
|
+
clientId: string;
|
|
17
|
+
apiUrl?: string;
|
|
18
|
+
user?: {
|
|
19
|
+
userId?: string;
|
|
20
|
+
email?: string;
|
|
21
|
+
properties?: Record<string, any>;
|
|
22
|
+
};
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/** Enable debug logging */
|
|
25
|
+
debug?: boolean;
|
|
26
|
+
/** Skip persistent storage */
|
|
27
|
+
skipStorage?: boolean;
|
|
28
|
+
/** Whether session is loading */
|
|
29
|
+
isPending?: boolean;
|
|
30
|
+
/** Automatically fetch all flags on initialization (default: true) */
|
|
31
|
+
autoFetch?: boolean;
|
|
32
|
+
}
|
|
33
|
+
interface FlagsContext {
|
|
34
|
+
isEnabled: (key: string) => boolean;
|
|
35
|
+
getValue: (key: string, defaultValue?: boolean) => boolean;
|
|
36
|
+
fetchAllFlags: () => Promise<void>;
|
|
37
|
+
updateUser: (user: FlagsConfig['user']) => void;
|
|
38
|
+
refresh: (forceClear?: boolean) => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface FlagsProviderProps extends FlagsConfig {
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
}
|
|
44
|
+
declare function FlagsProvider({ children, ...config }: FlagsProviderProps): react.FunctionComponentElement<{
|
|
45
|
+
children?: ReactNode;
|
|
46
|
+
store?: {
|
|
47
|
+
get: <Value>(atom: jotai.Atom<Value>) => Value;
|
|
48
|
+
set: <Value, Args extends unknown[], Result>(atom: jotai.WritableAtom<Value, Args, Result>, ...args: Args) => Result;
|
|
49
|
+
sub: (atom: jotai.Atom<unknown>, listener: () => void) => () => void;
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
declare function useFlags(): {
|
|
53
|
+
isEnabled: (key: string) => boolean;
|
|
54
|
+
getValue: (key: string, defaultValue?: boolean) => boolean;
|
|
55
|
+
fetchAllFlags: () => Promise<void>;
|
|
56
|
+
updateUser: (user: FlagsConfig["user"]) => void;
|
|
57
|
+
refresh: (forceClear?: boolean) => Promise<void>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export { FlagsProvider, useFlags };
|
|
61
|
+
export type { FlagResult, FlagsConfig, FlagsContext };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1 +1,61 @@
|
|
|
1
|
-
export { b as Databuddy } from '../shared/@databuddy/sdk.
|
|
1
|
+
export { b as Databuddy } from '../shared/@databuddy/sdk.ClgMzRh8.js';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import * as jotai from 'jotai';
|
|
5
|
+
|
|
6
|
+
interface FlagResult {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
value: boolean;
|
|
9
|
+
payload: any;
|
|
10
|
+
reason: string;
|
|
11
|
+
flagId?: string;
|
|
12
|
+
flagType?: 'boolean' | 'rollout';
|
|
13
|
+
}
|
|
14
|
+
interface FlagsConfig {
|
|
15
|
+
/** Client ID for flag evaluation */
|
|
16
|
+
clientId: string;
|
|
17
|
+
apiUrl?: string;
|
|
18
|
+
user?: {
|
|
19
|
+
userId?: string;
|
|
20
|
+
email?: string;
|
|
21
|
+
properties?: Record<string, any>;
|
|
22
|
+
};
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/** Enable debug logging */
|
|
25
|
+
debug?: boolean;
|
|
26
|
+
/** Skip persistent storage */
|
|
27
|
+
skipStorage?: boolean;
|
|
28
|
+
/** Whether session is loading */
|
|
29
|
+
isPending?: boolean;
|
|
30
|
+
/** Automatically fetch all flags on initialization (default: true) */
|
|
31
|
+
autoFetch?: boolean;
|
|
32
|
+
}
|
|
33
|
+
interface FlagsContext {
|
|
34
|
+
isEnabled: (key: string) => boolean;
|
|
35
|
+
getValue: (key: string, defaultValue?: boolean) => boolean;
|
|
36
|
+
fetchAllFlags: () => Promise<void>;
|
|
37
|
+
updateUser: (user: FlagsConfig['user']) => void;
|
|
38
|
+
refresh: (forceClear?: boolean) => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface FlagsProviderProps extends FlagsConfig {
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
}
|
|
44
|
+
declare function FlagsProvider({ children, ...config }: FlagsProviderProps): react.FunctionComponentElement<{
|
|
45
|
+
children?: ReactNode;
|
|
46
|
+
store?: {
|
|
47
|
+
get: <Value>(atom: jotai.Atom<Value>) => Value;
|
|
48
|
+
set: <Value, Args extends unknown[], Result>(atom: jotai.WritableAtom<Value, Args, Result>, ...args: Args) => Result;
|
|
49
|
+
sub: (atom: jotai.Atom<unknown>, listener: () => void) => () => void;
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
declare function useFlags(): {
|
|
53
|
+
isEnabled: (key: string) => boolean;
|
|
54
|
+
getValue: (key: string, defaultValue?: boolean) => boolean;
|
|
55
|
+
fetchAllFlags: () => Promise<void>;
|
|
56
|
+
updateUser: (user: FlagsConfig["user"]) => void;
|
|
57
|
+
refresh: (forceClear?: boolean) => Promise<void>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export { FlagsProvider, useFlags };
|
|
61
|
+
export type { FlagResult, FlagsConfig, FlagsContext };
|
package/dist/react/index.mjs
CHANGED
|
@@ -1,13 +1,612 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export { D as Databuddy } from '../shared/@databuddy/sdk.B1Fz4Gpw.mjs';
|
|
4
|
+
import { createStore, atom, Provider, useAtom } from 'jotai';
|
|
5
|
+
import { useEffect, createElement } from 'react';
|
|
6
|
+
import '../shared/@databuddy/sdk.DqscWwcO.mjs';
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
class FlagStorage {
|
|
9
|
+
dbName = "databuddy-flags";
|
|
10
|
+
version = 1;
|
|
11
|
+
storeName = "flags";
|
|
12
|
+
ttl = 24 * 60 * 60 * 1e3;
|
|
13
|
+
// 24 hours in milliseconds
|
|
14
|
+
async get(key) {
|
|
15
|
+
try {
|
|
16
|
+
const db = await this.openDB();
|
|
17
|
+
const transaction = db.transaction(this.storeName, "readonly");
|
|
18
|
+
const store = transaction.objectStore(this.storeName);
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
const request = store.get(key);
|
|
21
|
+
request.onsuccess = () => {
|
|
22
|
+
const result = request.result;
|
|
23
|
+
if (result && this.isExpired(result.expiresAt)) {
|
|
24
|
+
this.delete(key);
|
|
25
|
+
resolve(null);
|
|
26
|
+
} else {
|
|
27
|
+
resolve(result?.value);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
request.onerror = () => resolve(null);
|
|
31
|
+
});
|
|
32
|
+
} catch {
|
|
33
|
+
return this.getFromLocalStorage(key);
|
|
34
|
+
}
|
|
9
35
|
}
|
|
10
|
-
|
|
36
|
+
async set(key, value) {
|
|
37
|
+
try {
|
|
38
|
+
const db = await this.openDB();
|
|
39
|
+
const transaction = db.transaction(this.storeName, "readwrite");
|
|
40
|
+
const store = transaction.objectStore(this.storeName);
|
|
41
|
+
const expiresAt = Date.now() + this.ttl;
|
|
42
|
+
store.put({ key, value, timestamp: Date.now(), expiresAt });
|
|
43
|
+
} catch {
|
|
44
|
+
this.setToLocalStorage(key, value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async getAll() {
|
|
48
|
+
try {
|
|
49
|
+
const db = await this.openDB();
|
|
50
|
+
const transaction = db.transaction(this.storeName, "readonly");
|
|
51
|
+
const store = transaction.objectStore(this.storeName);
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
const request = store.getAll();
|
|
54
|
+
request.onsuccess = () => {
|
|
55
|
+
const result = {};
|
|
56
|
+
const expiredKeys = [];
|
|
57
|
+
for (const item of request.result || []) {
|
|
58
|
+
if (this.isExpired(item.expiresAt)) {
|
|
59
|
+
expiredKeys.push(item.key);
|
|
60
|
+
} else {
|
|
61
|
+
result[item.key] = item.value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (expiredKeys.length > 0) {
|
|
65
|
+
this.deleteMultiple(expiredKeys);
|
|
66
|
+
}
|
|
67
|
+
resolve(result);
|
|
68
|
+
};
|
|
69
|
+
request.onerror = () => resolve({});
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
const result = {};
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
Object.keys(localStorage).filter((key) => key.startsWith("db-flag-")).forEach((key) => {
|
|
75
|
+
const flagKey = key.replace("db-flag-", "");
|
|
76
|
+
try {
|
|
77
|
+
const item = localStorage.getItem(key);
|
|
78
|
+
if (item) {
|
|
79
|
+
const parsed = JSON.parse(item);
|
|
80
|
+
if (parsed.expiresAt && now > parsed.expiresAt) {
|
|
81
|
+
localStorage.removeItem(key);
|
|
82
|
+
} else {
|
|
83
|
+
result[flagKey] = parsed.value || parsed;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async clear() {
|
|
93
|
+
try {
|
|
94
|
+
const db = await this.openDB();
|
|
95
|
+
const transaction = db.transaction(this.storeName, "readwrite");
|
|
96
|
+
const store = transaction.objectStore(this.storeName);
|
|
97
|
+
store.clear();
|
|
98
|
+
} catch {
|
|
99
|
+
Object.keys(localStorage).filter((key) => key.startsWith("db-flag-")).forEach((key) => {
|
|
100
|
+
localStorage.removeItem(key);
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async openDB() {
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
const request = indexedDB.open(this.dbName, this.version);
|
|
108
|
+
request.onerror = () => reject(request.error);
|
|
109
|
+
request.onsuccess = () => resolve(request.result);
|
|
110
|
+
request.onupgradeneeded = () => {
|
|
111
|
+
const db = request.result;
|
|
112
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
113
|
+
db.createObjectStore(this.storeName, { keyPath: "key" });
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
getFromLocalStorage(key) {
|
|
119
|
+
try {
|
|
120
|
+
const item = localStorage.getItem(`db-flag-${key}`);
|
|
121
|
+
if (!item) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const parsed = JSON.parse(item);
|
|
125
|
+
if (parsed.expiresAt) {
|
|
126
|
+
if (this.isExpired(parsed.expiresAt)) {
|
|
127
|
+
localStorage.removeItem(`db-flag-${key}`);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return parsed.value;
|
|
131
|
+
}
|
|
132
|
+
return parsed;
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
setToLocalStorage(key, value) {
|
|
138
|
+
try {
|
|
139
|
+
const item = {
|
|
140
|
+
value,
|
|
141
|
+
timestamp: Date.now(),
|
|
142
|
+
expiresAt: Date.now() + this.ttl
|
|
143
|
+
};
|
|
144
|
+
localStorage.setItem(`db-flag-${key}`, JSON.stringify(item));
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
isExpired(expiresAt) {
|
|
149
|
+
if (!expiresAt) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return Date.now() > expiresAt;
|
|
153
|
+
}
|
|
154
|
+
async delete(key) {
|
|
155
|
+
try {
|
|
156
|
+
const db = await this.openDB();
|
|
157
|
+
const transaction = db.transaction(this.storeName, "readwrite");
|
|
158
|
+
const store = transaction.objectStore(this.storeName);
|
|
159
|
+
store.delete(key);
|
|
160
|
+
} catch {
|
|
161
|
+
localStorage.removeItem(`db-flag-${key}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async deleteMultiple(keys) {
|
|
165
|
+
try {
|
|
166
|
+
const db = await this.openDB();
|
|
167
|
+
const transaction = db.transaction(this.storeName, "readwrite");
|
|
168
|
+
const store = transaction.objectStore(this.storeName);
|
|
169
|
+
for (const key of keys) {
|
|
170
|
+
store.delete(key);
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
for (const key of keys) {
|
|
174
|
+
localStorage.removeItem(`db-flag-${key}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async setAll(flags) {
|
|
179
|
+
const currentFlags = await this.getAll();
|
|
180
|
+
const currentKeys = Object.keys(currentFlags);
|
|
181
|
+
const newKeys = Object.keys(flags);
|
|
182
|
+
const removedKeys = currentKeys.filter((key) => !newKeys.includes(key));
|
|
183
|
+
if (removedKeys.length > 0) {
|
|
184
|
+
await this.deleteMultiple(removedKeys);
|
|
185
|
+
}
|
|
186
|
+
for (const [key, value] of Object.entries(flags)) {
|
|
187
|
+
await this.set(key, value);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async cleanupExpired() {
|
|
191
|
+
try {
|
|
192
|
+
const db = await this.openDB();
|
|
193
|
+
const transaction = db.transaction(this.storeName, "readwrite");
|
|
194
|
+
const store = transaction.objectStore(this.storeName);
|
|
195
|
+
return new Promise((resolve) => {
|
|
196
|
+
const request = store.getAll();
|
|
197
|
+
request.onsuccess = () => {
|
|
198
|
+
const expiredKeys = [];
|
|
199
|
+
for (const item of request.result || []) {
|
|
200
|
+
if (this.isExpired(item.expiresAt)) {
|
|
201
|
+
expiredKeys.push(item.key);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (expiredKeys.length > 0) {
|
|
205
|
+
this.deleteMultiple(expiredKeys).then(() => resolve()).catch(() => resolve());
|
|
206
|
+
} else {
|
|
207
|
+
resolve();
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
request.onerror = () => resolve();
|
|
211
|
+
});
|
|
212
|
+
} catch {
|
|
213
|
+
this.cleanupExpired();
|
|
214
|
+
const now = Date.now();
|
|
215
|
+
Object.keys(localStorage).filter((key) => key.startsWith("db-flag-")).forEach((key) => {
|
|
216
|
+
try {
|
|
217
|
+
const item = localStorage.getItem(key);
|
|
218
|
+
if (item) {
|
|
219
|
+
const parsed = JSON.parse(item);
|
|
220
|
+
if (parsed.expiresAt && now > parsed.expiresAt) {
|
|
221
|
+
localStorage.removeItem(key);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
} catch {
|
|
225
|
+
localStorage.removeItem(key);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const flagStorage = new FlagStorage();
|
|
232
|
+
|
|
233
|
+
const flagsStore = createStore();
|
|
234
|
+
const configAtom = atom(null);
|
|
235
|
+
const memoryFlagsAtom = atom({});
|
|
236
|
+
const pendingFlagsAtom = atom(/* @__PURE__ */ new Set());
|
|
237
|
+
function FlagsProvider({ children, ...config }) {
|
|
238
|
+
console.log("[Databuddy Flags] Provider rendering with config:", {
|
|
239
|
+
clientId: config.clientId,
|
|
240
|
+
debug: config.debug,
|
|
241
|
+
isPending: config.isPending,
|
|
242
|
+
hasUser: !!config.user
|
|
243
|
+
});
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
const newConfig = {
|
|
246
|
+
clientId: config.clientId,
|
|
247
|
+
apiUrl: config.apiUrl,
|
|
248
|
+
user: config.user,
|
|
249
|
+
disabled: config.disabled,
|
|
250
|
+
debug: config.debug,
|
|
251
|
+
skipStorage: config.skipStorage,
|
|
252
|
+
isPending: config.isPending,
|
|
253
|
+
autoFetch: config.autoFetch
|
|
254
|
+
};
|
|
255
|
+
flagsStore.set(configAtom, newConfig);
|
|
256
|
+
console.log("[Databuddy Flags] Config set on store", {
|
|
257
|
+
clientId: config.clientId,
|
|
258
|
+
apiUrl: config.apiUrl,
|
|
259
|
+
user: config.user,
|
|
260
|
+
isPending: config.isPending,
|
|
261
|
+
skipStorage: config.skipStorage
|
|
262
|
+
});
|
|
263
|
+
if (!config.skipStorage) {
|
|
264
|
+
loadCachedFlagsImmediate(newConfig);
|
|
265
|
+
flagStorage.cleanupExpired().catch(() => {
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}, [
|
|
269
|
+
config.clientId,
|
|
270
|
+
config.apiUrl,
|
|
271
|
+
config.user?.userId,
|
|
272
|
+
config.user?.email,
|
|
273
|
+
config.disabled,
|
|
274
|
+
config.debug,
|
|
275
|
+
config.skipStorage,
|
|
276
|
+
config.isPending,
|
|
277
|
+
config.autoFetch
|
|
278
|
+
]);
|
|
279
|
+
const loadCachedFlagsImmediate = (configToUse) => {
|
|
280
|
+
if (configToUse.skipStorage) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
const cachedFlags = {};
|
|
285
|
+
const flagKeys = Object.keys(localStorage).filter(
|
|
286
|
+
(key) => key.startsWith("db-flag-")
|
|
287
|
+
);
|
|
288
|
+
for (const key of flagKeys) {
|
|
289
|
+
const flagKey = key.replace("db-flag-", "");
|
|
290
|
+
try {
|
|
291
|
+
const value = localStorage.getItem(key);
|
|
292
|
+
if (value) {
|
|
293
|
+
cachedFlags[flagKey] = JSON.parse(value);
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (Object.keys(cachedFlags).length > 0) {
|
|
299
|
+
flagsStore.set(memoryFlagsAtom, cachedFlags);
|
|
300
|
+
if (configToUse.debug) {
|
|
301
|
+
console.log(
|
|
302
|
+
"[Databuddy Flags] Loaded cached flags immediately:",
|
|
303
|
+
Object.keys(cachedFlags)
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
} catch (err) {
|
|
308
|
+
if (configToUse.debug) {
|
|
309
|
+
console.warn(
|
|
310
|
+
"[Databuddy Flags] Error loading cached flags immediately:",
|
|
311
|
+
err
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
flagStorage.getAll().then((cachedFlags) => {
|
|
316
|
+
if (Object.keys(cachedFlags).length > 0) {
|
|
317
|
+
flagsStore.set(memoryFlagsAtom, (prev) => ({
|
|
318
|
+
...prev,
|
|
319
|
+
...cachedFlags
|
|
320
|
+
}));
|
|
321
|
+
if (configToUse.debug) {
|
|
322
|
+
console.log(
|
|
323
|
+
"[Databuddy Flags] Loaded cached flags from IndexedDB:",
|
|
324
|
+
Object.keys(cachedFlags)
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}).catch((err) => {
|
|
329
|
+
if (configToUse.debug) {
|
|
330
|
+
console.warn("[Databuddy Flags] Error loading from IndexedDB:", err);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
return createElement(Provider, { store: flagsStore }, children);
|
|
335
|
+
}
|
|
336
|
+
function useFlags() {
|
|
337
|
+
const [config] = useAtom(configAtom, { store: flagsStore });
|
|
338
|
+
const [memoryFlags, setMemoryFlags] = useAtom(memoryFlagsAtom, {
|
|
339
|
+
store: flagsStore
|
|
340
|
+
});
|
|
341
|
+
const [pendingFlags, setPendingFlags] = useAtom(pendingFlagsAtom, {
|
|
342
|
+
store: flagsStore
|
|
343
|
+
});
|
|
344
|
+
console.log("[Databuddy Flags] useFlags called with config:", {
|
|
345
|
+
hasConfig: !!config,
|
|
346
|
+
clientId: config?.clientId,
|
|
347
|
+
isPending: config?.isPending,
|
|
348
|
+
debug: config?.debug,
|
|
349
|
+
skipStorage: config?.skipStorage,
|
|
350
|
+
memoryFlagsCount: Object.keys(memoryFlags).length,
|
|
351
|
+
memoryFlags: Object.keys(memoryFlags)
|
|
352
|
+
});
|
|
353
|
+
const fetchAllFlags = async () => {
|
|
354
|
+
if (!config) {
|
|
355
|
+
console.warn("[Databuddy Flags] No config for bulk fetch");
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (config.isPending) {
|
|
359
|
+
if (config.debug) {
|
|
360
|
+
console.log("[Databuddy Flags] Session pending, skipping bulk fetch");
|
|
361
|
+
}
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const params = new URLSearchParams();
|
|
365
|
+
params.set("clientId", config.clientId);
|
|
366
|
+
if (config.user?.userId) {
|
|
367
|
+
params.set("userId", config.user.userId);
|
|
368
|
+
}
|
|
369
|
+
if (config.user?.email) {
|
|
370
|
+
params.set("email", config.user.email);
|
|
371
|
+
}
|
|
372
|
+
if (config.user?.properties) {
|
|
373
|
+
params.set("properties", JSON.stringify(config.user.properties));
|
|
374
|
+
}
|
|
375
|
+
const url = `${config.apiUrl}/public/v1/flags/bulk?${params.toString()}`;
|
|
376
|
+
try {
|
|
377
|
+
const response = await fetch(url, {
|
|
378
|
+
method: "GET",
|
|
379
|
+
headers: { Accept: "application/json" }
|
|
380
|
+
});
|
|
381
|
+
if (!response.ok) {
|
|
382
|
+
throw new Error(`HTTP ${response.status}`);
|
|
383
|
+
}
|
|
384
|
+
const result = await response.json();
|
|
385
|
+
if (config.debug) {
|
|
386
|
+
console.log("[Databuddy Flags] Bulk fetch response:", result);
|
|
387
|
+
}
|
|
388
|
+
if (result.flags) {
|
|
389
|
+
setMemoryFlags(result.flags);
|
|
390
|
+
if (!config.skipStorage) {
|
|
391
|
+
try {
|
|
392
|
+
await flagStorage.setAll(result.flags);
|
|
393
|
+
if (config.debug) {
|
|
394
|
+
console.log(
|
|
395
|
+
"[Databuddy Flags] Bulk flags synced to cache, removed old flags"
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
} catch (err) {
|
|
399
|
+
if (config.debug) {
|
|
400
|
+
console.warn("[Databuddy Flags] Bulk storage error:", err);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
} catch (err) {
|
|
406
|
+
if (config.debug) {
|
|
407
|
+
console.error("[Databuddy Flags] Bulk fetch error:", err);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const fetchFlag = async (key) => {
|
|
412
|
+
if (!config) {
|
|
413
|
+
console.warn(`[Databuddy Flags] No config for flag: ${key}`);
|
|
414
|
+
return {
|
|
415
|
+
enabled: false,
|
|
416
|
+
value: false,
|
|
417
|
+
payload: null,
|
|
418
|
+
reason: "NO_CONFIG"
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
setPendingFlags((prev) => /* @__PURE__ */ new Set([...prev, key]));
|
|
422
|
+
const params = new URLSearchParams();
|
|
423
|
+
params.set("key", key);
|
|
424
|
+
params.set("clientId", config.clientId);
|
|
425
|
+
if (config.user?.userId) {
|
|
426
|
+
params.set("userId", config.user.userId);
|
|
427
|
+
}
|
|
428
|
+
if (config.user?.email) {
|
|
429
|
+
params.set("email", config.user.email);
|
|
430
|
+
}
|
|
431
|
+
if (config.user?.properties) {
|
|
432
|
+
params.set("properties", JSON.stringify(config.user.properties));
|
|
433
|
+
}
|
|
434
|
+
const url = `${config.apiUrl}/public/v1/flags/evaluate?${params.toString()}`;
|
|
435
|
+
if (config.debug) {
|
|
436
|
+
console.log(`[Databuddy Flags] Fetching from server: ${key}`, { url });
|
|
437
|
+
console.log(`[Databuddy Flags] Request details for ${key}:`, {
|
|
438
|
+
hasConfig: !!config,
|
|
439
|
+
hasUser: !!config.user,
|
|
440
|
+
userId: config.user?.userId || "MISSING",
|
|
441
|
+
email: config.user?.email || "MISSING",
|
|
442
|
+
clientId: config.clientId || "MISSING"
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
const response = await fetch(url, {
|
|
447
|
+
method: "GET",
|
|
448
|
+
headers: { Accept: "application/json" }
|
|
449
|
+
});
|
|
450
|
+
if (!response.ok) {
|
|
451
|
+
throw new Error(`HTTP ${response.status}`);
|
|
452
|
+
}
|
|
453
|
+
const result = await response.json();
|
|
454
|
+
if (config.debug) {
|
|
455
|
+
console.log(`[Databuddy Flags] Server response for: ${key}`, result);
|
|
456
|
+
}
|
|
457
|
+
setMemoryFlags((prev) => ({ ...prev, [key]: result }));
|
|
458
|
+
if (!config.skipStorage) {
|
|
459
|
+
try {
|
|
460
|
+
await flagStorage.set(key, result);
|
|
461
|
+
if (config.debug) {
|
|
462
|
+
console.log(`[Databuddy Flags] Stored in cache: ${key}`);
|
|
463
|
+
}
|
|
464
|
+
} catch (err) {
|
|
465
|
+
if (config.debug) {
|
|
466
|
+
console.warn(`[Databuddy Flags] Storage save error: ${key}`, err);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return result;
|
|
471
|
+
} catch (err) {
|
|
472
|
+
if (config.debug) {
|
|
473
|
+
console.error(`[Databuddy Flags] Fetch error for: ${key}`, err);
|
|
474
|
+
}
|
|
475
|
+
const fallback = {
|
|
476
|
+
enabled: false,
|
|
477
|
+
value: false,
|
|
478
|
+
payload: null,
|
|
479
|
+
reason: "ERROR"
|
|
480
|
+
};
|
|
481
|
+
setMemoryFlags((prev) => ({ ...prev, [key]: fallback }));
|
|
482
|
+
return fallback;
|
|
483
|
+
} finally {
|
|
484
|
+
setPendingFlags((prev) => {
|
|
485
|
+
const newSet = new Set(prev);
|
|
486
|
+
newSet.delete(key);
|
|
487
|
+
return newSet;
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
const getFlag = async (key) => {
|
|
492
|
+
if (config?.debug) {
|
|
493
|
+
console.log(`[Databuddy Flags] Getting flag: ${key}`);
|
|
494
|
+
}
|
|
495
|
+
if (config?.isPending) {
|
|
496
|
+
if (config?.debug) {
|
|
497
|
+
console.log(
|
|
498
|
+
`[Databuddy Flags] Session pending, returning default for: ${key}`
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
enabled: false,
|
|
503
|
+
value: false,
|
|
504
|
+
payload: null,
|
|
505
|
+
reason: "SESSION_PENDING"
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (memoryFlags[key]) {
|
|
509
|
+
if (config?.debug) {
|
|
510
|
+
console.log(
|
|
511
|
+
`[Databuddy Flags] Found in memory: ${key}`,
|
|
512
|
+
memoryFlags[key]
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
return memoryFlags[key];
|
|
516
|
+
}
|
|
517
|
+
if (pendingFlags.has(key)) {
|
|
518
|
+
if (config?.debug) {
|
|
519
|
+
console.log(
|
|
520
|
+
`[Databuddy Flags] Already fetching: ${key}, returning default`
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
return {
|
|
524
|
+
enabled: false,
|
|
525
|
+
value: false,
|
|
526
|
+
payload: null,
|
|
527
|
+
reason: "FETCHING"
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
if (!config?.skipStorage) {
|
|
531
|
+
try {
|
|
532
|
+
const cached = await flagStorage.get(key);
|
|
533
|
+
if (cached) {
|
|
534
|
+
if (config?.debug) {
|
|
535
|
+
console.log(`[Databuddy Flags] Found in storage: ${key}`, cached);
|
|
536
|
+
}
|
|
537
|
+
setMemoryFlags((prev) => ({ ...prev, [key]: cached }));
|
|
538
|
+
return cached;
|
|
539
|
+
}
|
|
540
|
+
} catch (err) {
|
|
541
|
+
if (config?.debug) {
|
|
542
|
+
console.warn(`[Databuddy Flags] Storage error for: ${key}`, err);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return fetchFlag(key);
|
|
547
|
+
};
|
|
548
|
+
const isEnabled = (key) => {
|
|
549
|
+
if (memoryFlags[key]) {
|
|
550
|
+
return memoryFlags[key].enabled;
|
|
551
|
+
}
|
|
552
|
+
getFlag(key);
|
|
553
|
+
return false;
|
|
554
|
+
};
|
|
555
|
+
const getValue = (key, defaultValue = false) => {
|
|
556
|
+
if (memoryFlags[key]) {
|
|
557
|
+
return memoryFlags[key].value ?? defaultValue;
|
|
558
|
+
}
|
|
559
|
+
getFlag(key);
|
|
560
|
+
return defaultValue;
|
|
561
|
+
};
|
|
562
|
+
const refresh = async (forceClear = false) => {
|
|
563
|
+
if (config?.debug) {
|
|
564
|
+
console.log("[Databuddy Flags] Refreshing all flags", { forceClear });
|
|
565
|
+
}
|
|
566
|
+
if (forceClear) {
|
|
567
|
+
setMemoryFlags({});
|
|
568
|
+
if (!config?.skipStorage) {
|
|
569
|
+
try {
|
|
570
|
+
await flagStorage.clear();
|
|
571
|
+
if (config?.debug) {
|
|
572
|
+
console.log("[Databuddy Flags] Storage cleared");
|
|
573
|
+
}
|
|
574
|
+
} catch (err) {
|
|
575
|
+
if (config?.debug) {
|
|
576
|
+
console.warn("[Databuddy Flags] Storage clear error:", err);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
await fetchAllFlags();
|
|
582
|
+
};
|
|
583
|
+
const updateUser = (user) => {
|
|
584
|
+
if (config) {
|
|
585
|
+
flagsStore.set(configAtom, { ...config, user });
|
|
586
|
+
refresh();
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
useEffect(() => {
|
|
590
|
+
if (config && !config.isPending && config.autoFetch !== false) {
|
|
591
|
+
if (config.debug) {
|
|
592
|
+
console.log("[Databuddy Flags] Auto-fetching flags in background");
|
|
593
|
+
}
|
|
594
|
+
fetchAllFlags();
|
|
595
|
+
}
|
|
596
|
+
}, [
|
|
597
|
+
config?.clientId,
|
|
598
|
+
config?.user?.userId,
|
|
599
|
+
config?.user?.email,
|
|
600
|
+
config?.isPending,
|
|
601
|
+
config?.autoFetch
|
|
602
|
+
]);
|
|
603
|
+
return {
|
|
604
|
+
isEnabled,
|
|
605
|
+
getValue,
|
|
606
|
+
fetchAllFlags,
|
|
607
|
+
updateUser,
|
|
608
|
+
refresh
|
|
609
|
+
};
|
|
11
610
|
}
|
|
12
611
|
|
|
13
|
-
export {
|
|
612
|
+
export { FlagsProvider, useFlags };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { i as isScriptInjected, c as createScript } from './sdk.DqscWwcO.mjs';
|
|
2
|
+
|
|
3
|
+
function detectClientId(providedClientId) {
|
|
4
|
+
if (providedClientId) {
|
|
5
|
+
return providedClientId;
|
|
6
|
+
}
|
|
7
|
+
if (typeof process !== "undefined" && process.env) {
|
|
8
|
+
return process.env.NEXT_PUBLIC_DATABUDDY_CLIENT_ID || process.env.NUXT_PUBLIC_DATABUDDY_CLIENT_ID || process.env.VITE_DATABUDDY_CLIENT_ID || process.env.REACT_APP_DATABUDDY_CLIENT_ID;
|
|
9
|
+
}
|
|
10
|
+
if (typeof window !== "undefined") {
|
|
11
|
+
const nextEnv = window.__NEXT_DATA__?.env?.NEXT_PUBLIC_DATABUDDY_CLIENT_ID;
|
|
12
|
+
if (nextEnv) {
|
|
13
|
+
return nextEnv;
|
|
14
|
+
}
|
|
15
|
+
const nuxtEnv = window.__NUXT__?.env?.NUXT_PUBLIC_DATABUDDY_CLIENT_ID;
|
|
16
|
+
if (nuxtEnv) {
|
|
17
|
+
return nuxtEnv;
|
|
18
|
+
}
|
|
19
|
+
const viteEnv = window.__VITE_ENV__?.VITE_DATABUDDY_CLIENT_ID;
|
|
20
|
+
if (viteEnv) {
|
|
21
|
+
return viteEnv;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function Databuddy(props) {
|
|
28
|
+
const clientId = detectClientId(props.clientId);
|
|
29
|
+
if (!clientId) {
|
|
30
|
+
if (typeof window !== "undefined" && !props.disabled) {
|
|
31
|
+
console.warn(
|
|
32
|
+
"Databuddy: No client ID found. Please provide clientId prop or set NEXT_PUBLIC_DATABUDDY_CLIENT_ID environment variable."
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (typeof window !== "undefined" && !props.disabled && !isScriptInjected()) {
|
|
38
|
+
const script = createScript({ ...props, clientId });
|
|
39
|
+
document.head.appendChild(script);
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { Databuddy as D, detectClientId as d };
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
interface DatabuddyConfig {
|
|
6
6
|
/**
|
|
7
|
-
* Your Databuddy project client ID
|
|
7
|
+
* Your Databuddy project client ID.
|
|
8
|
+
* If not provided, will automatically detect from NEXT_PUBLIC_DATABUDDY_CLIENT_ID environment variable.
|
|
8
9
|
* Get this from your Databuddy dashboard.
|
|
9
10
|
* Example: '3ed1fce1-5a56-4cbc-a917-66864f6d18e3'
|
|
10
11
|
*/
|
|
11
|
-
clientId
|
|
12
|
+
clientId?: string;
|
|
12
13
|
/**
|
|
13
14
|
* (Advanced) Your Databuddy client secret for server-side operations.
|
|
14
15
|
* Not required for browser usage.
|
|
@@ -95,6 +96,34 @@ interface DatabuddyConfig {
|
|
|
95
96
|
* Track JavaScript errors (default: false).
|
|
96
97
|
*/
|
|
97
98
|
trackErrors?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Enable observability features (logging, error tracking, tracing) (default: false).
|
|
101
|
+
*/
|
|
102
|
+
enableObservability?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Service name for observability events.
|
|
105
|
+
*/
|
|
106
|
+
observabilityService?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Environment for observability events.
|
|
109
|
+
*/
|
|
110
|
+
observabilityEnvironment?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Service version for observability events.
|
|
113
|
+
*/
|
|
114
|
+
observabilityVersion?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Enable structured logging (default: false).
|
|
117
|
+
*/
|
|
118
|
+
enableLogging?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Enable distributed tracing (default: false).
|
|
121
|
+
*/
|
|
122
|
+
enableTracing?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Enable error tracking (default: false).
|
|
125
|
+
*/
|
|
126
|
+
enableErrorTracking?: boolean;
|
|
98
127
|
/**
|
|
99
128
|
* Sampling rate for events (0.0 to 1.0, default: 1.0).
|
|
100
129
|
* Example: 0.5 = 50% of events sent.
|
|
@@ -301,6 +330,7 @@ type SetGlobalPropertiesFunction = (properties: EventProperties) => void;
|
|
|
301
330
|
* <Databuddy /> component for Next.js/React apps
|
|
302
331
|
* Injects the databuddy.js script with all config as data attributes
|
|
303
332
|
* Usage: <Databuddy clientId="..." trackScreenViews trackPerformance ... />
|
|
333
|
+
* Or simply: <Databuddy /> (auto-detects clientId from environment variables)
|
|
304
334
|
*/
|
|
305
335
|
declare function Databuddy(props: DatabuddyConfig): null;
|
|
306
336
|
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
interface DatabuddyConfig {
|
|
6
6
|
/**
|
|
7
|
-
* Your Databuddy project client ID
|
|
7
|
+
* Your Databuddy project client ID.
|
|
8
|
+
* If not provided, will automatically detect from NEXT_PUBLIC_DATABUDDY_CLIENT_ID environment variable.
|
|
8
9
|
* Get this from your Databuddy dashboard.
|
|
9
10
|
* Example: '3ed1fce1-5a56-4cbc-a917-66864f6d18e3'
|
|
10
11
|
*/
|
|
11
|
-
clientId
|
|
12
|
+
clientId?: string;
|
|
12
13
|
/**
|
|
13
14
|
* (Advanced) Your Databuddy client secret for server-side operations.
|
|
14
15
|
* Not required for browser usage.
|
|
@@ -95,6 +96,34 @@ interface DatabuddyConfig {
|
|
|
95
96
|
* Track JavaScript errors (default: false).
|
|
96
97
|
*/
|
|
97
98
|
trackErrors?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Enable observability features (logging, error tracking, tracing) (default: false).
|
|
101
|
+
*/
|
|
102
|
+
enableObservability?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Service name for observability events.
|
|
105
|
+
*/
|
|
106
|
+
observabilityService?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Environment for observability events.
|
|
109
|
+
*/
|
|
110
|
+
observabilityEnvironment?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Service version for observability events.
|
|
113
|
+
*/
|
|
114
|
+
observabilityVersion?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Enable structured logging (default: false).
|
|
117
|
+
*/
|
|
118
|
+
enableLogging?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Enable distributed tracing (default: false).
|
|
121
|
+
*/
|
|
122
|
+
enableTracing?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Enable error tracking (default: false).
|
|
125
|
+
*/
|
|
126
|
+
enableErrorTracking?: boolean;
|
|
98
127
|
/**
|
|
99
128
|
* Sampling rate for events (0.0 to 1.0, default: 1.0).
|
|
100
129
|
* Example: 0.5 = 50% of events sent.
|
|
@@ -301,6 +330,7 @@ type SetGlobalPropertiesFunction = (properties: EventProperties) => void;
|
|
|
301
330
|
* <Databuddy /> component for Next.js/React apps
|
|
302
331
|
* Injects the databuddy.js script with all config as data attributes
|
|
303
332
|
* Usage: <Databuddy clientId="..." trackScreenViews trackPerformance ... />
|
|
333
|
+
* Or simply: <Databuddy /> (auto-detects clientId from environment variables)
|
|
304
334
|
*/
|
|
305
335
|
declare function Databuddy(props: DatabuddyConfig): null;
|
|
306
336
|
|
package/dist/vue/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as vue from 'vue';
|
|
2
2
|
|
|
3
3
|
declare const Databuddy: vue.DefineComponent<{
|
|
4
|
-
clientId
|
|
4
|
+
clientId?: {
|
|
5
5
|
type: StringConstructor;
|
|
6
|
-
required:
|
|
7
|
-
};
|
|
6
|
+
required: false;
|
|
7
|
+
} | undefined;
|
|
8
8
|
clientSecret?: {
|
|
9
9
|
type: StringConstructor;
|
|
10
10
|
required: false;
|
|
@@ -85,6 +85,34 @@ declare const Databuddy: vue.DefineComponent<{
|
|
|
85
85
|
type: BooleanConstructor;
|
|
86
86
|
required: false;
|
|
87
87
|
} | undefined;
|
|
88
|
+
enableObservability?: {
|
|
89
|
+
type: BooleanConstructor;
|
|
90
|
+
required: false;
|
|
91
|
+
} | undefined;
|
|
92
|
+
observabilityService?: {
|
|
93
|
+
type: StringConstructor;
|
|
94
|
+
required: false;
|
|
95
|
+
} | undefined;
|
|
96
|
+
observabilityEnvironment?: {
|
|
97
|
+
type: StringConstructor;
|
|
98
|
+
required: false;
|
|
99
|
+
} | undefined;
|
|
100
|
+
observabilityVersion?: {
|
|
101
|
+
type: StringConstructor;
|
|
102
|
+
required: false;
|
|
103
|
+
} | undefined;
|
|
104
|
+
enableLogging?: {
|
|
105
|
+
type: BooleanConstructor;
|
|
106
|
+
required: false;
|
|
107
|
+
} | undefined;
|
|
108
|
+
enableTracing?: {
|
|
109
|
+
type: BooleanConstructor;
|
|
110
|
+
required: false;
|
|
111
|
+
} | undefined;
|
|
112
|
+
enableErrorTracking?: {
|
|
113
|
+
type: BooleanConstructor;
|
|
114
|
+
required: false;
|
|
115
|
+
} | undefined;
|
|
88
116
|
samplingRate?: {
|
|
89
117
|
type: NumberConstructor;
|
|
90
118
|
required: false;
|
|
@@ -113,13 +141,12 @@ declare const Databuddy: vue.DefineComponent<{
|
|
|
113
141
|
type: NumberConstructor;
|
|
114
142
|
required: false;
|
|
115
143
|
} | undefined;
|
|
116
|
-
}, () => null, unknown, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, Record<string, any>, string, vue.VNodeProps & vue.AllowedComponentProps & vue.ComponentCustomProps, Readonly<{
|
|
117
|
-
|
|
118
|
-
|
|
144
|
+
}, () => null, unknown, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, Record<string, any>, string, vue.VNodeProps & vue.AllowedComponentProps & vue.ComponentCustomProps, Readonly<{} & {
|
|
145
|
+
sdk?: string | undefined;
|
|
146
|
+
clientId?: string | undefined;
|
|
119
147
|
clientSecret?: string | undefined;
|
|
120
148
|
apiUrl?: string | undefined;
|
|
121
149
|
scriptUrl?: string | undefined;
|
|
122
|
-
sdk?: string | undefined;
|
|
123
150
|
sdkVersion?: string | undefined;
|
|
124
151
|
disabled?: boolean | undefined;
|
|
125
152
|
waitForProfile?: boolean | undefined;
|
|
@@ -136,6 +163,13 @@ declare const Databuddy: vue.DefineComponent<{
|
|
|
136
163
|
trackPerformance?: boolean | undefined;
|
|
137
164
|
trackWebVitals?: boolean | undefined;
|
|
138
165
|
trackErrors?: boolean | undefined;
|
|
166
|
+
enableObservability?: boolean | undefined;
|
|
167
|
+
observabilityService?: string | undefined;
|
|
168
|
+
observabilityEnvironment?: string | undefined;
|
|
169
|
+
observabilityVersion?: string | undefined;
|
|
170
|
+
enableLogging?: boolean | undefined;
|
|
171
|
+
enableTracing?: boolean | undefined;
|
|
172
|
+
enableErrorTracking?: boolean | undefined;
|
|
139
173
|
samplingRate?: number | undefined;
|
|
140
174
|
enableRetries?: boolean | undefined;
|
|
141
175
|
maxRetries?: number | undefined;
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as vue from 'vue';
|
|
2
2
|
|
|
3
3
|
declare const Databuddy: vue.DefineComponent<{
|
|
4
|
-
clientId
|
|
4
|
+
clientId?: {
|
|
5
5
|
type: StringConstructor;
|
|
6
|
-
required:
|
|
7
|
-
};
|
|
6
|
+
required: false;
|
|
7
|
+
} | undefined;
|
|
8
8
|
clientSecret?: {
|
|
9
9
|
type: StringConstructor;
|
|
10
10
|
required: false;
|
|
@@ -85,6 +85,34 @@ declare const Databuddy: vue.DefineComponent<{
|
|
|
85
85
|
type: BooleanConstructor;
|
|
86
86
|
required: false;
|
|
87
87
|
} | undefined;
|
|
88
|
+
enableObservability?: {
|
|
89
|
+
type: BooleanConstructor;
|
|
90
|
+
required: false;
|
|
91
|
+
} | undefined;
|
|
92
|
+
observabilityService?: {
|
|
93
|
+
type: StringConstructor;
|
|
94
|
+
required: false;
|
|
95
|
+
} | undefined;
|
|
96
|
+
observabilityEnvironment?: {
|
|
97
|
+
type: StringConstructor;
|
|
98
|
+
required: false;
|
|
99
|
+
} | undefined;
|
|
100
|
+
observabilityVersion?: {
|
|
101
|
+
type: StringConstructor;
|
|
102
|
+
required: false;
|
|
103
|
+
} | undefined;
|
|
104
|
+
enableLogging?: {
|
|
105
|
+
type: BooleanConstructor;
|
|
106
|
+
required: false;
|
|
107
|
+
} | undefined;
|
|
108
|
+
enableTracing?: {
|
|
109
|
+
type: BooleanConstructor;
|
|
110
|
+
required: false;
|
|
111
|
+
} | undefined;
|
|
112
|
+
enableErrorTracking?: {
|
|
113
|
+
type: BooleanConstructor;
|
|
114
|
+
required: false;
|
|
115
|
+
} | undefined;
|
|
88
116
|
samplingRate?: {
|
|
89
117
|
type: NumberConstructor;
|
|
90
118
|
required: false;
|
|
@@ -113,13 +141,12 @@ declare const Databuddy: vue.DefineComponent<{
|
|
|
113
141
|
type: NumberConstructor;
|
|
114
142
|
required: false;
|
|
115
143
|
} | undefined;
|
|
116
|
-
}, () => null, unknown, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, Record<string, any>, string, vue.VNodeProps & vue.AllowedComponentProps & vue.ComponentCustomProps, Readonly<{
|
|
117
|
-
|
|
118
|
-
|
|
144
|
+
}, () => null, unknown, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, Record<string, any>, string, vue.VNodeProps & vue.AllowedComponentProps & vue.ComponentCustomProps, Readonly<{} & {
|
|
145
|
+
sdk?: string | undefined;
|
|
146
|
+
clientId?: string | undefined;
|
|
119
147
|
clientSecret?: string | undefined;
|
|
120
148
|
apiUrl?: string | undefined;
|
|
121
149
|
scriptUrl?: string | undefined;
|
|
122
|
-
sdk?: string | undefined;
|
|
123
150
|
sdkVersion?: string | undefined;
|
|
124
151
|
disabled?: boolean | undefined;
|
|
125
152
|
waitForProfile?: boolean | undefined;
|
|
@@ -136,6 +163,13 @@ declare const Databuddy: vue.DefineComponent<{
|
|
|
136
163
|
trackPerformance?: boolean | undefined;
|
|
137
164
|
trackWebVitals?: boolean | undefined;
|
|
138
165
|
trackErrors?: boolean | undefined;
|
|
166
|
+
enableObservability?: boolean | undefined;
|
|
167
|
+
observabilityService?: string | undefined;
|
|
168
|
+
observabilityEnvironment?: string | undefined;
|
|
169
|
+
observabilityVersion?: string | undefined;
|
|
170
|
+
enableLogging?: boolean | undefined;
|
|
171
|
+
enableTracing?: boolean | undefined;
|
|
172
|
+
enableErrorTracking?: boolean | undefined;
|
|
139
173
|
samplingRate?: number | undefined;
|
|
140
174
|
enableRetries?: boolean | undefined;
|
|
141
175
|
maxRetries?: number | undefined;
|
package/dist/vue/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent, ref, onMounted, onUnmounted, watch } from 'vue';
|
|
2
|
-
import { i as isScriptInjected, c as createScript } from '../shared/@databuddy/sdk.
|
|
2
|
+
import { i as isScriptInjected, c as createScript } from '../shared/@databuddy/sdk.DqscWwcO.mjs';
|
|
3
3
|
|
|
4
4
|
const Databuddy = defineComponent({
|
|
5
5
|
props: {},
|
package/package.json
CHANGED
|
@@ -1,58 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@databuddy/sdk",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Official Databuddy Analytics SDK",
|
|
5
|
-
"main": "./dist/core/index.mjs",
|
|
6
|
-
"types": "./dist/core/index.d.ts",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"private": false,
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "unbuild"
|
|
11
|
-
},
|
|
12
|
-
"devDependencies": {
|
|
13
|
-
"@types/node": "^20.0.0",
|
|
14
|
-
"@vitejs/plugin-react": "^5.0.0",
|
|
15
|
-
"react": "18.0.0",
|
|
16
|
-
"typescript": "catalog:",
|
|
17
|
-
"unbuild": "^3.6.1",
|
|
18
|
-
"vue": "3.0.0",
|
|
19
|
-
"vue-sfc-transformer": "^0.1.16"
|
|
20
|
-
},
|
|
21
|
-
"peerDependencies": {
|
|
22
|
-
"react": ">=18",
|
|
23
|
-
"vue": ">=3"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"types": "./dist/
|
|
40
|
-
"import": "./dist/
|
|
41
|
-
},
|
|
42
|
-
"./
|
|
43
|
-
"types": "./dist/
|
|
44
|
-
"import": "./dist/
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@databuddy/sdk",
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "Official Databuddy Analytics SDK",
|
|
5
|
+
"main": "./dist/core/index.mjs",
|
|
6
|
+
"types": "./dist/core/index.d.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"private": false,
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "unbuild"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/node": "^20.0.0",
|
|
14
|
+
"@vitejs/plugin-react": "^5.0.0",
|
|
15
|
+
"react": "18.0.0",
|
|
16
|
+
"typescript": "catalog:",
|
|
17
|
+
"unbuild": "^3.6.1",
|
|
18
|
+
"vue": "3.0.0",
|
|
19
|
+
"vue-sfc-transformer": "^0.1.16"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"react": ">=18",
|
|
23
|
+
"vue": ">=3",
|
|
24
|
+
"jotai": ">=2.0.0"
|
|
25
|
+
},
|
|
26
|
+
"peerDependenciesMeta": {
|
|
27
|
+
"react": {
|
|
28
|
+
"optional": true
|
|
29
|
+
},
|
|
30
|
+
"vue": {
|
|
31
|
+
"optional": true
|
|
32
|
+
},
|
|
33
|
+
"jotai": {
|
|
34
|
+
"optional": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/core/index.d.ts",
|
|
40
|
+
"import": "./dist/core/index.mjs"
|
|
41
|
+
},
|
|
42
|
+
"./react": {
|
|
43
|
+
"types": "./dist/react/index.d.ts",
|
|
44
|
+
"import": "./dist/react/index.mjs"
|
|
45
|
+
},
|
|
46
|
+
"./vue": {
|
|
47
|
+
"types": "./dist/vue/index.d.ts",
|
|
48
|
+
"import": "./dist/vue/index.mjs"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist"
|
|
53
|
+
],
|
|
54
|
+
"keywords": [
|
|
55
|
+
"analytics",
|
|
56
|
+
"tracking",
|
|
57
|
+
"databuddy",
|
|
58
|
+
"sdk",
|
|
59
|
+
"react",
|
|
60
|
+
"vue"
|
|
61
|
+
]
|
|
62
|
+
}
|