@stacksee/analytics 0.7.0 → 0.9.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.
@@ -0,0 +1,56 @@
1
+ import { BaseEvent, EventContext } from '../../core/events/types.js';
2
+ import { BaseAnalyticsProvider } from '../base.provider.js';
3
+ import { ProxyBatchConfig, ProxyRetryConfig } from './types.js';
4
+ export interface ProxyProviderConfig {
5
+ /**
6
+ * The endpoint to send events to (e.g., '/api/events')
7
+ */
8
+ endpoint: string;
9
+ /**
10
+ * Batching configuration
11
+ */
12
+ batch?: ProxyBatchConfig;
13
+ /**
14
+ * Retry configuration
15
+ */
16
+ retry?: ProxyRetryConfig;
17
+ /**
18
+ * Custom headers to include in requests
19
+ */
20
+ headers?: Record<string, string>;
21
+ /**
22
+ * Enable debug logging
23
+ */
24
+ debug?: boolean;
25
+ /**
26
+ * Enable/disable the provider
27
+ */
28
+ enabled?: boolean;
29
+ }
30
+ export declare class ProxyProvider extends BaseAnalyticsProvider {
31
+ name: string;
32
+ private config;
33
+ private queue;
34
+ private flushTimer?;
35
+ private readonly batchSize;
36
+ private readonly batchInterval;
37
+ private readonly retryAttempts;
38
+ private readonly retryBackoff;
39
+ private readonly retryInitialDelay;
40
+ constructor(config: ProxyProviderConfig);
41
+ initialize(): Promise<void>;
42
+ identify(userId: string, traits?: Record<string, unknown>): void;
43
+ track(event: BaseEvent, context?: EventContext): Promise<void>;
44
+ pageView(properties?: Record<string, unknown>, context?: EventContext): void;
45
+ reset(): Promise<void>;
46
+ shutdown(): Promise<void>;
47
+ /**
48
+ * Manually flush all queued events
49
+ */
50
+ flush(useBeacon?: boolean): Promise<void>;
51
+ private queueEvent;
52
+ private sendEvents;
53
+ private sendWithRetry;
54
+ private calculateRetryDelay;
55
+ private enrichContext;
56
+ }
@@ -0,0 +1,55 @@
1
+ import { ServerAnalytics } from '../../server.js';
2
+ /**
3
+ * Configuration for ingesting proxy events
4
+ */
5
+ export interface IngestProxyEventsConfig {
6
+ /**
7
+ * Enrich context with server-side data
8
+ */
9
+ enrichContext?: (request: Request) => Record<string, unknown>;
10
+ /**
11
+ * Extract IP address from request
12
+ * Default: Uses standard headers (X-Forwarded-For, X-Real-IP)
13
+ */
14
+ extractIp?: (request: Request) => string | undefined;
15
+ /**
16
+ * Error handler
17
+ */
18
+ onError?: (error: unknown) => void;
19
+ }
20
+ /**
21
+ * Ingests events from ProxyProvider and replays them through server analytics
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // Next.js App Router
26
+ * export async function POST(req: Request) {
27
+ * await ingestProxyEvents(req, serverAnalytics);
28
+ * return new Response('OK');
29
+ * }
30
+ *
31
+ * // With custom IP extraction
32
+ * export async function POST(req: Request) {
33
+ * await ingestProxyEvents(req, serverAnalytics, {
34
+ * extractIp: (req) => req.headers.get('cf-connecting-ip') // Cloudflare
35
+ * });
36
+ * return new Response('OK');
37
+ * }
38
+ * ```
39
+ */
40
+ export declare function ingestProxyEvents<TEventMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TUserTraits extends Record<string, unknown> = Record<string, unknown>>(request: Request, analytics: ServerAnalytics<TEventMap, TUserTraits>, config?: IngestProxyEventsConfig): Promise<void>;
41
+ /**
42
+ * Creates a Request handler for common frameworks
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * // Next.js App Router
47
+ * export const POST = createProxyHandler(serverAnalytics);
48
+ *
49
+ * // With custom config
50
+ * export const POST = createProxyHandler(serverAnalytics, {
51
+ * extractIp: (req) => req.headers.get('cf-connecting-ip')
52
+ * });
53
+ * ```
54
+ */
55
+ export declare function createProxyHandler<TEventMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TUserTraits extends Record<string, unknown> = Record<string, unknown>>(analytics: ServerAnalytics<TEventMap, TUserTraits>, config?: IngestProxyEventsConfig): (request: Request) => Promise<Response>;
@@ -0,0 +1,64 @@
1
+ import { BaseEvent, EventContext } from '../../core/events/types.js';
2
+ /**
3
+ * Proxy event types for batching and sending to server
4
+ */
5
+ export type ProxyTrackEvent = {
6
+ type: "track";
7
+ event: BaseEvent;
8
+ context?: EventContext;
9
+ };
10
+ export type ProxyIdentifyEvent = {
11
+ type: "identify";
12
+ userId: string;
13
+ traits?: Record<string, unknown>;
14
+ };
15
+ export type ProxyPageViewEvent = {
16
+ type: "pageView";
17
+ properties?: Record<string, unknown>;
18
+ context?: EventContext;
19
+ };
20
+ export type ProxyResetEvent = {
21
+ type: "reset";
22
+ };
23
+ export type ProxyEvent = ProxyTrackEvent | ProxyIdentifyEvent | ProxyPageViewEvent | ProxyResetEvent;
24
+ /**
25
+ * Payload sent to the proxy endpoint
26
+ */
27
+ export interface ProxyPayload {
28
+ events: ProxyEvent[];
29
+ }
30
+ /**
31
+ * Configuration for batching behavior
32
+ */
33
+ export interface ProxyBatchConfig {
34
+ /**
35
+ * Maximum number of events before auto-flush
36
+ * @default 10
37
+ */
38
+ size?: number;
39
+ /**
40
+ * Maximum time in ms before auto-flush
41
+ * @default 5000
42
+ */
43
+ interval?: number;
44
+ }
45
+ /**
46
+ * Configuration for retry behavior
47
+ */
48
+ export interface ProxyRetryConfig {
49
+ /**
50
+ * Maximum retry attempts
51
+ * @default 3
52
+ */
53
+ attempts?: number;
54
+ /**
55
+ * Backoff strategy
56
+ * @default 'exponential'
57
+ */
58
+ backoff?: "exponential" | "linear";
59
+ /**
60
+ * Initial delay in ms
61
+ * @default 1000
62
+ */
63
+ initialDelay?: number;
64
+ }
@@ -5,3 +5,5 @@ export { BentoServerProvider } from './bento/server.js';
5
5
  export type { BentoServerConfig, BentoAnalyticsOptions } from './bento/server.js';
6
6
  export { PirschServerProvider } from './pirsch/server.js';
7
7
  export type { PirschServerConfig } from './pirsch/server.js';
8
+ export { ingestProxyEvents, createProxyHandler } from './proxy/server.js';
9
+ export type { IngestProxyEventsConfig } from './proxy/server.js';
@@ -1,100 +1,100 @@
1
- var g = Object.defineProperty;
2
- var p = (o, h, e) => h in o ? g(o, h, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[h] = e;
3
- var n = (o, h, e) => p(o, typeof h != "symbol" ? h + "" : h, e);
4
- import { B as f } from "../base.provider-AfFL5W_P.js";
5
- import { P as k } from "../server-DjEk1fUD.js";
6
- class b extends f {
7
- constructor(e) {
8
- super({ debug: e.debug, enabled: e.enabled });
9
- n(this, "name", "Bento-Server");
10
- n(this, "client");
11
- n(this, "initialized", !1);
12
- n(this, "config");
13
- n(this, "currentUserEmail");
14
- this.config = e;
1
+ var f = Object.defineProperty;
2
+ var y = (l, n, i) => n in l ? f(l, n, { enumerable: !0, configurable: !0, writable: !0, value: i }) : l[n] = i;
3
+ var d = (l, n, i) => y(l, typeof n != "symbol" ? n + "" : n, i);
4
+ import { B as p } from "../base.provider-AfFL5W_P.js";
5
+ import { P as z } from "../server-DjEk1fUD.js";
6
+ class v extends p {
7
+ constructor(i) {
8
+ super({ debug: i.debug, enabled: i.enabled });
9
+ d(this, "name", "Bento-Server");
10
+ d(this, "client");
11
+ d(this, "initialized", !1);
12
+ d(this, "config");
13
+ d(this, "currentUserEmail");
14
+ this.config = i;
15
15
  }
16
16
  async initialize() {
17
- var e, i;
17
+ var i, e;
18
18
  if (this.isEnabled() && !this.initialized) {
19
19
  if (!this.config.siteUuid || typeof this.config.siteUuid != "string")
20
20
  throw new Error("Bento requires a siteUuid");
21
- if (!((e = this.config.authentication) != null && e.publishableKey) || typeof this.config.authentication.publishableKey != "string")
21
+ if (!((i = this.config.authentication) != null && i.publishableKey) || typeof this.config.authentication.publishableKey != "string")
22
22
  throw new Error("Bento requires authentication.publishableKey");
23
- if (!((i = this.config.authentication) != null && i.secretKey) || typeof this.config.authentication.secretKey != "string")
23
+ if (!((e = this.config.authentication) != null && e.secretKey) || typeof this.config.authentication.secretKey != "string")
24
24
  throw new Error("Bento requires authentication.secretKey");
25
25
  try {
26
- const { Analytics: r } = await import("../bento-node-sdk.esm-C4HG7SVz.js"), { debug: a, enabled: s, ...l } = this.config;
27
- this.client = new r(l), this.initialized = !0, this.log("Initialized successfully", {
26
+ const { Analytics: s } = await import("../bento-node-sdk.esm-C4HG7SVz.js"), { debug: a, enabled: t, ...o } = this.config;
27
+ this.client = new s(o), this.initialized = !0, this.log("Initialized successfully", {
28
28
  siteUuid: this.config.siteUuid
29
29
  });
30
- } catch (r) {
30
+ } catch (s) {
31
31
  throw console.error(
32
32
  "[Bento-Server] Failed to initialize. Make sure @bentonow/bento-node-sdk is installed:",
33
- r
34
- ), r;
33
+ s
34
+ ), s;
35
35
  }
36
36
  }
37
37
  }
38
- identify(e, i) {
38
+ identify(i, e) {
39
39
  if (!this.isEnabled() || !this.initialized || !this.client) return;
40
- const r = (i == null ? void 0 : i.email) || e;
41
- this.currentUserEmail = r;
42
- const a = i ? { ...i } : {};
40
+ const s = (e == null ? void 0 : e.email) || i;
41
+ this.currentUserEmail = s;
42
+ const a = e ? { ...e } : {};
43
43
  delete a.email, this.client.V1.addSubscriber({
44
- email: r,
44
+ email: s,
45
45
  fields: a
46
- }).catch((s) => {
47
- console.error("[Bento-Server] Failed to identify user:", s);
48
- }), this.log("Identified user", { userId: e, email: r, traits: i });
46
+ }).catch((t) => {
47
+ console.error("[Bento-Server] Failed to identify user:", t);
48
+ }), this.log("Identified user", { userId: i, email: s, traits: e });
49
49
  }
50
- async track(e, i) {
51
- var l, t, d;
50
+ async track(i, e) {
51
+ var o, r, h;
52
52
  if (!this.isEnabled() || !this.initialized || !this.client) return;
53
- const r = ((l = i == null ? void 0 : i.user) == null ? void 0 : l.email) || this.currentUserEmail || ((t = i == null ? void 0 : i.user) == null ? void 0 : t.userId) || e.userId || "anonymous@unknown.com", a = {
54
- ...e.properties,
55
- category: e.category,
56
- timestamp: e.timestamp || Date.now(),
57
- ...e.sessionId && { sessionId: e.sessionId },
58
- ...(i == null ? void 0 : i.page) && {
53
+ const s = ((o = e == null ? void 0 : e.user) == null ? void 0 : o.email) || this.currentUserEmail || ((r = e == null ? void 0 : e.user) == null ? void 0 : r.userId) || i.userId || "anonymous@unknown.com", a = {
54
+ ...i.properties,
55
+ category: i.category,
56
+ timestamp: i.timestamp || Date.now(),
57
+ ...i.sessionId && { sessionId: i.sessionId },
58
+ ...(e == null ? void 0 : e.page) && {
59
59
  page: {
60
- path: i.page.path,
61
- title: i.page.title,
62
- referrer: i.page.referrer
60
+ path: e.page.path,
61
+ title: e.page.title,
62
+ referrer: e.page.referrer
63
63
  }
64
64
  },
65
- ...(i == null ? void 0 : i.device) && { device: i.device },
66
- ...(i == null ? void 0 : i.utm) && { utm: i.utm }
67
- }, s = ((d = i == null ? void 0 : i.user) == null ? void 0 : d.traits) || {};
65
+ ...(e == null ? void 0 : e.device) && { device: e.device },
66
+ ...(e == null ? void 0 : e.utm) && { utm: e.utm }
67
+ }, t = ((h = e == null ? void 0 : e.user) == null ? void 0 : h.traits) || {};
68
68
  try {
69
69
  await this.client.V1.track({
70
- email: r,
71
- type: `$${e.action}`,
70
+ email: s,
71
+ type: `$${i.action}`,
72
72
  details: a,
73
- fields: s
74
- }), this.log("Tracked event", { event: e, context: i });
75
- } catch (c) {
76
- console.error("[Bento-Server] Failed to track event:", c);
73
+ fields: t
74
+ }), this.log("Tracked event", { event: i, context: e });
75
+ } catch (u) {
76
+ console.error("[Bento-Server] Failed to track event:", u);
77
77
  }
78
78
  }
79
- pageView(e, i) {
80
- var l, t;
79
+ pageView(i, e) {
80
+ var o, r;
81
81
  if (!this.isEnabled() || !this.initialized || !this.client) return;
82
- const r = ((l = i == null ? void 0 : i.user) == null ? void 0 : l.email) || this.currentUserEmail || "anonymous@unknown.com", a = {
83
- ...e,
84
- ...(i == null ? void 0 : i.page) && {
85
- path: i.page.path,
86
- title: i.page.title,
87
- referrer: i.page.referrer
82
+ const s = ((o = e == null ? void 0 : e.user) == null ? void 0 : o.email) || this.currentUserEmail || "anonymous@unknown.com", a = {
83
+ ...i,
84
+ ...(e == null ? void 0 : e.page) && {
85
+ path: e.page.path,
86
+ title: e.page.title,
87
+ referrer: e.page.referrer
88
88
  }
89
- }, s = ((t = i == null ? void 0 : i.user) == null ? void 0 : t.traits) || {};
89
+ }, t = ((r = e == null ? void 0 : e.user) == null ? void 0 : r.traits) || {};
90
90
  this.client.V1.track({
91
- email: r,
92
- type: "$pageview",
91
+ email: s,
92
+ type: "$view",
93
93
  details: a,
94
- fields: s
95
- }).catch((d) => {
96
- console.error("[Bento-Server] Failed to track page view:", d);
97
- }), this.log("Tracked page view", { properties: e, context: i });
94
+ fields: t
95
+ }).catch((h) => {
96
+ console.error("[Bento-Server] Failed to track page view:", h);
97
+ }), this.log("Tracked page view", { properties: i, context: e });
98
98
  }
99
99
  async reset() {
100
100
  !this.isEnabled() || !this.initialized || !this.client || (this.currentUserEmail = void 0, this.log("Reset user session"));
@@ -103,14 +103,14 @@ class b extends f {
103
103
  this.client = void 0, this.initialized = !1, this.log("Shutdown complete");
104
104
  }
105
105
  }
106
- class w extends f {
107
- constructor(e) {
108
- super({ debug: e.debug, enabled: e.enabled });
109
- n(this, "name", "Pirsch-Server");
110
- n(this, "client");
111
- n(this, "initialized", !1);
112
- n(this, "config");
113
- this.config = e;
106
+ class E extends p {
107
+ constructor(i) {
108
+ super({ debug: i.debug, enabled: i.enabled });
109
+ d(this, "name", "Pirsch-Server");
110
+ d(this, "client");
111
+ d(this, "initialized", !1);
112
+ d(this, "config");
113
+ this.config = i;
114
114
  }
115
115
  async initialize() {
116
116
  if (this.isEnabled() && !this.initialized) {
@@ -119,106 +119,192 @@ class w extends f {
119
119
  if (!this.config.clientSecret || typeof this.config.clientSecret != "string")
120
120
  throw new Error("Pirsch requires a clientSecret (or access key)");
121
121
  try {
122
- const { Pirsch: e } = await import("../index-bgxxv-IJ.js").then((s) => s.i), { debug: i, enabled: r, ...a } = this.config;
123
- this.client = new e(a), this.initialized = !0, this.log("Initialized successfully", {
122
+ const { Pirsch: i } = await import("../index-bgxxv-IJ.js").then((t) => t.i), { debug: e, enabled: s, ...a } = this.config;
123
+ this.client = new i(a), this.initialized = !0, this.log("Initialized successfully", {
124
124
  hostname: this.config.hostname
125
125
  });
126
- } catch (e) {
126
+ } catch (i) {
127
127
  throw console.error(
128
128
  "[Pirsch-Server] Failed to initialize. Make sure pirsch-sdk is installed:",
129
- e
130
- ), e;
129
+ i
130
+ ), i;
131
131
  }
132
132
  }
133
133
  }
134
- identify(e, i) {
134
+ identify(i, e) {
135
135
  if (!this.isEnabled() || !this.initialized || !this.client) return;
136
- const r = {
136
+ const s = {
137
137
  url: "https://identify",
138
138
  ip: "0.0.0.0",
139
139
  user_agent: "analytics-library"
140
140
  }, a = {
141
- userId: e,
142
- ...i && Object.fromEntries(
143
- Object.entries(i).filter(
144
- ([, s]) => typeof s == "string" || typeof s == "number" || typeof s == "boolean"
141
+ userId: i,
142
+ ...e && Object.fromEntries(
143
+ Object.entries(e).filter(
144
+ ([, t]) => typeof t == "string" || typeof t == "number" || typeof t == "boolean"
145
145
  )
146
146
  )
147
147
  };
148
- this.client.event("user_identified", r, 0, a).catch((s) => {
149
- console.error("[Pirsch-Server] Failed to track identify event:", s);
150
- }), this.log("Identified user via event", { userId: e, traits: i });
148
+ this.client.event("user_identified", s, 0, a).catch((t) => {
149
+ console.error("[Pirsch-Server] Failed to track identify event:", t);
150
+ }), this.log("Identified user via event", { userId: i, traits: e });
151
151
  }
152
- async track(e, i) {
153
- var l, t, d, c;
152
+ async track(i, e) {
153
+ var o, r, h, u;
154
154
  if (!this.isEnabled() || !this.initialized || !this.client) return;
155
- const r = {
156
- url: ((l = i == null ? void 0 : i.page) == null ? void 0 : l.path) || "https://event",
155
+ const s = {
156
+ url: ((o = e == null ? void 0 : e.page) == null ? void 0 : o.path) || "https://event",
157
157
  ip: "0.0.0.0",
158
158
  // Server-side should provide real IP if available
159
159
  user_agent: "analytics-library",
160
160
  // Server-side should provide real UA if available
161
- ...((t = i == null ? void 0 : i.page) == null ? void 0 : t.title) && { title: i.page.title },
162
- ...((d = i == null ? void 0 : i.page) == null ? void 0 : d.referrer) && { referrer: i.page.referrer }
163
- }, s = {
161
+ ...((r = e == null ? void 0 : e.page) == null ? void 0 : r.title) && { title: e.page.title },
162
+ ...((h = e == null ? void 0 : e.page) == null ? void 0 : h.referrer) && { referrer: e.page.referrer }
163
+ }, t = {
164
164
  ...Object.fromEntries(
165
- Object.entries(e.properties).filter(
166
- ([, u]) => typeof u == "string" || typeof u == "number" || typeof u == "boolean"
165
+ Object.entries(i.properties).filter(
166
+ ([, c]) => typeof c == "string" || typeof c == "number" || typeof c == "boolean"
167
167
  )
168
168
  ),
169
- category: e.category,
170
- timestamp: String(e.timestamp || Date.now()),
171
- ...e.userId && { userId: e.userId },
172
- ...e.sessionId && { sessionId: e.sessionId },
173
- ...((c = i == null ? void 0 : i.user) == null ? void 0 : c.email) && { user_email: i.user.email }
169
+ category: i.category,
170
+ timestamp: String(i.timestamp || Date.now()),
171
+ ...i.userId && { userId: i.userId },
172
+ ...i.sessionId && { sessionId: i.sessionId },
173
+ ...((u = e == null ? void 0 : e.user) == null ? void 0 : u.email) && { user_email: e.user.email }
174
174
  };
175
175
  try {
176
- await this.client.event(e.action, r, 0, s), this.log("Tracked event", { event: e, context: i });
177
- } catch (u) {
178
- console.error("[Pirsch-Server] Failed to track event:", u);
176
+ await this.client.event(i.action, s, 0, t), this.log("Tracked event", { event: i, context: e });
177
+ } catch (c) {
178
+ console.error("[Pirsch-Server] Failed to track event:", c);
179
179
  }
180
180
  }
181
- pageView(e, i) {
182
- var a, s, l;
181
+ pageView(i, e) {
182
+ var a, t, o;
183
183
  if (!this.isEnabled() || !this.initialized || !this.client) return;
184
- const r = {
185
- url: ((a = i == null ? void 0 : i.page) == null ? void 0 : a.path) || "https://pageview",
184
+ const s = {
185
+ url: ((a = e == null ? void 0 : e.page) == null ? void 0 : a.path) || "https://pageview",
186
186
  ip: "0.0.0.0",
187
187
  // Server-side should provide real IP if available
188
188
  user_agent: "analytics-library",
189
189
  // Server-side should provide real UA if available
190
- ...((s = i == null ? void 0 : i.page) == null ? void 0 : s.title) && { title: i.page.title },
191
- ...((l = i == null ? void 0 : i.page) == null ? void 0 : l.referrer) && { referrer: i.page.referrer },
192
- ...e && {
190
+ ...((t = e == null ? void 0 : e.page) == null ? void 0 : t.title) && { title: e.page.title },
191
+ ...((o = e == null ? void 0 : e.page) == null ? void 0 : o.referrer) && { referrer: e.page.referrer },
192
+ ...i && {
193
193
  tags: Object.fromEntries(
194
- Object.entries(e).filter(
195
- ([, t]) => typeof t == "string" || typeof t == "number" || typeof t == "boolean"
194
+ Object.entries(i).filter(
195
+ ([, r]) => typeof r == "string" || typeof r == "number" || typeof r == "boolean"
196
196
  )
197
197
  )
198
198
  }
199
199
  };
200
- this.client.hit(r).catch((t) => {
201
- console.error("[Pirsch-Server] Failed to track page view:", t);
202
- }), this.log("Tracked page view", { properties: e, context: i });
200
+ this.client.hit(s).catch((r) => {
201
+ console.error("[Pirsch-Server] Failed to track page view:", r);
202
+ }), this.log("Tracked page view", { properties: i, context: e });
203
203
  }
204
204
  async reset() {
205
205
  if (!this.isEnabled() || !this.initialized || !this.client) return;
206
- const e = {
206
+ const i = {
207
207
  url: "https://session-reset",
208
208
  ip: "0.0.0.0",
209
209
  user_agent: "analytics-library"
210
210
  };
211
- await this.client.event("session_reset", e, 0, {}).catch((i) => {
212
- console.error("[Pirsch-Server] Failed to track session reset:", i);
211
+ await this.client.event("session_reset", i, 0, {}).catch((e) => {
212
+ console.error("[Pirsch-Server] Failed to track session reset:", e);
213
213
  }), this.log("Reset user session");
214
214
  }
215
215
  async shutdown() {
216
216
  this.client = void 0, this.initialized = !1, this.log("Shutdown complete");
217
217
  }
218
218
  }
219
+ async function g(l, n, i) {
220
+ var e, s;
221
+ try {
222
+ const a = await l.json();
223
+ if (!a.events || !Array.isArray(a.events))
224
+ throw new Error("Invalid payload: missing events array");
225
+ const t = i != null && i.extractIp ? i.extractIp(l) : m(l), o = i != null && i.enrichContext ? i.enrichContext(l) : {};
226
+ for (const r of a.events)
227
+ try {
228
+ switch (r.type) {
229
+ case "track": {
230
+ const h = {
231
+ ...r.context,
232
+ ...o,
233
+ device: {
234
+ ...(e = r.context) == null ? void 0 : e.device,
235
+ // Add IP (using type assertion for extended fields)
236
+ // biome-ignore lint/suspicious/noExplicitAny: IP field not in base device type
237
+ ...t ? { ip: t } : {}
238
+ }
239
+ };
240
+ await n.track(r.event.action, r.event.properties, {
241
+ userId: r.event.userId,
242
+ sessionId: r.event.sessionId,
243
+ // biome-ignore lint/suspicious/noExplicitAny: Generic context forwarding requires type assertion
244
+ context: h
245
+ });
246
+ break;
247
+ }
248
+ case "identify": {
249
+ n.identify(r.userId, r.traits);
250
+ break;
251
+ }
252
+ case "pageView": {
253
+ const h = {
254
+ ...r.context,
255
+ ...o,
256
+ device: {
257
+ ...(s = r.context) == null ? void 0 : s.device,
258
+ // biome-ignore lint/suspicious/noExplicitAny: IP field not in base device type
259
+ // Add IP (using type assertion for extended fields)
260
+ ...t ? { ip: t } : {}
261
+ }
262
+ };
263
+ n.pageView(r.properties, h);
264
+ break;
265
+ }
266
+ case "reset":
267
+ break;
268
+ default:
269
+ console.warn("[Proxy] Unknown event type:", r);
270
+ }
271
+ } catch (h) {
272
+ i != null && i.onError ? i.onError(h) : console.error("[Proxy] Failed to process event:", h);
273
+ }
274
+ } catch (a) {
275
+ throw i != null && i.onError ? i.onError(a) : console.error("[Proxy] Failed to ingest events:", a), a;
276
+ }
277
+ }
278
+ function m(l) {
279
+ var i;
280
+ const n = [
281
+ "x-forwarded-for",
282
+ "x-real-ip",
283
+ "cf-connecting-ip",
284
+ // Cloudflare
285
+ "x-client-ip",
286
+ "x-cluster-client-ip"
287
+ ];
288
+ for (const e of n) {
289
+ const s = l.headers.get(e);
290
+ if (s)
291
+ return (i = s.split(",")[0]) == null ? void 0 : i.trim();
292
+ }
293
+ }
294
+ function k(l, n) {
295
+ return async (i) => {
296
+ try {
297
+ return await g(i, l, n), new Response("OK", { status: 200 });
298
+ } catch (e) {
299
+ return console.error("[Proxy] Handler error:", e), new Response("Internal Server Error", { status: 500 });
300
+ }
301
+ };
302
+ }
219
303
  export {
220
- f as BaseAnalyticsProvider,
221
- b as BentoServerProvider,
222
- w as PirschServerProvider,
223
- k as PostHogServerProvider
304
+ p as BaseAnalyticsProvider,
305
+ v as BentoServerProvider,
306
+ E as PirschServerProvider,
307
+ z as PostHogServerProvider,
308
+ k as createProxyHandler,
309
+ g as ingestProxyEvents
224
310
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stacksee/analytics",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "A highly typed, provider-agnostic analytics library for TypeScript applications",
5
5
  "type": "module",
6
6
  "exports": {
@@ -70,6 +70,10 @@
70
70
  "pnpm": ">=9.0.0",
71
71
  "node": ">=20"
72
72
  },
73
+ "dependencies": {
74
+ "@tailwindcss/vite": "^4.1.16",
75
+ "tailwindcss": "^4.1.16"
76
+ },
73
77
  "scripts": {
74
78
  "test": "vitest run",
75
79
  "test:watch": "vitest",