@databuddy/sdk 2.1.78 → 2.2.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.
@@ -1,6 +1,6 @@
1
- import { D as Databuddy$1 } from '../shared/@databuddy/sdk.CHuEu0ou.mjs';
2
- export { d as detectClientId } from '../shared/@databuddy/sdk.CHuEu0ou.mjs';
3
- export { B as BrowserFlagStorage, C as CoreFlagsManager, c as createScript, i as isScriptInjected } from '../shared/@databuddy/sdk.ItWNeH-Y.mjs';
1
+ import { D as Databuddy$1 } from '../shared/@databuddy/sdk.aVQee-4k.mjs';
2
+ export { d as detectClientId } from '../shared/@databuddy/sdk.aVQee-4k.mjs';
3
+ export { B as BrowserFlagStorage, C as CoreFlagsManager, c as createScript, i as isScriptInjected } from '../shared/@databuddy/sdk.tFAHtL2M.mjs';
4
4
 
5
5
  function isTrackerAvailable() {
6
6
  return typeof window !== "undefined" && (!!window.databuddy || !!window.db);
@@ -0,0 +1,132 @@
1
+ interface Logger {
2
+ info(msg: string, data?: Record<string, unknown>): void;
3
+ error(msg: string, data?: Record<string, unknown>): void;
4
+ warn(msg: string, data?: Record<string, unknown>): void;
5
+ debug(msg: string, data?: Record<string, unknown>): void;
6
+ }
7
+
8
+ interface DatabuddyConfig {
9
+ clientId: string;
10
+ apiUrl?: string;
11
+ debug?: boolean;
12
+ logger?: Logger;
13
+ /**
14
+ * Enable automatic batching of events
15
+ * Default: true
16
+ */
17
+ enableBatching?: boolean;
18
+ /**
19
+ * Number of events to batch before auto-flushing
20
+ * Default: 10, Max: 100
21
+ */
22
+ batchSize?: number;
23
+ /**
24
+ * Time in milliseconds before auto-flushing batched events
25
+ * Default: 2000ms (2 seconds)
26
+ */
27
+ batchTimeout?: number;
28
+ /**
29
+ * Maximum number of events to queue before auto-flushing
30
+ * Default: 1000
31
+ */
32
+ maxQueueSize?: number;
33
+ }
34
+ interface CustomEventInput {
35
+ name: string;
36
+ eventId?: string;
37
+ anonymousId?: string | null;
38
+ sessionId?: string | null;
39
+ timestamp?: number | null;
40
+ properties?: Record<string, unknown> | null;
41
+ }
42
+ interface EventResponse {
43
+ success: boolean;
44
+ eventId?: string;
45
+ error?: string;
46
+ }
47
+ interface BatchEventInput {
48
+ type: 'custom';
49
+ name: string;
50
+ eventId?: string;
51
+ anonymousId?: string | null;
52
+ sessionId?: string | null;
53
+ timestamp?: number | null;
54
+ properties?: Record<string, unknown> | null;
55
+ }
56
+ interface BatchEventResponse {
57
+ success: boolean;
58
+ processed?: number;
59
+ results?: Array<{
60
+ status: string;
61
+ type?: string;
62
+ eventId?: string;
63
+ message?: string;
64
+ error?: string;
65
+ }>;
66
+ error?: string;
67
+ }
68
+
69
+ declare class Databuddy {
70
+ private clientId;
71
+ private apiUrl;
72
+ private logger;
73
+ private enableBatching;
74
+ private batchSize;
75
+ private batchTimeout;
76
+ private queue;
77
+ private flushTimer;
78
+ constructor(config: DatabuddyConfig);
79
+ /**
80
+ * Track a custom event
81
+ * If batching is enabled, queues the event and auto-flushes when batch size is reached or timeout expires
82
+ * If batching is disabled, sends the event immediately
83
+ *
84
+ * @param event - Custom event data
85
+ * @returns Response indicating success or failure
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * await client.track({
90
+ * name: 'user_signup',
91
+ * properties: { plan: 'pro' }
92
+ * });
93
+ * ```
94
+ */
95
+ track(event: CustomEventInput): Promise<EventResponse>;
96
+ private send;
97
+ private scheduleFlush;
98
+ /**
99
+ * Manually flush all queued events
100
+ * Important for serverless/stateless environments where you need to ensure events are sent before the process exits
101
+ *
102
+ * @returns Response with batch results
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // In serverless function
107
+ * await client.track({ name: 'api_call' });
108
+ * await client.flush(); // Ensure events are sent before function exits
109
+ * ```
110
+ */
111
+ flush(): Promise<BatchEventResponse>;
112
+ /**
113
+ * Send multiple custom events in a single batch request
114
+ * Max 100 events per batch
115
+ * Note: Usually you don't need to call this directly - use track() with batching enabled instead
116
+ *
117
+ * @param events - Array of custom events
118
+ * @returns Response with results for each event
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * await client.batch([
123
+ * { type: 'custom', name: 'event1', properties: { foo: 'bar' } },
124
+ * { type: 'custom', name: 'event2', properties: { baz: 'qux' } }
125
+ * ]);
126
+ * ```
127
+ */
128
+ batch(events: BatchEventInput[]): Promise<BatchEventResponse>;
129
+ }
130
+
131
+ export { Databuddy, Databuddy as db };
132
+ export type { BatchEventInput, BatchEventResponse, CustomEventInput, DatabuddyConfig, EventResponse, Logger };
@@ -0,0 +1,132 @@
1
+ interface Logger {
2
+ info(msg: string, data?: Record<string, unknown>): void;
3
+ error(msg: string, data?: Record<string, unknown>): void;
4
+ warn(msg: string, data?: Record<string, unknown>): void;
5
+ debug(msg: string, data?: Record<string, unknown>): void;
6
+ }
7
+
8
+ interface DatabuddyConfig {
9
+ clientId: string;
10
+ apiUrl?: string;
11
+ debug?: boolean;
12
+ logger?: Logger;
13
+ /**
14
+ * Enable automatic batching of events
15
+ * Default: true
16
+ */
17
+ enableBatching?: boolean;
18
+ /**
19
+ * Number of events to batch before auto-flushing
20
+ * Default: 10, Max: 100
21
+ */
22
+ batchSize?: number;
23
+ /**
24
+ * Time in milliseconds before auto-flushing batched events
25
+ * Default: 2000ms (2 seconds)
26
+ */
27
+ batchTimeout?: number;
28
+ /**
29
+ * Maximum number of events to queue before auto-flushing
30
+ * Default: 1000
31
+ */
32
+ maxQueueSize?: number;
33
+ }
34
+ interface CustomEventInput {
35
+ name: string;
36
+ eventId?: string;
37
+ anonymousId?: string | null;
38
+ sessionId?: string | null;
39
+ timestamp?: number | null;
40
+ properties?: Record<string, unknown> | null;
41
+ }
42
+ interface EventResponse {
43
+ success: boolean;
44
+ eventId?: string;
45
+ error?: string;
46
+ }
47
+ interface BatchEventInput {
48
+ type: 'custom';
49
+ name: string;
50
+ eventId?: string;
51
+ anonymousId?: string | null;
52
+ sessionId?: string | null;
53
+ timestamp?: number | null;
54
+ properties?: Record<string, unknown> | null;
55
+ }
56
+ interface BatchEventResponse {
57
+ success: boolean;
58
+ processed?: number;
59
+ results?: Array<{
60
+ status: string;
61
+ type?: string;
62
+ eventId?: string;
63
+ message?: string;
64
+ error?: string;
65
+ }>;
66
+ error?: string;
67
+ }
68
+
69
+ declare class Databuddy {
70
+ private clientId;
71
+ private apiUrl;
72
+ private logger;
73
+ private enableBatching;
74
+ private batchSize;
75
+ private batchTimeout;
76
+ private queue;
77
+ private flushTimer;
78
+ constructor(config: DatabuddyConfig);
79
+ /**
80
+ * Track a custom event
81
+ * If batching is enabled, queues the event and auto-flushes when batch size is reached or timeout expires
82
+ * If batching is disabled, sends the event immediately
83
+ *
84
+ * @param event - Custom event data
85
+ * @returns Response indicating success or failure
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * await client.track({
90
+ * name: 'user_signup',
91
+ * properties: { plan: 'pro' }
92
+ * });
93
+ * ```
94
+ */
95
+ track(event: CustomEventInput): Promise<EventResponse>;
96
+ private send;
97
+ private scheduleFlush;
98
+ /**
99
+ * Manually flush all queued events
100
+ * Important for serverless/stateless environments where you need to ensure events are sent before the process exits
101
+ *
102
+ * @returns Response with batch results
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // In serverless function
107
+ * await client.track({ name: 'api_call' });
108
+ * await client.flush(); // Ensure events are sent before function exits
109
+ * ```
110
+ */
111
+ flush(): Promise<BatchEventResponse>;
112
+ /**
113
+ * Send multiple custom events in a single batch request
114
+ * Max 100 events per batch
115
+ * Note: Usually you don't need to call this directly - use track() with batching enabled instead
116
+ *
117
+ * @param events - Array of custom events
118
+ * @returns Response with results for each event
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * await client.batch([
123
+ * { type: 'custom', name: 'event1', properties: { foo: 'bar' } },
124
+ * { type: 'custom', name: 'event2', properties: { baz: 'qux' } }
125
+ * ]);
126
+ * ```
127
+ */
128
+ batch(events: BatchEventInput[]): Promise<BatchEventResponse>;
129
+ }
130
+
131
+ export { Databuddy, Databuddy as db };
132
+ export type { BatchEventInput, BatchEventResponse, CustomEventInput, DatabuddyConfig, EventResponse, Logger };
@@ -0,0 +1,344 @@
1
+ function createLogger(debug = false) {
2
+ try {
3
+ const pino = require("pino");
4
+ return pino({
5
+ level: debug ? "debug" : "info",
6
+ name: "databuddy"
7
+ });
8
+ } catch {
9
+ return createConsoleLogger(debug);
10
+ }
11
+ }
12
+ function createConsoleLogger(debug) {
13
+ const noop = () => {
14
+ };
15
+ return {
16
+ info(msg, data) {
17
+ if (debug) {
18
+ console.info(`[Databuddy] ${msg}`, data ? JSON.stringify(data) : "");
19
+ }
20
+ },
21
+ error(msg, data) {
22
+ if (debug) {
23
+ console.error(
24
+ `[Databuddy] ${msg}`,
25
+ data ? JSON.stringify(data) : ""
26
+ );
27
+ }
28
+ },
29
+ warn(msg, data) {
30
+ if (debug) {
31
+ console.warn(`[Databuddy] ${msg}`, data ? JSON.stringify(data) : "");
32
+ }
33
+ },
34
+ debug: debug ? (msg, data) => {
35
+ console.debug(
36
+ `[Databuddy] ${msg}`,
37
+ data ? JSON.stringify(data) : ""
38
+ );
39
+ } : noop
40
+ };
41
+ }
42
+ function createNoopLogger() {
43
+ const noop = () => {
44
+ };
45
+ return {
46
+ info: noop,
47
+ error: noop,
48
+ warn: noop,
49
+ debug: noop
50
+ };
51
+ }
52
+
53
+ class EventQueue {
54
+ queue = [];
55
+ maxSize;
56
+ constructor(maxSize) {
57
+ this.maxSize = maxSize;
58
+ }
59
+ add(event) {
60
+ this.queue.push(event);
61
+ return this.queue.length >= this.maxSize;
62
+ }
63
+ getAll() {
64
+ return [...this.queue];
65
+ }
66
+ clear() {
67
+ this.queue = [];
68
+ }
69
+ size() {
70
+ return this.queue.length;
71
+ }
72
+ isEmpty() {
73
+ return this.queue.length === 0;
74
+ }
75
+ }
76
+
77
+ const DEFAULT_API_URL = "https://basket.databuddy.cc";
78
+ const DEFAULT_BATCH_SIZE = 10;
79
+ const DEFAULT_BATCH_TIMEOUT = 2e3;
80
+ const DEFAULT_MAX_QUEUE_SIZE = 1e3;
81
+ class Databuddy {
82
+ clientId;
83
+ apiUrl;
84
+ logger;
85
+ enableBatching;
86
+ batchSize;
87
+ batchTimeout;
88
+ queue;
89
+ flushTimer = null;
90
+ constructor(config) {
91
+ if (!config.clientId || typeof config.clientId !== "string") {
92
+ throw new Error("clientId is required and must be a string");
93
+ }
94
+ this.clientId = config.clientId.trim();
95
+ this.apiUrl = config.apiUrl?.trim() || DEFAULT_API_URL;
96
+ this.enableBatching = config.enableBatching !== false;
97
+ this.batchSize = Math.min(config.batchSize || DEFAULT_BATCH_SIZE, 100);
98
+ this.batchTimeout = config.batchTimeout || DEFAULT_BATCH_TIMEOUT;
99
+ this.queue = new EventQueue(config.maxQueueSize || DEFAULT_MAX_QUEUE_SIZE);
100
+ if (config.logger) {
101
+ this.logger = config.logger;
102
+ } else if (config.debug) {
103
+ this.logger = createLogger(true);
104
+ } else {
105
+ this.logger = createNoopLogger();
106
+ }
107
+ this.logger.info("Initialized", {
108
+ clientId: this.clientId,
109
+ apiUrl: this.apiUrl,
110
+ enableBatching: this.enableBatching,
111
+ batchSize: this.batchSize,
112
+ batchTimeout: this.batchTimeout
113
+ });
114
+ }
115
+ /**
116
+ * Track a custom event
117
+ * If batching is enabled, queues the event and auto-flushes when batch size is reached or timeout expires
118
+ * If batching is disabled, sends the event immediately
119
+ *
120
+ * @param event - Custom event data
121
+ * @returns Response indicating success or failure
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * await client.track({
126
+ * name: 'user_signup',
127
+ * properties: { plan: 'pro' }
128
+ * });
129
+ * ```
130
+ */
131
+ async track(event) {
132
+ if (!event.name || typeof event.name !== "string") {
133
+ return {
134
+ success: false,
135
+ error: "Event name is required and must be a string"
136
+ };
137
+ }
138
+ const batchEvent = {
139
+ type: "custom",
140
+ name: event.name,
141
+ eventId: event.eventId,
142
+ anonymousId: event.anonymousId,
143
+ sessionId: event.sessionId,
144
+ timestamp: event.timestamp,
145
+ properties: event.properties || null
146
+ };
147
+ if (!this.enableBatching) {
148
+ return this.send(batchEvent);
149
+ }
150
+ const shouldFlush = this.queue.add(batchEvent);
151
+ this.logger.debug("Event queued", { queueSize: this.queue.size() });
152
+ this.scheduleFlush();
153
+ if (shouldFlush || this.queue.size() >= this.batchSize) {
154
+ await this.flush();
155
+ }
156
+ return { success: true };
157
+ }
158
+ async send(event) {
159
+ try {
160
+ const url = `${this.apiUrl}/?client_id=${encodeURIComponent(this.clientId)}`;
161
+ this.logger.info("\u{1F4E4} SENDING SINGLE EVENT:", {
162
+ name: event.name,
163
+ properties: JSON.stringify(event.properties, null, 2),
164
+ propertiesCount: Object.keys(event.properties || {}).length
165
+ });
166
+ const response = await fetch(url, {
167
+ method: "POST",
168
+ headers: {
169
+ "Content-Type": "application/json"
170
+ },
171
+ body: JSON.stringify(event)
172
+ });
173
+ if (!response.ok) {
174
+ const errorText = await response.text().catch(() => "Unknown error");
175
+ this.logger.error("Request failed", {
176
+ status: response.status,
177
+ statusText: response.statusText,
178
+ body: errorText
179
+ });
180
+ return {
181
+ success: false,
182
+ error: `HTTP ${response.status}: ${response.statusText}`
183
+ };
184
+ }
185
+ const data = await response.json();
186
+ this.logger.info("Response received", data);
187
+ if (data.status === "success") {
188
+ return {
189
+ success: true,
190
+ eventId: data.eventId
191
+ };
192
+ }
193
+ return {
194
+ success: false,
195
+ error: data.message || "Unknown error from server"
196
+ };
197
+ } catch (error) {
198
+ this.logger.error("Request error", {
199
+ error: error instanceof Error ? error.message : String(error)
200
+ });
201
+ return {
202
+ success: false,
203
+ error: error instanceof Error ? error.message : "Network request failed"
204
+ };
205
+ }
206
+ }
207
+ scheduleFlush() {
208
+ if (this.flushTimer) {
209
+ return;
210
+ }
211
+ this.flushTimer = setTimeout(() => {
212
+ this.flush().catch((error) => {
213
+ this.logger.error("Auto-flush error", {
214
+ error: error instanceof Error ? error.message : String(error)
215
+ });
216
+ });
217
+ }, this.batchTimeout);
218
+ }
219
+ /**
220
+ * Manually flush all queued events
221
+ * Important for serverless/stateless environments where you need to ensure events are sent before the process exits
222
+ *
223
+ * @returns Response with batch results
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * // In serverless function
228
+ * await client.track({ name: 'api_call' });
229
+ * await client.flush(); // Ensure events are sent before function exits
230
+ * ```
231
+ */
232
+ async flush() {
233
+ if (this.flushTimer) {
234
+ clearTimeout(this.flushTimer);
235
+ this.flushTimer = null;
236
+ }
237
+ if (this.queue.isEmpty()) {
238
+ return {
239
+ success: true,
240
+ processed: 0,
241
+ results: []
242
+ };
243
+ }
244
+ const events = this.queue.getAll();
245
+ this.queue.clear();
246
+ this.logger.info("Flushing events", { count: events.length });
247
+ return this.batch(events);
248
+ }
249
+ /**
250
+ * Send multiple custom events in a single batch request
251
+ * Max 100 events per batch
252
+ * Note: Usually you don't need to call this directly - use track() with batching enabled instead
253
+ *
254
+ * @param events - Array of custom events
255
+ * @returns Response with results for each event
256
+ *
257
+ * @example
258
+ * ```typescript
259
+ * await client.batch([
260
+ * { type: 'custom', name: 'event1', properties: { foo: 'bar' } },
261
+ * { type: 'custom', name: 'event2', properties: { baz: 'qux' } }
262
+ * ]);
263
+ * ```
264
+ */
265
+ async batch(events) {
266
+ if (!Array.isArray(events)) {
267
+ return {
268
+ success: false,
269
+ error: "Events must be an array"
270
+ };
271
+ }
272
+ if (events.length === 0) {
273
+ return {
274
+ success: false,
275
+ error: "Events array cannot be empty"
276
+ };
277
+ }
278
+ if (events.length > 100) {
279
+ return {
280
+ success: false,
281
+ error: "Batch size cannot exceed 100 events"
282
+ };
283
+ }
284
+ for (const event of events) {
285
+ if (!event.name || typeof event.name !== "string") {
286
+ return {
287
+ success: false,
288
+ error: "All events must have a valid name"
289
+ };
290
+ }
291
+ }
292
+ try {
293
+ const url = `${this.apiUrl}/batch?client_id=${encodeURIComponent(this.clientId)}`;
294
+ this.logger.info("\u{1F4E6} SENDING BATCH EVENTS:", {
295
+ count: events.length,
296
+ firstEventName: events[0]?.name,
297
+ firstEventProperties: JSON.stringify(events[0]?.properties, null, 2),
298
+ firstEventPropertiesCount: Object.keys(events[0]?.properties || {}).length
299
+ });
300
+ const response = await fetch(url, {
301
+ method: "POST",
302
+ headers: {
303
+ "Content-Type": "application/json"
304
+ },
305
+ body: JSON.stringify(events)
306
+ });
307
+ if (!response.ok) {
308
+ const errorText = await response.text().catch(() => "Unknown error");
309
+ this.logger.error("Batch request failed", {
310
+ status: response.status,
311
+ statusText: response.statusText,
312
+ body: errorText
313
+ });
314
+ return {
315
+ success: false,
316
+ error: `HTTP ${response.status}: ${response.statusText}`
317
+ };
318
+ }
319
+ const data = await response.json();
320
+ this.logger.info("Batch response received", data);
321
+ if (data.status === "success") {
322
+ return {
323
+ success: true,
324
+ processed: data.processed,
325
+ results: data.results
326
+ };
327
+ }
328
+ return {
329
+ success: false,
330
+ error: data.message || "Unknown error from server"
331
+ };
332
+ } catch (error) {
333
+ this.logger.error("Batch request error", {
334
+ error: error instanceof Error ? error.message : String(error)
335
+ });
336
+ return {
337
+ success: false,
338
+ error: error instanceof Error ? error.message : "Network request failed"
339
+ };
340
+ }
341
+ }
342
+ }
343
+
344
+ export { Databuddy, Databuddy as db };
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
 
3
- export { D as Databuddy } from '../shared/@databuddy/sdk.CHuEu0ou.mjs';
3
+ export { D as Databuddy } from '../shared/@databuddy/sdk.aVQee-4k.mjs';
4
4
  import { createStore, atom, Provider, useAtom } from 'jotai';
5
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';
6
+ import { B as BrowserFlagStorage, C as CoreFlagsManager, l as logger } from '../shared/@databuddy/sdk.tFAHtL2M.mjs';
7
7
 
8
8
  const flagsStore = createStore();
9
9
  const managerAtom = atom(null);
@@ -1,4 +1,4 @@
1
- import { i as isScriptInjected, c as createScript } from './sdk.ItWNeH-Y.mjs';
1
+ import { i as isScriptInjected, c as createScript } from './sdk.tFAHtL2M.mjs';
2
2
 
3
3
  function detectClientId(providedClientId) {
4
4
  if (providedClientId) {
@@ -434,7 +434,7 @@ class CoreFlagsManager {
434
434
  }
435
435
  }
436
436
 
437
- const version = "2.1.78";
437
+ const version = "2.2.0";
438
438
 
439
439
  const INJECTED_SCRIPT_ATTRIBUTE = "data-databuddy-injected";
440
440
  function isScriptInjected() {
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, ref, onMounted, onUnmounted, watch, reactive, watchEffect, computed } from 'vue';
2
- import { i as isScriptInjected, c as createScript, B as BrowserFlagStorage, C as CoreFlagsManager } from '../shared/@databuddy/sdk.ItWNeH-Y.mjs';
2
+ import { i as isScriptInjected, c as createScript, B as BrowserFlagStorage, C as CoreFlagsManager } from '../shared/@databuddy/sdk.tFAHtL2M.mjs';
3
3
 
4
4
  const Databuddy = defineComponent({
5
5
  props: {},
package/package.json CHANGED
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "name": "@databuddy/sdk",
3
- "version": "2.1.78",
3
+ "version": "2.2.0",
4
4
  "description": "Official Databuddy Analytics SDK",
5
5
  "main": "./dist/core/index.mjs",
6
6
  "types": "./dist/core/index.d.ts",
7
7
  "license": "MIT",
8
8
  "private": false,
9
9
  "scripts": {
10
- "build": "unbuild"
10
+ "build": "unbuild",
11
+ "test": "bun test"
11
12
  },
12
13
  "dependencies": {
13
14
  "jotai": ">=2.0.0"
14
15
  },
16
+ "optionalDependencies": {
17
+ "pino": "^9.0.0"
18
+ },
15
19
  "devDependencies": {
16
20
  "@types/node": "^20.0.0",
17
21
  "@vitejs/plugin-react": "^5.0.0",
@@ -42,6 +46,10 @@
42
46
  "./vue": {
43
47
  "types": "./dist/vue/index.d.ts",
44
48
  "import": "./dist/vue/index.mjs"
49
+ },
50
+ "./node": {
51
+ "types": "./dist/node/index.d.ts",
52
+ "import": "./dist/node/index.mjs"
45
53
  }
46
54
  },
47
55
  "files": [