luzzi-analytics 0.1.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.
- package/README.md +94 -0
- package/dist/index.d.mts +118 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +390 -0
- package/dist/index.mjs +357 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @luzzi/analytics
|
|
2
|
+
|
|
3
|
+
Simple, plug-and-play analytics SDK for solo builders.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @luzzi/analytics
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import luzzi from "@luzzi/analytics";
|
|
15
|
+
|
|
16
|
+
// Initialize with your API key
|
|
17
|
+
luzzi.init("pk_live_xxx");
|
|
18
|
+
|
|
19
|
+
// Track events
|
|
20
|
+
luzzi.track("button_clicked", { button: "signup" });
|
|
21
|
+
|
|
22
|
+
// Identify users
|
|
23
|
+
luzzi.identify("user_123", { plan: "pro" });
|
|
24
|
+
|
|
25
|
+
// Reset on logout
|
|
26
|
+
luzzi.reset();
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## API
|
|
30
|
+
|
|
31
|
+
### `init(apiKey, config?)`
|
|
32
|
+
|
|
33
|
+
Initialize the SDK. Must be called before any other method.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
luzzi.init("pk_live_xxx", {
|
|
37
|
+
apiUrl: "https://api.luzzi.dev", // Custom API URL (optional)
|
|
38
|
+
batchSize: 10, // Events to batch before sending (default: 10)
|
|
39
|
+
flushInterval: 30000, // Flush interval in ms (default: 30s)
|
|
40
|
+
debug: false, // Enable debug logging (default: false)
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### `track(eventName, properties?)`
|
|
45
|
+
|
|
46
|
+
Track an event with optional properties.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
luzzi.track("purchase_completed", {
|
|
50
|
+
amount: 99.99,
|
|
51
|
+
currency: "USD",
|
|
52
|
+
product_id: "prod_123",
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `identify(userId, traits?)`
|
|
57
|
+
|
|
58
|
+
Identify the current user with optional traits.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
luzzi.identify("user_123", {
|
|
62
|
+
email: "user@example.com",
|
|
63
|
+
plan: "pro",
|
|
64
|
+
created_at: "2024-01-01",
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `reset()`
|
|
69
|
+
|
|
70
|
+
Reset the current user. Call this on logout.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
luzzi.reset();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### `flush()`
|
|
77
|
+
|
|
78
|
+
Manually flush pending events to the server.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
await luzzi.flush();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Automatic Features
|
|
85
|
+
|
|
86
|
+
- **Session tracking**: Automatically generates a unique session ID
|
|
87
|
+
- **Device info**: Collects OS, browser, screen size, language, timezone
|
|
88
|
+
- **Batching**: Events are batched (10 events or 30 seconds)
|
|
89
|
+
- **Auto-flush**: Events are flushed on page unload/visibility change
|
|
90
|
+
- **Retry**: Failed events are re-queued and retried
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Luzzi Analytics SDK Types
|
|
3
|
+
*/
|
|
4
|
+
interface LuzziConfig {
|
|
5
|
+
/** API endpoint URL (defaults to https://api.luzzi.dev) */
|
|
6
|
+
apiUrl?: string;
|
|
7
|
+
/** Batch size before auto-flush (default: 10) */
|
|
8
|
+
batchSize?: number;
|
|
9
|
+
/** Flush interval in milliseconds (default: 30000 = 30s) */
|
|
10
|
+
flushInterval?: number;
|
|
11
|
+
/** Enable debug logging */
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface DeviceInfo {
|
|
15
|
+
os?: string;
|
|
16
|
+
app_version?: string;
|
|
17
|
+
browser?: string;
|
|
18
|
+
screen_width?: number;
|
|
19
|
+
screen_height?: number;
|
|
20
|
+
language?: string;
|
|
21
|
+
timezone?: string;
|
|
22
|
+
}
|
|
23
|
+
interface EventPayload {
|
|
24
|
+
event: string;
|
|
25
|
+
properties?: Record<string, unknown>;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
session_id: string;
|
|
28
|
+
user_id?: string;
|
|
29
|
+
device: DeviceInfo;
|
|
30
|
+
}
|
|
31
|
+
interface UserTraits {
|
|
32
|
+
[key: string]: unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Luzzi Analytics SDK
|
|
37
|
+
*
|
|
38
|
+
* Simple, plug-and-play analytics for solo builders.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import luzzi from "@luzzi/analytics";
|
|
43
|
+
*
|
|
44
|
+
* // Initialize with your API key
|
|
45
|
+
* luzzi.init("pk_live_xxx");
|
|
46
|
+
*
|
|
47
|
+
* // Track events
|
|
48
|
+
* luzzi.track("button_clicked", { button: "signup" });
|
|
49
|
+
*
|
|
50
|
+
* // Identify users
|
|
51
|
+
* luzzi.identify("user_123", { plan: "pro" });
|
|
52
|
+
*
|
|
53
|
+
* // Reset on logout
|
|
54
|
+
* luzzi.reset();
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Luzzi Analytics SDK
|
|
60
|
+
*/
|
|
61
|
+
declare const luzzi: {
|
|
62
|
+
/**
|
|
63
|
+
* Initialize the SDK with your API key
|
|
64
|
+
* Must be called before any other method
|
|
65
|
+
*
|
|
66
|
+
* @param apiKey - Your Luzzi API key (pk_live_xxx or pk_test_xxx)
|
|
67
|
+
* @param config - Optional configuration
|
|
68
|
+
*/
|
|
69
|
+
init: (apiKey: string, config?: LuzziConfig) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Track an event
|
|
72
|
+
*
|
|
73
|
+
* @param eventName - Name of the event (e.g., "button_clicked", "page_viewed")
|
|
74
|
+
* @param properties - Optional event properties
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* luzzi.track("purchase_completed", { amount: 99.99, currency: "USD" });
|
|
78
|
+
*/
|
|
79
|
+
track: (eventName: string, properties?: Record<string, unknown>) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Identify the current user
|
|
82
|
+
*
|
|
83
|
+
* @param userId - Unique user identifier
|
|
84
|
+
* @param traits - Optional user traits/properties
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* luzzi.identify("user_123", { email: "user@example.com", plan: "pro" });
|
|
88
|
+
*/
|
|
89
|
+
identify: (userId: string, traits?: UserTraits) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Reset the current user (call on logout)
|
|
92
|
+
* Clears user ID and generates a new session
|
|
93
|
+
*/
|
|
94
|
+
reset: () => void;
|
|
95
|
+
/**
|
|
96
|
+
* Manually flush pending events to the server
|
|
97
|
+
* Events are automatically flushed on a timer and on page unload
|
|
98
|
+
*/
|
|
99
|
+
flush: () => Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Get the current session ID
|
|
102
|
+
*/
|
|
103
|
+
getSessionId: () => string;
|
|
104
|
+
/**
|
|
105
|
+
* Get the current user ID (if identified)
|
|
106
|
+
*/
|
|
107
|
+
getUserId: () => string | undefined;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
declare const init: (apiKey: string, config?: LuzziConfig) => void;
|
|
111
|
+
declare const track: (eventName: string, properties?: Record<string, unknown>) => void;
|
|
112
|
+
declare const identify: (userId: string, traits?: UserTraits) => void;
|
|
113
|
+
declare const reset: () => void;
|
|
114
|
+
declare const flush: () => Promise<void>;
|
|
115
|
+
declare const getSessionId: () => string;
|
|
116
|
+
declare const getUserId: () => string | undefined;
|
|
117
|
+
|
|
118
|
+
export { type DeviceInfo, type EventPayload, type LuzziConfig, type UserTraits, luzzi as default, flush, getSessionId, getUserId, identify, init, reset, track };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Luzzi Analytics SDK Types
|
|
3
|
+
*/
|
|
4
|
+
interface LuzziConfig {
|
|
5
|
+
/** API endpoint URL (defaults to https://api.luzzi.dev) */
|
|
6
|
+
apiUrl?: string;
|
|
7
|
+
/** Batch size before auto-flush (default: 10) */
|
|
8
|
+
batchSize?: number;
|
|
9
|
+
/** Flush interval in milliseconds (default: 30000 = 30s) */
|
|
10
|
+
flushInterval?: number;
|
|
11
|
+
/** Enable debug logging */
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface DeviceInfo {
|
|
15
|
+
os?: string;
|
|
16
|
+
app_version?: string;
|
|
17
|
+
browser?: string;
|
|
18
|
+
screen_width?: number;
|
|
19
|
+
screen_height?: number;
|
|
20
|
+
language?: string;
|
|
21
|
+
timezone?: string;
|
|
22
|
+
}
|
|
23
|
+
interface EventPayload {
|
|
24
|
+
event: string;
|
|
25
|
+
properties?: Record<string, unknown>;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
session_id: string;
|
|
28
|
+
user_id?: string;
|
|
29
|
+
device: DeviceInfo;
|
|
30
|
+
}
|
|
31
|
+
interface UserTraits {
|
|
32
|
+
[key: string]: unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Luzzi Analytics SDK
|
|
37
|
+
*
|
|
38
|
+
* Simple, plug-and-play analytics for solo builders.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import luzzi from "@luzzi/analytics";
|
|
43
|
+
*
|
|
44
|
+
* // Initialize with your API key
|
|
45
|
+
* luzzi.init("pk_live_xxx");
|
|
46
|
+
*
|
|
47
|
+
* // Track events
|
|
48
|
+
* luzzi.track("button_clicked", { button: "signup" });
|
|
49
|
+
*
|
|
50
|
+
* // Identify users
|
|
51
|
+
* luzzi.identify("user_123", { plan: "pro" });
|
|
52
|
+
*
|
|
53
|
+
* // Reset on logout
|
|
54
|
+
* luzzi.reset();
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Luzzi Analytics SDK
|
|
60
|
+
*/
|
|
61
|
+
declare const luzzi: {
|
|
62
|
+
/**
|
|
63
|
+
* Initialize the SDK with your API key
|
|
64
|
+
* Must be called before any other method
|
|
65
|
+
*
|
|
66
|
+
* @param apiKey - Your Luzzi API key (pk_live_xxx or pk_test_xxx)
|
|
67
|
+
* @param config - Optional configuration
|
|
68
|
+
*/
|
|
69
|
+
init: (apiKey: string, config?: LuzziConfig) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Track an event
|
|
72
|
+
*
|
|
73
|
+
* @param eventName - Name of the event (e.g., "button_clicked", "page_viewed")
|
|
74
|
+
* @param properties - Optional event properties
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* luzzi.track("purchase_completed", { amount: 99.99, currency: "USD" });
|
|
78
|
+
*/
|
|
79
|
+
track: (eventName: string, properties?: Record<string, unknown>) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Identify the current user
|
|
82
|
+
*
|
|
83
|
+
* @param userId - Unique user identifier
|
|
84
|
+
* @param traits - Optional user traits/properties
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* luzzi.identify("user_123", { email: "user@example.com", plan: "pro" });
|
|
88
|
+
*/
|
|
89
|
+
identify: (userId: string, traits?: UserTraits) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Reset the current user (call on logout)
|
|
92
|
+
* Clears user ID and generates a new session
|
|
93
|
+
*/
|
|
94
|
+
reset: () => void;
|
|
95
|
+
/**
|
|
96
|
+
* Manually flush pending events to the server
|
|
97
|
+
* Events are automatically flushed on a timer and on page unload
|
|
98
|
+
*/
|
|
99
|
+
flush: () => Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Get the current session ID
|
|
102
|
+
*/
|
|
103
|
+
getSessionId: () => string;
|
|
104
|
+
/**
|
|
105
|
+
* Get the current user ID (if identified)
|
|
106
|
+
*/
|
|
107
|
+
getUserId: () => string | undefined;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
declare const init: (apiKey: string, config?: LuzziConfig) => void;
|
|
111
|
+
declare const track: (eventName: string, properties?: Record<string, unknown>) => void;
|
|
112
|
+
declare const identify: (userId: string, traits?: UserTraits) => void;
|
|
113
|
+
declare const reset: () => void;
|
|
114
|
+
declare const flush: () => Promise<void>;
|
|
115
|
+
declare const getSessionId: () => string;
|
|
116
|
+
declare const getUserId: () => string | undefined;
|
|
117
|
+
|
|
118
|
+
export { type DeviceInfo, type EventPayload, type LuzziConfig, type UserTraits, luzzi as default, flush, getSessionId, getUserId, identify, init, reset, track };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
default: () => index_default,
|
|
24
|
+
flush: () => flush,
|
|
25
|
+
getSessionId: () => getSessionId,
|
|
26
|
+
getUserId: () => getUserId,
|
|
27
|
+
identify: () => identify,
|
|
28
|
+
init: () => init,
|
|
29
|
+
reset: () => reset,
|
|
30
|
+
track: () => track
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
|
|
34
|
+
// src/queue.ts
|
|
35
|
+
var EventQueue = class {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.queue = [];
|
|
38
|
+
this.flushTimer = null;
|
|
39
|
+
this.apiKey = "";
|
|
40
|
+
this.apiUrl = "";
|
|
41
|
+
this.batchSize = 10;
|
|
42
|
+
this.flushInterval = 3e4;
|
|
43
|
+
this.debug = false;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Initialize the queue
|
|
47
|
+
*/
|
|
48
|
+
init(apiKey, apiUrl, batchSize, flushInterval, debug) {
|
|
49
|
+
this.apiKey = apiKey;
|
|
50
|
+
this.apiUrl = apiUrl;
|
|
51
|
+
this.batchSize = batchSize;
|
|
52
|
+
this.flushInterval = flushInterval;
|
|
53
|
+
this.debug = debug;
|
|
54
|
+
this.startFlushTimer();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Add event to queue
|
|
58
|
+
*/
|
|
59
|
+
push(event) {
|
|
60
|
+
this.queue.push(event);
|
|
61
|
+
this.log(`Event queued: ${event.event}`, event);
|
|
62
|
+
if (this.queue.length >= this.batchSize) {
|
|
63
|
+
this.flush();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Flush all events in queue to server
|
|
68
|
+
*/
|
|
69
|
+
async flush() {
|
|
70
|
+
if (this.queue.length === 0) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const events = [...this.queue];
|
|
74
|
+
this.queue = [];
|
|
75
|
+
try {
|
|
76
|
+
const payload = { events };
|
|
77
|
+
this.log(`Flushing ${events.length} events`, payload);
|
|
78
|
+
const response = await fetch(`${this.apiUrl}/v1/events`, {
|
|
79
|
+
method: "POST",
|
|
80
|
+
headers: {
|
|
81
|
+
"Content-Type": "application/json",
|
|
82
|
+
"x-api-key": this.apiKey
|
|
83
|
+
},
|
|
84
|
+
body: JSON.stringify(payload)
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const error = await response.json().catch(() => ({}));
|
|
88
|
+
console.error("[Luzzi] Failed to send events:", error);
|
|
89
|
+
if (this.queue.length < this.batchSize * 10) {
|
|
90
|
+
this.queue.unshift(...events);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
const result = await response.json();
|
|
94
|
+
this.log(`Events sent successfully`, result);
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error("[Luzzi] Failed to send events:", error);
|
|
98
|
+
if (this.queue.length < this.batchSize * 10) {
|
|
99
|
+
this.queue.unshift(...events);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Start auto-flush timer
|
|
105
|
+
*/
|
|
106
|
+
startFlushTimer() {
|
|
107
|
+
this.stopFlushTimer();
|
|
108
|
+
this.flushTimer = setInterval(() => {
|
|
109
|
+
this.flush();
|
|
110
|
+
}, this.flushInterval);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Stop auto-flush timer
|
|
114
|
+
*/
|
|
115
|
+
stopFlushTimer() {
|
|
116
|
+
if (this.flushTimer) {
|
|
117
|
+
clearInterval(this.flushTimer);
|
|
118
|
+
this.flushTimer = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get queue length
|
|
123
|
+
*/
|
|
124
|
+
get length() {
|
|
125
|
+
return this.queue.length;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Clear queue and stop timer
|
|
129
|
+
*/
|
|
130
|
+
reset() {
|
|
131
|
+
this.queue = [];
|
|
132
|
+
this.stopFlushTimer();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Debug log
|
|
136
|
+
*/
|
|
137
|
+
log(message, data) {
|
|
138
|
+
if (this.debug) {
|
|
139
|
+
console.log(`[Luzzi] ${message}`, data || "");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// src/core.ts
|
|
145
|
+
var DEFAULT_API_URL = "https://luzzi.vercel.app/api";
|
|
146
|
+
var DEFAULT_BATCH_SIZE = 10;
|
|
147
|
+
var DEFAULT_FLUSH_INTERVAL = 3e4;
|
|
148
|
+
var LuzziCore = class {
|
|
149
|
+
constructor() {
|
|
150
|
+
this.apiKey = "";
|
|
151
|
+
this.apiUrl = DEFAULT_API_URL;
|
|
152
|
+
this.sessionId = "";
|
|
153
|
+
this.userTraits = {};
|
|
154
|
+
this.deviceInfo = {};
|
|
155
|
+
this.initialized = false;
|
|
156
|
+
this.debug = false;
|
|
157
|
+
this.queue = new EventQueue();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Initialize the SDK
|
|
161
|
+
* Must be called before any other method
|
|
162
|
+
*/
|
|
163
|
+
init(apiKey, config = {}) {
|
|
164
|
+
if (!apiKey) {
|
|
165
|
+
console.error("[Luzzi] API key is required");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.apiKey = apiKey;
|
|
169
|
+
this.apiUrl = config.apiUrl || DEFAULT_API_URL;
|
|
170
|
+
this.debug = config.debug || false;
|
|
171
|
+
this.sessionId = this.generateSessionId();
|
|
172
|
+
this.deviceInfo = this.collectDeviceInfo();
|
|
173
|
+
this.queue.init(
|
|
174
|
+
this.apiKey,
|
|
175
|
+
this.apiUrl,
|
|
176
|
+
config.batchSize || DEFAULT_BATCH_SIZE,
|
|
177
|
+
config.flushInterval || DEFAULT_FLUSH_INTERVAL,
|
|
178
|
+
this.debug
|
|
179
|
+
);
|
|
180
|
+
this.initialized = true;
|
|
181
|
+
this.log("Initialized", { apiKey: apiKey.slice(0, 10) + "...", sessionId: this.sessionId });
|
|
182
|
+
if (typeof window !== "undefined") {
|
|
183
|
+
window.addEventListener("beforeunload", () => {
|
|
184
|
+
this.flush();
|
|
185
|
+
});
|
|
186
|
+
window.addEventListener("visibilitychange", () => {
|
|
187
|
+
if (document.visibilityState === "hidden") {
|
|
188
|
+
this.flush();
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Track an event
|
|
195
|
+
*/
|
|
196
|
+
track(eventName, properties) {
|
|
197
|
+
if (!this.initialized) {
|
|
198
|
+
console.warn("[Luzzi] SDK not initialized. Call luzzi.init() first.");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (!eventName || typeof eventName !== "string") {
|
|
202
|
+
console.warn("[Luzzi] Event name is required and must be a string");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this.queue.push({
|
|
206
|
+
event: eventName,
|
|
207
|
+
properties: properties || {},
|
|
208
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
209
|
+
session_id: this.sessionId,
|
|
210
|
+
user_id: this.userId,
|
|
211
|
+
device: this.deviceInfo
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Identify the current user
|
|
216
|
+
*/
|
|
217
|
+
identify(userId, traits) {
|
|
218
|
+
if (!this.initialized) {
|
|
219
|
+
console.warn("[Luzzi] SDK not initialized. Call luzzi.init() first.");
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (!userId || typeof userId !== "string") {
|
|
223
|
+
console.warn("[Luzzi] User ID is required and must be a string");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
this.userId = userId;
|
|
227
|
+
this.userTraits = { ...this.userTraits, ...traits };
|
|
228
|
+
this.log("User identified", { userId, traits });
|
|
229
|
+
this.track("$identify", {
|
|
230
|
+
...this.userTraits,
|
|
231
|
+
$user_id: userId
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Reset the current user (logout)
|
|
236
|
+
*/
|
|
237
|
+
reset() {
|
|
238
|
+
this.log("Resetting user");
|
|
239
|
+
this.flush();
|
|
240
|
+
this.userId = void 0;
|
|
241
|
+
this.userTraits = {};
|
|
242
|
+
this.sessionId = this.generateSessionId();
|
|
243
|
+
this.log("Reset complete", { newSessionId: this.sessionId });
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Manually flush the event queue
|
|
247
|
+
*/
|
|
248
|
+
async flush() {
|
|
249
|
+
if (!this.initialized) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
await this.queue.flush();
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get the current session ID
|
|
256
|
+
*/
|
|
257
|
+
getSessionId() {
|
|
258
|
+
return this.sessionId;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get the current user ID
|
|
262
|
+
*/
|
|
263
|
+
getUserId() {
|
|
264
|
+
return this.userId;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Generate a unique session ID
|
|
268
|
+
*/
|
|
269
|
+
generateSessionId() {
|
|
270
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
271
|
+
return crypto.randomUUID();
|
|
272
|
+
}
|
|
273
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Collect device information
|
|
277
|
+
*/
|
|
278
|
+
collectDeviceInfo() {
|
|
279
|
+
const info = {};
|
|
280
|
+
if (typeof window !== "undefined" && typeof navigator !== "undefined") {
|
|
281
|
+
const ua = navigator.userAgent;
|
|
282
|
+
if (ua.includes("Windows")) info.os = "windows";
|
|
283
|
+
else if (ua.includes("Mac")) info.os = "macos";
|
|
284
|
+
else if (ua.includes("Linux")) info.os = "linux";
|
|
285
|
+
else if (ua.includes("Android")) info.os = "android";
|
|
286
|
+
else if (ua.includes("iPhone") || ua.includes("iPad")) info.os = "ios";
|
|
287
|
+
if (ua.includes("Chrome") && !ua.includes("Edg")) info.browser = "chrome";
|
|
288
|
+
else if (ua.includes("Firefox")) info.browser = "firefox";
|
|
289
|
+
else if (ua.includes("Safari") && !ua.includes("Chrome")) info.browser = "safari";
|
|
290
|
+
else if (ua.includes("Edg")) info.browser = "edge";
|
|
291
|
+
info.screen_width = window.screen?.width;
|
|
292
|
+
info.screen_height = window.screen?.height;
|
|
293
|
+
info.language = navigator.language;
|
|
294
|
+
try {
|
|
295
|
+
info.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
296
|
+
} catch {
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
300
|
+
info.os = process.platform;
|
|
301
|
+
info.app_version = process.versions.node;
|
|
302
|
+
}
|
|
303
|
+
return info;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Debug log
|
|
307
|
+
*/
|
|
308
|
+
log(message, data) {
|
|
309
|
+
if (this.debug) {
|
|
310
|
+
console.log(`[Luzzi] ${message}`, data || "");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
var luzziCore = new LuzziCore();
|
|
315
|
+
|
|
316
|
+
// src/index.ts
|
|
317
|
+
var luzzi = {
|
|
318
|
+
/**
|
|
319
|
+
* Initialize the SDK with your API key
|
|
320
|
+
* Must be called before any other method
|
|
321
|
+
*
|
|
322
|
+
* @param apiKey - Your Luzzi API key (pk_live_xxx or pk_test_xxx)
|
|
323
|
+
* @param config - Optional configuration
|
|
324
|
+
*/
|
|
325
|
+
init: (apiKey, config) => {
|
|
326
|
+
luzziCore.init(apiKey, config);
|
|
327
|
+
},
|
|
328
|
+
/**
|
|
329
|
+
* Track an event
|
|
330
|
+
*
|
|
331
|
+
* @param eventName - Name of the event (e.g., "button_clicked", "page_viewed")
|
|
332
|
+
* @param properties - Optional event properties
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* luzzi.track("purchase_completed", { amount: 99.99, currency: "USD" });
|
|
336
|
+
*/
|
|
337
|
+
track: (eventName, properties) => {
|
|
338
|
+
luzziCore.track(eventName, properties);
|
|
339
|
+
},
|
|
340
|
+
/**
|
|
341
|
+
* Identify the current user
|
|
342
|
+
*
|
|
343
|
+
* @param userId - Unique user identifier
|
|
344
|
+
* @param traits - Optional user traits/properties
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* luzzi.identify("user_123", { email: "user@example.com", plan: "pro" });
|
|
348
|
+
*/
|
|
349
|
+
identify: (userId, traits) => {
|
|
350
|
+
luzziCore.identify(userId, traits);
|
|
351
|
+
},
|
|
352
|
+
/**
|
|
353
|
+
* Reset the current user (call on logout)
|
|
354
|
+
* Clears user ID and generates a new session
|
|
355
|
+
*/
|
|
356
|
+
reset: () => {
|
|
357
|
+
luzziCore.reset();
|
|
358
|
+
},
|
|
359
|
+
/**
|
|
360
|
+
* Manually flush pending events to the server
|
|
361
|
+
* Events are automatically flushed on a timer and on page unload
|
|
362
|
+
*/
|
|
363
|
+
flush: () => {
|
|
364
|
+
return luzziCore.flush();
|
|
365
|
+
},
|
|
366
|
+
/**
|
|
367
|
+
* Get the current session ID
|
|
368
|
+
*/
|
|
369
|
+
getSessionId: () => {
|
|
370
|
+
return luzziCore.getSessionId();
|
|
371
|
+
},
|
|
372
|
+
/**
|
|
373
|
+
* Get the current user ID (if identified)
|
|
374
|
+
*/
|
|
375
|
+
getUserId: () => {
|
|
376
|
+
return luzziCore.getUserId();
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
var index_default = luzzi;
|
|
380
|
+
var { init, track, identify, reset, flush, getSessionId, getUserId } = luzzi;
|
|
381
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
382
|
+
0 && (module.exports = {
|
|
383
|
+
flush,
|
|
384
|
+
getSessionId,
|
|
385
|
+
getUserId,
|
|
386
|
+
identify,
|
|
387
|
+
init,
|
|
388
|
+
reset,
|
|
389
|
+
track
|
|
390
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// src/queue.ts
|
|
2
|
+
var EventQueue = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.queue = [];
|
|
5
|
+
this.flushTimer = null;
|
|
6
|
+
this.apiKey = "";
|
|
7
|
+
this.apiUrl = "";
|
|
8
|
+
this.batchSize = 10;
|
|
9
|
+
this.flushInterval = 3e4;
|
|
10
|
+
this.debug = false;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Initialize the queue
|
|
14
|
+
*/
|
|
15
|
+
init(apiKey, apiUrl, batchSize, flushInterval, debug) {
|
|
16
|
+
this.apiKey = apiKey;
|
|
17
|
+
this.apiUrl = apiUrl;
|
|
18
|
+
this.batchSize = batchSize;
|
|
19
|
+
this.flushInterval = flushInterval;
|
|
20
|
+
this.debug = debug;
|
|
21
|
+
this.startFlushTimer();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Add event to queue
|
|
25
|
+
*/
|
|
26
|
+
push(event) {
|
|
27
|
+
this.queue.push(event);
|
|
28
|
+
this.log(`Event queued: ${event.event}`, event);
|
|
29
|
+
if (this.queue.length >= this.batchSize) {
|
|
30
|
+
this.flush();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Flush all events in queue to server
|
|
35
|
+
*/
|
|
36
|
+
async flush() {
|
|
37
|
+
if (this.queue.length === 0) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const events = [...this.queue];
|
|
41
|
+
this.queue = [];
|
|
42
|
+
try {
|
|
43
|
+
const payload = { events };
|
|
44
|
+
this.log(`Flushing ${events.length} events`, payload);
|
|
45
|
+
const response = await fetch(`${this.apiUrl}/v1/events`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
"x-api-key": this.apiKey
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(payload)
|
|
52
|
+
});
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const error = await response.json().catch(() => ({}));
|
|
55
|
+
console.error("[Luzzi] Failed to send events:", error);
|
|
56
|
+
if (this.queue.length < this.batchSize * 10) {
|
|
57
|
+
this.queue.unshift(...events);
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
const result = await response.json();
|
|
61
|
+
this.log(`Events sent successfully`, result);
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error("[Luzzi] Failed to send events:", error);
|
|
65
|
+
if (this.queue.length < this.batchSize * 10) {
|
|
66
|
+
this.queue.unshift(...events);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Start auto-flush timer
|
|
72
|
+
*/
|
|
73
|
+
startFlushTimer() {
|
|
74
|
+
this.stopFlushTimer();
|
|
75
|
+
this.flushTimer = setInterval(() => {
|
|
76
|
+
this.flush();
|
|
77
|
+
}, this.flushInterval);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Stop auto-flush timer
|
|
81
|
+
*/
|
|
82
|
+
stopFlushTimer() {
|
|
83
|
+
if (this.flushTimer) {
|
|
84
|
+
clearInterval(this.flushTimer);
|
|
85
|
+
this.flushTimer = null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get queue length
|
|
90
|
+
*/
|
|
91
|
+
get length() {
|
|
92
|
+
return this.queue.length;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Clear queue and stop timer
|
|
96
|
+
*/
|
|
97
|
+
reset() {
|
|
98
|
+
this.queue = [];
|
|
99
|
+
this.stopFlushTimer();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Debug log
|
|
103
|
+
*/
|
|
104
|
+
log(message, data) {
|
|
105
|
+
if (this.debug) {
|
|
106
|
+
console.log(`[Luzzi] ${message}`, data || "");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// src/core.ts
|
|
112
|
+
var DEFAULT_API_URL = "https://luzzi.vercel.app/api";
|
|
113
|
+
var DEFAULT_BATCH_SIZE = 10;
|
|
114
|
+
var DEFAULT_FLUSH_INTERVAL = 3e4;
|
|
115
|
+
var LuzziCore = class {
|
|
116
|
+
constructor() {
|
|
117
|
+
this.apiKey = "";
|
|
118
|
+
this.apiUrl = DEFAULT_API_URL;
|
|
119
|
+
this.sessionId = "";
|
|
120
|
+
this.userTraits = {};
|
|
121
|
+
this.deviceInfo = {};
|
|
122
|
+
this.initialized = false;
|
|
123
|
+
this.debug = false;
|
|
124
|
+
this.queue = new EventQueue();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Initialize the SDK
|
|
128
|
+
* Must be called before any other method
|
|
129
|
+
*/
|
|
130
|
+
init(apiKey, config = {}) {
|
|
131
|
+
if (!apiKey) {
|
|
132
|
+
console.error("[Luzzi] API key is required");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.apiKey = apiKey;
|
|
136
|
+
this.apiUrl = config.apiUrl || DEFAULT_API_URL;
|
|
137
|
+
this.debug = config.debug || false;
|
|
138
|
+
this.sessionId = this.generateSessionId();
|
|
139
|
+
this.deviceInfo = this.collectDeviceInfo();
|
|
140
|
+
this.queue.init(
|
|
141
|
+
this.apiKey,
|
|
142
|
+
this.apiUrl,
|
|
143
|
+
config.batchSize || DEFAULT_BATCH_SIZE,
|
|
144
|
+
config.flushInterval || DEFAULT_FLUSH_INTERVAL,
|
|
145
|
+
this.debug
|
|
146
|
+
);
|
|
147
|
+
this.initialized = true;
|
|
148
|
+
this.log("Initialized", { apiKey: apiKey.slice(0, 10) + "...", sessionId: this.sessionId });
|
|
149
|
+
if (typeof window !== "undefined") {
|
|
150
|
+
window.addEventListener("beforeunload", () => {
|
|
151
|
+
this.flush();
|
|
152
|
+
});
|
|
153
|
+
window.addEventListener("visibilitychange", () => {
|
|
154
|
+
if (document.visibilityState === "hidden") {
|
|
155
|
+
this.flush();
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Track an event
|
|
162
|
+
*/
|
|
163
|
+
track(eventName, properties) {
|
|
164
|
+
if (!this.initialized) {
|
|
165
|
+
console.warn("[Luzzi] SDK not initialized. Call luzzi.init() first.");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (!eventName || typeof eventName !== "string") {
|
|
169
|
+
console.warn("[Luzzi] Event name is required and must be a string");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.queue.push({
|
|
173
|
+
event: eventName,
|
|
174
|
+
properties: properties || {},
|
|
175
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
176
|
+
session_id: this.sessionId,
|
|
177
|
+
user_id: this.userId,
|
|
178
|
+
device: this.deviceInfo
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Identify the current user
|
|
183
|
+
*/
|
|
184
|
+
identify(userId, traits) {
|
|
185
|
+
if (!this.initialized) {
|
|
186
|
+
console.warn("[Luzzi] SDK not initialized. Call luzzi.init() first.");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (!userId || typeof userId !== "string") {
|
|
190
|
+
console.warn("[Luzzi] User ID is required and must be a string");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
this.userId = userId;
|
|
194
|
+
this.userTraits = { ...this.userTraits, ...traits };
|
|
195
|
+
this.log("User identified", { userId, traits });
|
|
196
|
+
this.track("$identify", {
|
|
197
|
+
...this.userTraits,
|
|
198
|
+
$user_id: userId
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Reset the current user (logout)
|
|
203
|
+
*/
|
|
204
|
+
reset() {
|
|
205
|
+
this.log("Resetting user");
|
|
206
|
+
this.flush();
|
|
207
|
+
this.userId = void 0;
|
|
208
|
+
this.userTraits = {};
|
|
209
|
+
this.sessionId = this.generateSessionId();
|
|
210
|
+
this.log("Reset complete", { newSessionId: this.sessionId });
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Manually flush the event queue
|
|
214
|
+
*/
|
|
215
|
+
async flush() {
|
|
216
|
+
if (!this.initialized) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
await this.queue.flush();
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get the current session ID
|
|
223
|
+
*/
|
|
224
|
+
getSessionId() {
|
|
225
|
+
return this.sessionId;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get the current user ID
|
|
229
|
+
*/
|
|
230
|
+
getUserId() {
|
|
231
|
+
return this.userId;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Generate a unique session ID
|
|
235
|
+
*/
|
|
236
|
+
generateSessionId() {
|
|
237
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
238
|
+
return crypto.randomUUID();
|
|
239
|
+
}
|
|
240
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Collect device information
|
|
244
|
+
*/
|
|
245
|
+
collectDeviceInfo() {
|
|
246
|
+
const info = {};
|
|
247
|
+
if (typeof window !== "undefined" && typeof navigator !== "undefined") {
|
|
248
|
+
const ua = navigator.userAgent;
|
|
249
|
+
if (ua.includes("Windows")) info.os = "windows";
|
|
250
|
+
else if (ua.includes("Mac")) info.os = "macos";
|
|
251
|
+
else if (ua.includes("Linux")) info.os = "linux";
|
|
252
|
+
else if (ua.includes("Android")) info.os = "android";
|
|
253
|
+
else if (ua.includes("iPhone") || ua.includes("iPad")) info.os = "ios";
|
|
254
|
+
if (ua.includes("Chrome") && !ua.includes("Edg")) info.browser = "chrome";
|
|
255
|
+
else if (ua.includes("Firefox")) info.browser = "firefox";
|
|
256
|
+
else if (ua.includes("Safari") && !ua.includes("Chrome")) info.browser = "safari";
|
|
257
|
+
else if (ua.includes("Edg")) info.browser = "edge";
|
|
258
|
+
info.screen_width = window.screen?.width;
|
|
259
|
+
info.screen_height = window.screen?.height;
|
|
260
|
+
info.language = navigator.language;
|
|
261
|
+
try {
|
|
262
|
+
info.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
263
|
+
} catch {
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
267
|
+
info.os = process.platform;
|
|
268
|
+
info.app_version = process.versions.node;
|
|
269
|
+
}
|
|
270
|
+
return info;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Debug log
|
|
274
|
+
*/
|
|
275
|
+
log(message, data) {
|
|
276
|
+
if (this.debug) {
|
|
277
|
+
console.log(`[Luzzi] ${message}`, data || "");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var luzziCore = new LuzziCore();
|
|
282
|
+
|
|
283
|
+
// src/index.ts
|
|
284
|
+
var luzzi = {
|
|
285
|
+
/**
|
|
286
|
+
* Initialize the SDK with your API key
|
|
287
|
+
* Must be called before any other method
|
|
288
|
+
*
|
|
289
|
+
* @param apiKey - Your Luzzi API key (pk_live_xxx or pk_test_xxx)
|
|
290
|
+
* @param config - Optional configuration
|
|
291
|
+
*/
|
|
292
|
+
init: (apiKey, config) => {
|
|
293
|
+
luzziCore.init(apiKey, config);
|
|
294
|
+
},
|
|
295
|
+
/**
|
|
296
|
+
* Track an event
|
|
297
|
+
*
|
|
298
|
+
* @param eventName - Name of the event (e.g., "button_clicked", "page_viewed")
|
|
299
|
+
* @param properties - Optional event properties
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* luzzi.track("purchase_completed", { amount: 99.99, currency: "USD" });
|
|
303
|
+
*/
|
|
304
|
+
track: (eventName, properties) => {
|
|
305
|
+
luzziCore.track(eventName, properties);
|
|
306
|
+
},
|
|
307
|
+
/**
|
|
308
|
+
* Identify the current user
|
|
309
|
+
*
|
|
310
|
+
* @param userId - Unique user identifier
|
|
311
|
+
* @param traits - Optional user traits/properties
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* luzzi.identify("user_123", { email: "user@example.com", plan: "pro" });
|
|
315
|
+
*/
|
|
316
|
+
identify: (userId, traits) => {
|
|
317
|
+
luzziCore.identify(userId, traits);
|
|
318
|
+
},
|
|
319
|
+
/**
|
|
320
|
+
* Reset the current user (call on logout)
|
|
321
|
+
* Clears user ID and generates a new session
|
|
322
|
+
*/
|
|
323
|
+
reset: () => {
|
|
324
|
+
luzziCore.reset();
|
|
325
|
+
},
|
|
326
|
+
/**
|
|
327
|
+
* Manually flush pending events to the server
|
|
328
|
+
* Events are automatically flushed on a timer and on page unload
|
|
329
|
+
*/
|
|
330
|
+
flush: () => {
|
|
331
|
+
return luzziCore.flush();
|
|
332
|
+
},
|
|
333
|
+
/**
|
|
334
|
+
* Get the current session ID
|
|
335
|
+
*/
|
|
336
|
+
getSessionId: () => {
|
|
337
|
+
return luzziCore.getSessionId();
|
|
338
|
+
},
|
|
339
|
+
/**
|
|
340
|
+
* Get the current user ID (if identified)
|
|
341
|
+
*/
|
|
342
|
+
getUserId: () => {
|
|
343
|
+
return luzziCore.getUserId();
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
var index_default = luzzi;
|
|
347
|
+
var { init, track, identify, reset, flush, getSessionId, getUserId } = luzzi;
|
|
348
|
+
export {
|
|
349
|
+
index_default as default,
|
|
350
|
+
flush,
|
|
351
|
+
getSessionId,
|
|
352
|
+
getUserId,
|
|
353
|
+
identify,
|
|
354
|
+
init,
|
|
355
|
+
reset,
|
|
356
|
+
track
|
|
357
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "luzzi-analytics",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Simple, plug-and-play analytics SDK for solo builders",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
17
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
18
|
+
"clean": "rimraf dist"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"analytics",
|
|
22
|
+
"tracking",
|
|
23
|
+
"events",
|
|
24
|
+
"solo-builder",
|
|
25
|
+
"luzzi"
|
|
26
|
+
],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"tsup": "^8.0.0",
|
|
31
|
+
"typescript": "^5.0.0",
|
|
32
|
+
"rimraf": "^5.0.0"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/your-username/luzzi"
|
|
40
|
+
}
|
|
41
|
+
}
|