@analytics-compliance/analytics-sdk 0.1.0 → 0.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/dist/index.cjs CHANGED
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- createAnalytics: () => createAnalytics
23
+ analytics: () => analytics,
24
+ default: () => sdk_default
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
26
27
 
@@ -68,14 +69,17 @@ function detectDeviceType(userAgent) {
68
69
  if (!userAgent) return "unknown";
69
70
  return "desktop";
70
71
  }
71
- function getDeviceInfo() {
72
+ function buildDeviceInfo() {
72
73
  if (typeof navigator === "undefined") {
73
74
  return {
74
75
  deviceType: "unknown",
75
76
  osName: "unknown",
76
77
  osVersion: "unknown",
77
78
  browserName: "unknown",
78
- browserVersion: "unknown"
79
+ browserVersion: "unknown",
80
+ country: "",
81
+ city: "",
82
+ ipAddress: ""
79
83
  };
80
84
  }
81
85
  const userAgent = navigator.userAgent ?? "";
@@ -86,120 +90,215 @@ function getDeviceInfo() {
86
90
  osName: os.osName,
87
91
  osVersion: os.osVersion,
88
92
  browserName: browser.browserName,
89
- browserVersion: browser.browserVersion
93
+ browserVersion: browser.browserVersion,
94
+ // country/city/ipAddress will be enriched on ingestion side.
95
+ country: "",
96
+ city: "",
97
+ ipAddress: ""
90
98
  };
91
99
  }
92
100
 
93
101
  // src/session.ts
94
- var SESSION_STORAGE_KEY = "analytics_sdk_session_id";
95
- function generateId() {
96
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
97
- return crypto.randomUUID();
98
- }
99
- return `ses_${Date.now()}_${Math.random().toString(16).slice(2)}`;
102
+ var SESSION_STORAGE_KEY = "analytics_sdk_session";
103
+ var SESSION_AGE_MS = 30 * 60 * 1e3;
104
+ function createSession(now = Date.now()) {
105
+ const id = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? `ses_${crypto.randomUUID()}` : `ses_${now}_${Math.random().toString(16).slice(2)}`;
106
+ return {
107
+ id,
108
+ startedAt: now,
109
+ expiresAt: now + SESSION_AGE_MS
110
+ };
100
111
  }
101
- function getOrCreateSessionId() {
112
+ function getSessionData() {
102
113
  if (typeof sessionStorage === "undefined") {
103
- return generateId();
114
+ return createSession();
115
+ }
116
+ const now = Date.now();
117
+ const raw = sessionStorage.getItem(SESSION_STORAGE_KEY);
118
+ if (raw) {
119
+ try {
120
+ const parsed = JSON.parse(raw);
121
+ if (now < parsed.expiresAt) {
122
+ const extended = {
123
+ ...parsed,
124
+ expiresAt: now + SESSION_AGE_MS
125
+ };
126
+ sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(extended));
127
+ return extended;
128
+ }
129
+ } catch {
130
+ }
104
131
  }
105
- const existing = sessionStorage.getItem(SESSION_STORAGE_KEY);
106
- if (existing) return existing;
107
- const next = generateId();
108
- sessionStorage.setItem(SESSION_STORAGE_KEY, next);
109
- return next;
132
+ const fresh = createSession(now);
133
+ sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(fresh));
134
+ return fresh;
135
+ }
136
+ function getSessionInfo() {
137
+ const session = getSessionData();
138
+ return {
139
+ sessionId: session.id,
140
+ startedAt: new Date(session.startedAt).toISOString(),
141
+ expiresAt: new Date(session.expiresAt).toISOString(),
142
+ isExpired: Date.now() > session.expiresAt
143
+ };
110
144
  }
111
145
 
112
146
  // src/sdk.ts
113
- function ensureRequiredConfig(config) {
114
- if (!config.endpoint) throw new Error("Analytics SDK: endpoint is required");
115
- if (!config.clientId) throw new Error("Analytics SDK: clientId is required");
116
- if (!config.clientName) throw new Error("Analytics SDK: clientName is required");
117
- }
118
- function generateEventId() {
147
+ var DEFAULT_INGESTION_ENDPOINT = "http://localhost:3001";
148
+ var _config = null;
149
+ var _user = null;
150
+ function uuid() {
119
151
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
120
152
  return crypto.randomUUID();
121
153
  }
122
- return `evt_${Date.now()}_${Math.random().toString(16).slice(2)}`;
123
- }
124
- async function postEvent(fetchImpl, endpoint, payload, apiKey) {
125
- const headers = {
126
- "Content-Type": "application/json"
127
- };
128
- if (apiKey) headers["X-API-Key"] = apiKey;
129
- const response = await fetchImpl(endpoint, {
130
- method: "POST",
131
- headers,
132
- body: JSON.stringify(payload),
133
- keepalive: true
154
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
155
+ const random = Math.random() * 16 | 0;
156
+ const value = char === "x" ? random : random & 3 | 8;
157
+ return value.toString(16);
134
158
  });
135
- if (!response.ok) {
136
- throw new Error(`Analytics SDK: ingestion error (${response.status})`);
159
+ }
160
+ function debugLog(...args) {
161
+ if (_config?.debug) {
162
+ console.log("[analytics-sdk]", ...args);
163
+ }
164
+ }
165
+ function getCurrentPageView() {
166
+ if (typeof window === "undefined") return "";
167
+ return window.location.pathname + window.location.search;
168
+ }
169
+ function getUrlParams() {
170
+ if (typeof window === "undefined") return {};
171
+ const params = {};
172
+ try {
173
+ const url = new URL(window.location.href);
174
+ url.searchParams.forEach((value, key) => {
175
+ params[key] = value;
176
+ });
177
+ } catch {
137
178
  }
179
+ return params;
138
180
  }
139
- function createAnalytics(config) {
140
- ensureRequiredConfig(config);
141
- const fetchImpl = config.fetchImpl ?? fetch;
142
- let currentPageView = config.defaultPageView;
143
- let currentUser = config.user;
144
- let currentContent = config.content;
145
- const getSession = () => getOrCreateSessionId();
146
- const getDevice = () => getDeviceInfo();
147
- const buildPayload = (eventName, input) => {
148
- const normalizedEventName = (eventName || "custom").trim();
149
- if (!normalizedEventName) {
150
- throw new Error("Analytics SDK: eventName must not be empty");
181
+ function resolveEndpoint(base) {
182
+ const globalEnv = globalThis.process?.env;
183
+ const source = base || globalEnv?.NEXT_PUBLIC_INGESTION_URL || DEFAULT_INGESTION_ENDPOINT;
184
+ return source.endsWith("/v1/events/batch") ? source : `${source.replace(/\/$/, "")}/v1/events/batch`;
185
+ }
186
+ async function sendEvent(payload) {
187
+ if (!_config) {
188
+ console.warn("[analytics-sdk] Please call analytics.init() before sending events.");
189
+ return;
190
+ }
191
+ try {
192
+ const response = await _config.fetchImpl(_config.endpoint, {
193
+ method: "POST",
194
+ headers: {
195
+ "Content-Type": "application/json",
196
+ "X-API-Key": _config.client.apiKey,
197
+ "X-Client-ID": _config.client.clientId
198
+ },
199
+ body: JSON.stringify({ events: [payload] }),
200
+ keepalive: true
201
+ });
202
+ if (!response.ok) {
203
+ const errorText = await response.text().catch(() => "");
204
+ console.error(`[analytics-sdk] Error response: ${response.status}`, errorText);
205
+ return;
151
206
  }
152
- return {
153
- eventId: generateEventId(),
154
- eventName: normalizedEventName,
155
- eventTime: (/* @__PURE__ */ new Date()).toISOString(),
156
- sessionId: getSession(),
157
- clientId: config.clientId,
158
- clientName: config.clientName,
159
- pageView: input?.pageView ?? currentPageView,
160
- user: input?.user ?? currentUser,
161
- content: input?.content ?? currentContent,
162
- // ip/city/country intentionally omitted here and expected from ingestion side.
163
- device: getDevice(),
164
- meta: input?.meta
165
- };
166
- };
167
- const track = async (eventName, input) => {
168
- const payload = buildPayload(eventName, input);
169
- await postEvent(fetchImpl, config.endpoint, payload, config.apiKey);
170
- };
171
- const initial = (input) => {
172
- if (input?.pageView) currentPageView = input.pageView;
173
- if (input?.user) currentUser = input.user;
174
- if (input?.content) currentContent = input.content;
175
- getSession();
176
- };
207
+ debugLog("event sent", payload.eventName);
208
+ } catch (error) {
209
+ console.error("[analytics-sdk] Network error:", error);
210
+ }
211
+ }
212
+ function buildEventPayload(eventName, content) {
213
+ const session = getSessionData();
177
214
  return {
178
- initial,
179
- setPageView: (pageView) => {
180
- currentPageView = pageView;
181
- },
182
- setUser: (user) => {
183
- currentUser = user;
184
- },
185
- setContent: (content) => {
186
- currentContent = content;
187
- },
188
- getSession,
189
- getDevice,
190
- track,
191
- trackPageView: (input) => track("event.pageView", input),
192
- trackSearched: (input) => track("event.searched", input),
193
- trackDownloaded: (input) => track("event.downloaded", input),
194
- trackClicked: (input) => track("event.clicked", input),
195
- trackSubmitted: (input) => track("event.submitted", input),
196
- trackLogin: (input) => track("event.login", input),
197
- trackSessionStart: (input) => track("event.sessionStart", input),
198
- trackCustom: (customEventName, input) => track(customEventName || "custom", input)
215
+ eventId: `evt_${uuid()}`,
216
+ eventName,
217
+ eventTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
218
+ sessionId: session.id,
219
+ clientName: _config?.client.clientName ?? "",
220
+ clientId: _config?.client.clientId ?? "",
221
+ pageView: getCurrentPageView(),
222
+ user: _user,
223
+ device: buildDeviceInfo(),
224
+ ...content && Object.keys(content).length > 0 ? { content } : {}
199
225
  };
200
226
  }
227
+ var analytics = {
228
+ init(cfg) {
229
+ _config = {
230
+ client: cfg.client,
231
+ endpoint: resolveEndpoint(cfg.endpoint),
232
+ debug: cfg.debug ?? false,
233
+ fetchImpl: cfg.fetchImpl ?? fetch
234
+ };
235
+ if (cfg.user) {
236
+ _user = { ...cfg.user };
237
+ }
238
+ getSessionData();
239
+ debugLog("initialized", {
240
+ clientId: cfg.client.clientId,
241
+ clientName: cfg.client.clientName
242
+ });
243
+ },
244
+ setUser(user) {
245
+ _user = { ...user };
246
+ debugLog("user set", user.userId);
247
+ },
248
+ clearUser() {
249
+ _user = null;
250
+ debugLog("user cleared");
251
+ },
252
+ getUser() {
253
+ return _user ? { ..._user } : null;
254
+ },
255
+ getClient() {
256
+ return _config ? { ..._config.client } : null;
257
+ },
258
+ pageView(contents) {
259
+ const urlParams = getUrlParams();
260
+ const payload = buildEventPayload("page_view", {
261
+ ...urlParams,
262
+ ...contents,
263
+ page_url: typeof window !== "undefined" ? window.location.href : "",
264
+ page_path: typeof window !== "undefined" ? window.location.pathname : "",
265
+ page_title: typeof document !== "undefined" ? document.title : "",
266
+ referrer_url: typeof document !== "undefined" ? document.referrer : ""
267
+ });
268
+ void sendEvent(payload);
269
+ },
270
+ eventViewed(contents) {
271
+ void sendEvent(buildEventPayload("event.viewed", contents));
272
+ },
273
+ eventSearched(contents) {
274
+ void sendEvent(buildEventPayload("event.searched", contents));
275
+ },
276
+ eventDownloaded(contents) {
277
+ void sendEvent(buildEventPayload("event.downloaded", contents));
278
+ },
279
+ eventClicked(contents) {
280
+ void sendEvent(buildEventPayload("event.clicked", contents));
281
+ },
282
+ eventSubmitted(contents) {
283
+ void sendEvent(buildEventPayload("event.submitted", contents));
284
+ },
285
+ eventLogin(contents) {
286
+ void sendEvent(buildEventPayload("event.login", contents));
287
+ },
288
+ eventSessionStart() {
289
+ void sendEvent(buildEventPayload("event.sessionStart"));
290
+ },
291
+ eventCustom(eventName, contents) {
292
+ const safeEventName = eventName.trim() || "custom";
293
+ void sendEvent(buildEventPayload(safeEventName, contents));
294
+ },
295
+ getSession() {
296
+ return getSessionInfo();
297
+ }
298
+ };
299
+ var sdk_default = analytics;
201
300
  // Annotate the CommonJS export names for ESM import in node:
202
301
  0 && (module.exports = {
203
- createAnalytics
302
+ analytics
204
303
  });
205
304
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/device.ts","../src/session.ts","../src/sdk.ts"],"sourcesContent":["export { createAnalytics } from \"./sdk\";\nexport type {\n AnalyticsEventPayload,\n AnalyticsSdkConfig,\n KnownEventName,\n SdkContent,\n SdkDevice,\n SdkUser,\n TrackInput\n} from \"./types\";\n","import type { SdkDevice } from \"./types\";\n\nfunction parseOs(userAgent: string): Pick<SdkDevice, \"osName\" | \"osVersion\"> {\n if (/Windows NT/i.test(userAgent)) {\n const match = userAgent.match(/Windows NT ([\\d.]+)/i);\n return { osName: \"Windows\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/Android/i.test(userAgent)) {\n const match = userAgent.match(/Android ([\\d.]+)/i);\n return { osName: \"Android\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/iPhone|iPad|iPod/i.test(userAgent)) {\n const match = userAgent.match(/OS ([\\d_]+)/i);\n return { osName: \"iOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Mac OS X/i.test(userAgent)) {\n const match = userAgent.match(/Mac OS X ([\\d_]+)/i);\n return { osName: \"macOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Linux/i.test(userAgent)) {\n return { osName: \"Linux\", osVersion: \"unknown\" };\n }\n return { osName: \"unknown\", osVersion: \"unknown\" };\n}\n\nfunction parseBrowser(userAgent: string): Pick<SdkDevice, \"browserName\" | \"browserVersion\"> {\n const candidates: Array<{ name: string; regex: RegExp }> = [\n { name: \"Edge\", regex: /Edg\\/([\\d.]+)/i },\n { name: \"Chrome\", regex: /Chrome\\/([\\d.]+)/i },\n { name: \"Firefox\", regex: /Firefox\\/([\\d.]+)/i },\n { name: \"Safari\", regex: /Version\\/([\\d.]+).*Safari/i }\n ];\n\n for (const candidate of candidates) {\n const match = userAgent.match(candidate.regex);\n if (match) {\n return { browserName: candidate.name, browserVersion: match[1] };\n }\n }\n\n return { browserName: \"unknown\", browserVersion: \"unknown\" };\n}\n\nfunction detectDeviceType(userAgent: string): SdkDevice[\"deviceType\"] {\n if (/Tablet|iPad/i.test(userAgent)) return \"tablet\";\n if (/Mobile|Android|iPhone|iPod/i.test(userAgent)) return \"mobile\";\n if (!userAgent) return \"unknown\";\n return \"desktop\";\n}\n\nexport function getDeviceInfo(): SdkDevice {\n if (typeof navigator === \"undefined\") {\n return {\n deviceType: \"unknown\",\n osName: \"unknown\",\n osVersion: \"unknown\",\n browserName: \"unknown\",\n browserVersion: \"unknown\"\n };\n }\n\n const userAgent = navigator.userAgent ?? \"\";\n const os = parseOs(userAgent);\n const browser = parseBrowser(userAgent);\n\n return {\n deviceType: detectDeviceType(userAgent),\n osName: os.osName,\n osVersion: os.osVersion,\n browserName: browser.browserName,\n browserVersion: browser.browserVersion\n };\n}\n","const SESSION_STORAGE_KEY = \"analytics_sdk_session_id\";\n\nfunction generateId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n return `ses_${Date.now()}_${Math.random().toString(16).slice(2)}`;\n}\n\nexport function getOrCreateSessionId(): string {\n if (typeof sessionStorage === \"undefined\") {\n return generateId();\n }\n\n const existing = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (existing) return existing;\n\n const next = generateId();\n sessionStorage.setItem(SESSION_STORAGE_KEY, next);\n return next;\n}\n","import { getDeviceInfo } from \"./device\";\nimport { getOrCreateSessionId } from \"./session\";\nimport type {\n AnalyticsEventPayload,\n AnalyticsSdkConfig,\n KnownEventName,\n SdkContent,\n SdkUser,\n TrackInput\n} from \"./types\";\n\nfunction ensureRequiredConfig(config: AnalyticsSdkConfig): void {\n if (!config.endpoint) throw new Error(\"Analytics SDK: endpoint is required\");\n if (!config.clientId) throw new Error(\"Analytics SDK: clientId is required\");\n if (!config.clientName) throw new Error(\"Analytics SDK: clientName is required\");\n}\n\nfunction generateEventId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n return `evt_${Date.now()}_${Math.random().toString(16).slice(2)}`;\n}\n\nasync function postEvent(\n fetchImpl: typeof fetch,\n endpoint: string,\n payload: AnalyticsEventPayload,\n apiKey?: string\n): Promise<void> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\"\n };\n\n if (apiKey) headers[\"X-API-Key\"] = apiKey;\n\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n keepalive: true\n });\n\n if (!response.ok) {\n throw new Error(`Analytics SDK: ingestion error (${response.status})`);\n }\n}\n\nexport interface AnalyticsSdk {\n initial: (input?: Pick<TrackInput, \"pageView\" | \"user\" | \"content\">) => void;\n setPageView: (pageView: string) => void;\n setUser: (user?: SdkUser) => void;\n setContent: (content?: SdkContent) => void;\n getSession: () => string;\n getDevice: () => ReturnType<typeof getDeviceInfo>;\n track: (eventName: KnownEventName | string, input?: TrackInput) => Promise<void>;\n trackPageView: (input?: TrackInput) => Promise<void>;\n trackSearched: (input?: TrackInput) => Promise<void>;\n trackDownloaded: (input?: TrackInput) => Promise<void>;\n trackClicked: (input?: TrackInput) => Promise<void>;\n trackSubmitted: (input?: TrackInput) => Promise<void>;\n trackLogin: (input?: TrackInput) => Promise<void>;\n trackSessionStart: (input?: TrackInput) => Promise<void>;\n trackCustom: (customEventName: string, input?: TrackInput) => Promise<void>;\n}\n\nexport function createAnalytics(config: AnalyticsSdkConfig): AnalyticsSdk {\n ensureRequiredConfig(config);\n\n const fetchImpl = config.fetchImpl ?? fetch;\n\n let currentPageView = config.defaultPageView;\n let currentUser = config.user;\n let currentContent = config.content;\n\n const getSession = (): string => getOrCreateSessionId();\n const getDevice = () => getDeviceInfo();\n\n const buildPayload = (eventName: string, input?: TrackInput): AnalyticsEventPayload => {\n const normalizedEventName = (eventName || \"custom\").trim();\n if (!normalizedEventName) {\n throw new Error(\"Analytics SDK: eventName must not be empty\");\n }\n\n return {\n eventId: generateEventId(),\n eventName: normalizedEventName,\n eventTime: new Date().toISOString(),\n sessionId: getSession(),\n clientId: config.clientId,\n clientName: config.clientName,\n pageView: input?.pageView ?? currentPageView,\n user: input?.user ?? currentUser,\n content: input?.content ?? currentContent,\n // ip/city/country intentionally omitted here and expected from ingestion side.\n device: getDevice(),\n meta: input?.meta\n };\n };\n\n const track = async (eventName: KnownEventName | string, input?: TrackInput): Promise<void> => {\n const payload = buildPayload(eventName, input);\n await postEvent(fetchImpl, config.endpoint, payload, config.apiKey);\n };\n\n const initial = (input?: Pick<TrackInput, \"pageView\" | \"user\" | \"content\">): void => {\n if (input?.pageView) currentPageView = input.pageView;\n if (input?.user) currentUser = input.user;\n if (input?.content) currentContent = input.content;\n getSession();\n };\n\n return {\n initial,\n setPageView: (pageView: string): void => {\n currentPageView = pageView;\n },\n setUser: (user?: SdkUser): void => {\n currentUser = user;\n },\n setContent: (content?: SdkContent): void => {\n currentContent = content;\n },\n getSession,\n getDevice,\n track,\n trackPageView: (input?: TrackInput) => track(\"event.pageView\", input),\n trackSearched: (input?: TrackInput) => track(\"event.searched\", input),\n trackDownloaded: (input?: TrackInput) => track(\"event.downloaded\", input),\n trackClicked: (input?: TrackInput) => track(\"event.clicked\", input),\n trackSubmitted: (input?: TrackInput) => track(\"event.submitted\", input),\n trackLogin: (input?: TrackInput) => track(\"event.login\", input),\n trackSessionStart: (input?: TrackInput) => track(\"event.sessionStart\", input),\n trackCustom: (customEventName: string, input?: TrackInput) => track(customEventName || \"custom\", input)\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/device.ts","../src/session.ts","../src/sdk.ts"],"sourcesContent":["export { analytics } from \"./sdk\";\nexport type { AnalyticsApi } from \"./sdk\";\nexport type {\n ClientConfig,\n Contents,\n DefaultEventType,\n DeviceInfo,\n EventPayload,\n InitConfig,\n SessionInfo,\n UserInfo\n} from \"./types\";\nexport { default } from \"./sdk\";\n","import type { DeviceInfo } from \"./types\";\n\nfunction parseOs(userAgent: string): Pick<DeviceInfo, \"osName\" | \"osVersion\"> {\n if (/Windows NT/i.test(userAgent)) {\n const match = userAgent.match(/Windows NT ([\\d.]+)/i);\n return { osName: \"Windows\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/Android/i.test(userAgent)) {\n const match = userAgent.match(/Android ([\\d.]+)/i);\n return { osName: \"Android\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/iPhone|iPad|iPod/i.test(userAgent)) {\n const match = userAgent.match(/OS ([\\d_]+)/i);\n return { osName: \"iOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Mac OS X/i.test(userAgent)) {\n const match = userAgent.match(/Mac OS X ([\\d_]+)/i);\n return { osName: \"macOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Linux/i.test(userAgent)) {\n return { osName: \"Linux\", osVersion: \"unknown\" };\n }\n return { osName: \"unknown\", osVersion: \"unknown\" };\n}\n\nfunction parseBrowser(userAgent: string): Pick<DeviceInfo, \"browserName\" | \"browserVersion\"> {\n const candidates: Array<{ name: string; regex: RegExp }> = [\n { name: \"Edge\", regex: /Edg\\/([\\d.]+)/i },\n { name: \"Chrome\", regex: /Chrome\\/([\\d.]+)/i },\n { name: \"Firefox\", regex: /Firefox\\/([\\d.]+)/i },\n { name: \"Safari\", regex: /Version\\/([\\d.]+).*Safari/i }\n ];\n\n for (const candidate of candidates) {\n const match = userAgent.match(candidate.regex);\n if (match) {\n return { browserName: candidate.name, browserVersion: match[1] };\n }\n }\n\n return { browserName: \"unknown\", browserVersion: \"unknown\" };\n}\n\nfunction detectDeviceType(userAgent: string): DeviceInfo[\"deviceType\"] {\n if (/Tablet|iPad/i.test(userAgent)) return \"tablet\";\n if (/Mobile|Android|iPhone|iPod/i.test(userAgent)) return \"mobile\";\n if (!userAgent) return \"unknown\";\n return \"desktop\";\n}\n\nexport function buildDeviceInfo(): DeviceInfo {\n if (typeof navigator === \"undefined\") {\n return {\n deviceType: \"unknown\",\n osName: \"unknown\",\n osVersion: \"unknown\",\n browserName: \"unknown\",\n browserVersion: \"unknown\",\n country: \"\",\n city: \"\",\n ipAddress: \"\"\n };\n }\n\n const userAgent = navigator.userAgent ?? \"\";\n const os = parseOs(userAgent);\n const browser = parseBrowser(userAgent);\n\n return {\n deviceType: detectDeviceType(userAgent),\n osName: os.osName,\n osVersion: os.osVersion,\n browserName: browser.browserName,\n browserVersion: browser.browserVersion,\n // country/city/ipAddress will be enriched on ingestion side.\n country: \"\",\n city: \"\",\n ipAddress: \"\"\n };\n}\n\nexport const getDeviceInfo = buildDeviceInfo;\n","import type { SessionInfo } from \"./types\";\n\nconst SESSION_STORAGE_KEY = \"analytics_sdk_session\";\nconst SESSION_AGE_MS = 30 * 60 * 1000;\n\ninterface RawSessionData {\n id: string;\n startedAt: number;\n expiresAt: number;\n}\n\nfunction createSession(now = Date.now()): RawSessionData {\n const id =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? `ses_${crypto.randomUUID()}`\n : `ses_${now}_${Math.random().toString(16).slice(2)}`;\n\n return {\n id,\n startedAt: now,\n expiresAt: now + SESSION_AGE_MS\n };\n}\n\nexport function getSessionData(): RawSessionData {\n if (typeof sessionStorage === \"undefined\") {\n return createSession();\n }\n\n const now = Date.now();\n const raw = sessionStorage.getItem(SESSION_STORAGE_KEY);\n\n if (raw) {\n try {\n const parsed = JSON.parse(raw) as RawSessionData;\n if (now < parsed.expiresAt) {\n const extended = {\n ...parsed,\n expiresAt: now + SESSION_AGE_MS\n };\n sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(extended));\n return extended;\n }\n } catch {\n // Invalid session data is replaced by a new one.\n }\n }\n\n const fresh = createSession(now);\n sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(fresh));\n return fresh;\n}\n\nexport function getSessionInfo(): SessionInfo {\n const session = getSessionData();\n\n return {\n sessionId: session.id,\n startedAt: new Date(session.startedAt).toISOString(),\n expiresAt: new Date(session.expiresAt).toISOString(),\n isExpired: Date.now() > session.expiresAt\n };\n}\n","import { buildDeviceInfo } from \"./device\";\nimport { getSessionData, getSessionInfo } from \"./session\";\nimport type { ClientConfig, Contents, DefaultEventType, EventPayload, InitConfig, SessionInfo, UserInfo } from \"./types\";\n\nconst DEFAULT_INGESTION_ENDPOINT = \"http://localhost:3001\";\n\nlet _config: { client: ClientConfig; endpoint: string; debug: boolean; fetchImpl: typeof fetch } | null = null;\nlet _user: UserInfo | null = null;\n\nfunction uuid(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (char) => {\n const random = (Math.random() * 16) | 0;\n const value = char === \"x\" ? random : (random & 0x3) | 0x8;\n return value.toString(16);\n });\n}\n\nfunction debugLog(...args: unknown[]): void {\n if (_config?.debug) {\n console.log(\"[analytics-sdk]\", ...args);\n }\n}\n\nfunction getCurrentPageView(): string {\n if (typeof window === \"undefined\") return \"\";\n return window.location.pathname + window.location.search;\n}\n\nfunction getUrlParams(): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n const params: Record<string, string> = {};\n\n try {\n const url = new URL(window.location.href);\n url.searchParams.forEach((value, key) => {\n params[key] = value;\n });\n } catch {\n // Ignore invalid URL parsing and return empty params.\n }\n\n return params;\n}\n\nfunction resolveEndpoint(base?: string): string {\n const globalEnv = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n const source =\n base ||\n globalEnv?.NEXT_PUBLIC_INGESTION_URL ||\n DEFAULT_INGESTION_ENDPOINT;\n\n return source.endsWith(\"/v1/events/batch\") ? source : `${source.replace(/\\/$/, \"\")}/v1/events/batch`;\n}\n\nasync function sendEvent(payload: EventPayload): Promise<void> {\n if (!_config) {\n console.warn(\"[analytics-sdk] Please call analytics.init() before sending events.\");\n return;\n }\n\n try {\n const response = await _config.fetchImpl(_config.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": _config.client.apiKey,\n \"X-Client-ID\": _config.client.clientId\n },\n body: JSON.stringify({ events: [payload] }),\n keepalive: true\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n console.error(`[analytics-sdk] Error response: ${response.status}`, errorText);\n return;\n }\n\n debugLog(\"event sent\", payload.eventName);\n } catch (error) {\n console.error(\"[analytics-sdk] Network error:\", error);\n }\n}\n\nfunction buildEventPayload(eventName: DefaultEventType | string, content?: Contents): EventPayload {\n const session = getSessionData();\n\n return {\n eventId: `evt_${uuid()}`,\n eventName,\n eventTimestamp: new Date().toISOString(),\n sessionId: session.id,\n clientName: _config?.client.clientName ?? \"\",\n clientId: _config?.client.clientId ?? \"\",\n pageView: getCurrentPageView(),\n user: _user,\n device: buildDeviceInfo(),\n ...(content && Object.keys(content).length > 0 ? { content } : {})\n };\n}\n\nexport interface AnalyticsApi {\n init: (cfg: InitConfig) => void;\n setUser: (user: UserInfo) => void;\n clearUser: () => void;\n getUser: () => UserInfo | null;\n getClient: () => ClientConfig | null;\n pageView: (contents?: Contents) => void;\n eventViewed: (contents?: Contents) => void;\n eventSearched: (contents?: Contents) => void;\n eventDownloaded: (contents?: Contents) => void;\n eventClicked: (contents?: Contents) => void;\n eventSubmitted: (contents?: Contents) => void;\n eventLogin: (contents?: Contents) => void;\n eventSessionStart: () => void;\n eventCustom: (eventName: string, contents?: Contents) => void;\n getSession: () => SessionInfo;\n}\n\nexport const analytics: AnalyticsApi = {\n init(cfg: InitConfig): void {\n _config = {\n client: cfg.client,\n endpoint: resolveEndpoint(cfg.endpoint),\n debug: cfg.debug ?? false,\n fetchImpl: cfg.fetchImpl ?? fetch\n };\n\n if (cfg.user) {\n _user = { ...cfg.user };\n }\n\n getSessionData();\n debugLog(\"initialized\", {\n clientId: cfg.client.clientId,\n clientName: cfg.client.clientName\n });\n },\n\n setUser(user: UserInfo): void {\n _user = { ...user };\n debugLog(\"user set\", user.userId);\n },\n\n clearUser(): void {\n _user = null;\n debugLog(\"user cleared\");\n },\n\n getUser(): UserInfo | null {\n return _user ? { ..._user } : null;\n },\n\n getClient(): ClientConfig | null {\n return _config ? { ..._config.client } : null;\n },\n\n pageView(contents?: Contents): void {\n const urlParams = getUrlParams();\n const payload = buildEventPayload(\"page_view\", {\n ...urlParams,\n ...contents,\n page_url: typeof window !== \"undefined\" ? window.location.href : \"\",\n page_path: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n page_title: typeof document !== \"undefined\" ? document.title : \"\",\n referrer_url: typeof document !== \"undefined\" ? document.referrer : \"\"\n });\n\n void sendEvent(payload);\n },\n\n eventViewed(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.viewed\", contents));\n },\n\n eventSearched(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.searched\", contents));\n },\n\n eventDownloaded(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.downloaded\", contents));\n },\n\n eventClicked(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.clicked\", contents));\n },\n\n eventSubmitted(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.submitted\", contents));\n },\n\n eventLogin(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.login\", contents));\n },\n\n eventSessionStart(): void {\n void sendEvent(buildEventPayload(\"event.sessionStart\"));\n },\n\n eventCustom(eventName: string, contents?: Contents): void {\n const safeEventName = eventName.trim() || \"custom\";\n void sendEvent(buildEventPayload(safeEventName, contents));\n },\n\n getSession(): SessionInfo {\n return getSessionInfo();\n }\n};\n\nexport default analytics;\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,10 @@
1
- type KnownEventName = "event.pageView" | "event.searched" | "event.downloaded" | "event.clicked" | "event.submitted" | "event.login" | "event.sessionStart";
2
- interface SdkUser {
3
- userId?: string;
1
+ interface ClientConfig {
2
+ clientId: string;
3
+ clientName: string;
4
+ apiKey: string;
5
+ }
6
+ interface UserInfo {
7
+ userId: string;
4
8
  email?: string;
5
9
  userType?: string;
6
10
  roles?: string[];
@@ -9,63 +13,61 @@ interface SdkUser {
9
13
  schoolNameEn?: string;
10
14
  [key: string]: unknown;
11
15
  }
12
- type SdkContent = Record<string, unknown>;
13
- interface SdkDevice {
16
+ interface InitConfig {
17
+ client: ClientConfig;
18
+ endpoint?: string;
19
+ user?: UserInfo;
20
+ debug?: boolean;
21
+ fetchImpl?: typeof fetch;
22
+ }
23
+ interface DeviceInfo {
14
24
  deviceType: "mobile" | "tablet" | "desktop" | "unknown";
15
25
  osName: string;
16
26
  osVersion: string;
17
27
  browserName: string;
18
28
  browserVersion: string;
29
+ country: string;
30
+ city: string;
31
+ ipAddress: string;
19
32
  }
20
- interface AnalyticsSdkConfig {
21
- endpoint: string;
22
- clientId: string;
23
- clientName: string;
24
- apiKey?: string;
25
- defaultPageView?: string;
26
- user?: SdkUser;
27
- content?: SdkContent;
28
- fetchImpl?: typeof fetch;
29
- }
30
- interface TrackInput {
31
- pageView?: string;
32
- user?: SdkUser;
33
- content?: SdkContent;
34
- meta?: Record<string, unknown>;
33
+ interface SessionInfo {
34
+ sessionId: string;
35
+ startedAt: string;
36
+ expiresAt: string;
37
+ isExpired: boolean;
35
38
  }
36
- interface AnalyticsEventPayload {
39
+ type Contents = Record<string, unknown>;
40
+ interface EventPayload {
37
41
  eventId: string;
38
42
  eventName: string;
39
- eventTime: string;
43
+ eventTimestamp: string;
40
44
  sessionId: string;
41
- clientId: string;
42
45
  clientName: string;
43
- pageView?: string;
44
- user?: SdkUser;
45
- content?: SdkContent;
46
- device: SdkDevice;
47
- meta?: Record<string, unknown>;
46
+ clientId: string;
47
+ pageView: string;
48
+ user: UserInfo | null;
49
+ device: DeviceInfo;
50
+ content?: Contents;
48
51
  }
52
+ type DefaultEventType = "event.viewed" | "event.searched" | "event.downloaded" | "event.clicked" | "event.submitted" | "event.login" | "event.sessionStart";
49
53
 
50
- declare function getDeviceInfo(): SdkDevice;
51
-
52
- interface AnalyticsSdk {
53
- initial: (input?: Pick<TrackInput, "pageView" | "user" | "content">) => void;
54
- setPageView: (pageView: string) => void;
55
- setUser: (user?: SdkUser) => void;
56
- setContent: (content?: SdkContent) => void;
57
- getSession: () => string;
58
- getDevice: () => ReturnType<typeof getDeviceInfo>;
59
- track: (eventName: KnownEventName | string, input?: TrackInput) => Promise<void>;
60
- trackPageView: (input?: TrackInput) => Promise<void>;
61
- trackSearched: (input?: TrackInput) => Promise<void>;
62
- trackDownloaded: (input?: TrackInput) => Promise<void>;
63
- trackClicked: (input?: TrackInput) => Promise<void>;
64
- trackSubmitted: (input?: TrackInput) => Promise<void>;
65
- trackLogin: (input?: TrackInput) => Promise<void>;
66
- trackSessionStart: (input?: TrackInput) => Promise<void>;
67
- trackCustom: (customEventName: string, input?: TrackInput) => Promise<void>;
54
+ interface AnalyticsApi {
55
+ init: (cfg: InitConfig) => void;
56
+ setUser: (user: UserInfo) => void;
57
+ clearUser: () => void;
58
+ getUser: () => UserInfo | null;
59
+ getClient: () => ClientConfig | null;
60
+ pageView: (contents?: Contents) => void;
61
+ eventViewed: (contents?: Contents) => void;
62
+ eventSearched: (contents?: Contents) => void;
63
+ eventDownloaded: (contents?: Contents) => void;
64
+ eventClicked: (contents?: Contents) => void;
65
+ eventSubmitted: (contents?: Contents) => void;
66
+ eventLogin: (contents?: Contents) => void;
67
+ eventSessionStart: () => void;
68
+ eventCustom: (eventName: string, contents?: Contents) => void;
69
+ getSession: () => SessionInfo;
68
70
  }
69
- declare function createAnalytics(config: AnalyticsSdkConfig): AnalyticsSdk;
71
+ declare const analytics: AnalyticsApi;
70
72
 
71
- export { type AnalyticsEventPayload, type AnalyticsSdkConfig, type KnownEventName, type SdkContent, type SdkDevice, type SdkUser, type TrackInput, createAnalytics };
73
+ export { type AnalyticsApi, type ClientConfig, type Contents, type DefaultEventType, type DeviceInfo, type EventPayload, type InitConfig, type SessionInfo, type UserInfo, analytics, analytics as default };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,10 @@
1
- type KnownEventName = "event.pageView" | "event.searched" | "event.downloaded" | "event.clicked" | "event.submitted" | "event.login" | "event.sessionStart";
2
- interface SdkUser {
3
- userId?: string;
1
+ interface ClientConfig {
2
+ clientId: string;
3
+ clientName: string;
4
+ apiKey: string;
5
+ }
6
+ interface UserInfo {
7
+ userId: string;
4
8
  email?: string;
5
9
  userType?: string;
6
10
  roles?: string[];
@@ -9,63 +13,61 @@ interface SdkUser {
9
13
  schoolNameEn?: string;
10
14
  [key: string]: unknown;
11
15
  }
12
- type SdkContent = Record<string, unknown>;
13
- interface SdkDevice {
16
+ interface InitConfig {
17
+ client: ClientConfig;
18
+ endpoint?: string;
19
+ user?: UserInfo;
20
+ debug?: boolean;
21
+ fetchImpl?: typeof fetch;
22
+ }
23
+ interface DeviceInfo {
14
24
  deviceType: "mobile" | "tablet" | "desktop" | "unknown";
15
25
  osName: string;
16
26
  osVersion: string;
17
27
  browserName: string;
18
28
  browserVersion: string;
29
+ country: string;
30
+ city: string;
31
+ ipAddress: string;
19
32
  }
20
- interface AnalyticsSdkConfig {
21
- endpoint: string;
22
- clientId: string;
23
- clientName: string;
24
- apiKey?: string;
25
- defaultPageView?: string;
26
- user?: SdkUser;
27
- content?: SdkContent;
28
- fetchImpl?: typeof fetch;
29
- }
30
- interface TrackInput {
31
- pageView?: string;
32
- user?: SdkUser;
33
- content?: SdkContent;
34
- meta?: Record<string, unknown>;
33
+ interface SessionInfo {
34
+ sessionId: string;
35
+ startedAt: string;
36
+ expiresAt: string;
37
+ isExpired: boolean;
35
38
  }
36
- interface AnalyticsEventPayload {
39
+ type Contents = Record<string, unknown>;
40
+ interface EventPayload {
37
41
  eventId: string;
38
42
  eventName: string;
39
- eventTime: string;
43
+ eventTimestamp: string;
40
44
  sessionId: string;
41
- clientId: string;
42
45
  clientName: string;
43
- pageView?: string;
44
- user?: SdkUser;
45
- content?: SdkContent;
46
- device: SdkDevice;
47
- meta?: Record<string, unknown>;
46
+ clientId: string;
47
+ pageView: string;
48
+ user: UserInfo | null;
49
+ device: DeviceInfo;
50
+ content?: Contents;
48
51
  }
52
+ type DefaultEventType = "event.viewed" | "event.searched" | "event.downloaded" | "event.clicked" | "event.submitted" | "event.login" | "event.sessionStart";
49
53
 
50
- declare function getDeviceInfo(): SdkDevice;
51
-
52
- interface AnalyticsSdk {
53
- initial: (input?: Pick<TrackInput, "pageView" | "user" | "content">) => void;
54
- setPageView: (pageView: string) => void;
55
- setUser: (user?: SdkUser) => void;
56
- setContent: (content?: SdkContent) => void;
57
- getSession: () => string;
58
- getDevice: () => ReturnType<typeof getDeviceInfo>;
59
- track: (eventName: KnownEventName | string, input?: TrackInput) => Promise<void>;
60
- trackPageView: (input?: TrackInput) => Promise<void>;
61
- trackSearched: (input?: TrackInput) => Promise<void>;
62
- trackDownloaded: (input?: TrackInput) => Promise<void>;
63
- trackClicked: (input?: TrackInput) => Promise<void>;
64
- trackSubmitted: (input?: TrackInput) => Promise<void>;
65
- trackLogin: (input?: TrackInput) => Promise<void>;
66
- trackSessionStart: (input?: TrackInput) => Promise<void>;
67
- trackCustom: (customEventName: string, input?: TrackInput) => Promise<void>;
54
+ interface AnalyticsApi {
55
+ init: (cfg: InitConfig) => void;
56
+ setUser: (user: UserInfo) => void;
57
+ clearUser: () => void;
58
+ getUser: () => UserInfo | null;
59
+ getClient: () => ClientConfig | null;
60
+ pageView: (contents?: Contents) => void;
61
+ eventViewed: (contents?: Contents) => void;
62
+ eventSearched: (contents?: Contents) => void;
63
+ eventDownloaded: (contents?: Contents) => void;
64
+ eventClicked: (contents?: Contents) => void;
65
+ eventSubmitted: (contents?: Contents) => void;
66
+ eventLogin: (contents?: Contents) => void;
67
+ eventSessionStart: () => void;
68
+ eventCustom: (eventName: string, contents?: Contents) => void;
69
+ getSession: () => SessionInfo;
68
70
  }
69
- declare function createAnalytics(config: AnalyticsSdkConfig): AnalyticsSdk;
71
+ declare const analytics: AnalyticsApi;
70
72
 
71
- export { type AnalyticsEventPayload, type AnalyticsSdkConfig, type KnownEventName, type SdkContent, type SdkDevice, type SdkUser, type TrackInput, createAnalytics };
73
+ export { type AnalyticsApi, type ClientConfig, type Contents, type DefaultEventType, type DeviceInfo, type EventPayload, type InitConfig, type SessionInfo, type UserInfo, analytics, analytics as default };
package/dist/index.js CHANGED
@@ -42,14 +42,17 @@ function detectDeviceType(userAgent) {
42
42
  if (!userAgent) return "unknown";
43
43
  return "desktop";
44
44
  }
45
- function getDeviceInfo() {
45
+ function buildDeviceInfo() {
46
46
  if (typeof navigator === "undefined") {
47
47
  return {
48
48
  deviceType: "unknown",
49
49
  osName: "unknown",
50
50
  osVersion: "unknown",
51
51
  browserName: "unknown",
52
- browserVersion: "unknown"
52
+ browserVersion: "unknown",
53
+ country: "",
54
+ city: "",
55
+ ipAddress: ""
53
56
  };
54
57
  }
55
58
  const userAgent = navigator.userAgent ?? "";
@@ -60,119 +63,215 @@ function getDeviceInfo() {
60
63
  osName: os.osName,
61
64
  osVersion: os.osVersion,
62
65
  browserName: browser.browserName,
63
- browserVersion: browser.browserVersion
66
+ browserVersion: browser.browserVersion,
67
+ // country/city/ipAddress will be enriched on ingestion side.
68
+ country: "",
69
+ city: "",
70
+ ipAddress: ""
64
71
  };
65
72
  }
66
73
 
67
74
  // src/session.ts
68
- var SESSION_STORAGE_KEY = "analytics_sdk_session_id";
69
- function generateId() {
70
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
71
- return crypto.randomUUID();
72
- }
73
- return `ses_${Date.now()}_${Math.random().toString(16).slice(2)}`;
75
+ var SESSION_STORAGE_KEY = "analytics_sdk_session";
76
+ var SESSION_AGE_MS = 30 * 60 * 1e3;
77
+ function createSession(now = Date.now()) {
78
+ const id = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? `ses_${crypto.randomUUID()}` : `ses_${now}_${Math.random().toString(16).slice(2)}`;
79
+ return {
80
+ id,
81
+ startedAt: now,
82
+ expiresAt: now + SESSION_AGE_MS
83
+ };
74
84
  }
75
- function getOrCreateSessionId() {
85
+ function getSessionData() {
76
86
  if (typeof sessionStorage === "undefined") {
77
- return generateId();
87
+ return createSession();
88
+ }
89
+ const now = Date.now();
90
+ const raw = sessionStorage.getItem(SESSION_STORAGE_KEY);
91
+ if (raw) {
92
+ try {
93
+ const parsed = JSON.parse(raw);
94
+ if (now < parsed.expiresAt) {
95
+ const extended = {
96
+ ...parsed,
97
+ expiresAt: now + SESSION_AGE_MS
98
+ };
99
+ sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(extended));
100
+ return extended;
101
+ }
102
+ } catch {
103
+ }
78
104
  }
79
- const existing = sessionStorage.getItem(SESSION_STORAGE_KEY);
80
- if (existing) return existing;
81
- const next = generateId();
82
- sessionStorage.setItem(SESSION_STORAGE_KEY, next);
83
- return next;
105
+ const fresh = createSession(now);
106
+ sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(fresh));
107
+ return fresh;
108
+ }
109
+ function getSessionInfo() {
110
+ const session = getSessionData();
111
+ return {
112
+ sessionId: session.id,
113
+ startedAt: new Date(session.startedAt).toISOString(),
114
+ expiresAt: new Date(session.expiresAt).toISOString(),
115
+ isExpired: Date.now() > session.expiresAt
116
+ };
84
117
  }
85
118
 
86
119
  // src/sdk.ts
87
- function ensureRequiredConfig(config) {
88
- if (!config.endpoint) throw new Error("Analytics SDK: endpoint is required");
89
- if (!config.clientId) throw new Error("Analytics SDK: clientId is required");
90
- if (!config.clientName) throw new Error("Analytics SDK: clientName is required");
91
- }
92
- function generateEventId() {
120
+ var DEFAULT_INGESTION_ENDPOINT = "http://localhost:3001";
121
+ var _config = null;
122
+ var _user = null;
123
+ function uuid() {
93
124
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
94
125
  return crypto.randomUUID();
95
126
  }
96
- return `evt_${Date.now()}_${Math.random().toString(16).slice(2)}`;
97
- }
98
- async function postEvent(fetchImpl, endpoint, payload, apiKey) {
99
- const headers = {
100
- "Content-Type": "application/json"
101
- };
102
- if (apiKey) headers["X-API-Key"] = apiKey;
103
- const response = await fetchImpl(endpoint, {
104
- method: "POST",
105
- headers,
106
- body: JSON.stringify(payload),
107
- keepalive: true
127
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
128
+ const random = Math.random() * 16 | 0;
129
+ const value = char === "x" ? random : random & 3 | 8;
130
+ return value.toString(16);
108
131
  });
109
- if (!response.ok) {
110
- throw new Error(`Analytics SDK: ingestion error (${response.status})`);
132
+ }
133
+ function debugLog(...args) {
134
+ if (_config?.debug) {
135
+ console.log("[analytics-sdk]", ...args);
136
+ }
137
+ }
138
+ function getCurrentPageView() {
139
+ if (typeof window === "undefined") return "";
140
+ return window.location.pathname + window.location.search;
141
+ }
142
+ function getUrlParams() {
143
+ if (typeof window === "undefined") return {};
144
+ const params = {};
145
+ try {
146
+ const url = new URL(window.location.href);
147
+ url.searchParams.forEach((value, key) => {
148
+ params[key] = value;
149
+ });
150
+ } catch {
111
151
  }
152
+ return params;
112
153
  }
113
- function createAnalytics(config) {
114
- ensureRequiredConfig(config);
115
- const fetchImpl = config.fetchImpl ?? fetch;
116
- let currentPageView = config.defaultPageView;
117
- let currentUser = config.user;
118
- let currentContent = config.content;
119
- const getSession = () => getOrCreateSessionId();
120
- const getDevice = () => getDeviceInfo();
121
- const buildPayload = (eventName, input) => {
122
- const normalizedEventName = (eventName || "custom").trim();
123
- if (!normalizedEventName) {
124
- throw new Error("Analytics SDK: eventName must not be empty");
154
+ function resolveEndpoint(base) {
155
+ const globalEnv = globalThis.process?.env;
156
+ const source = base || globalEnv?.NEXT_PUBLIC_INGESTION_URL || DEFAULT_INGESTION_ENDPOINT;
157
+ return source.endsWith("/v1/events/batch") ? source : `${source.replace(/\/$/, "")}/v1/events/batch`;
158
+ }
159
+ async function sendEvent(payload) {
160
+ if (!_config) {
161
+ console.warn("[analytics-sdk] Please call analytics.init() before sending events.");
162
+ return;
163
+ }
164
+ try {
165
+ const response = await _config.fetchImpl(_config.endpoint, {
166
+ method: "POST",
167
+ headers: {
168
+ "Content-Type": "application/json",
169
+ "X-API-Key": _config.client.apiKey,
170
+ "X-Client-ID": _config.client.clientId
171
+ },
172
+ body: JSON.stringify({ events: [payload] }),
173
+ keepalive: true
174
+ });
175
+ if (!response.ok) {
176
+ const errorText = await response.text().catch(() => "");
177
+ console.error(`[analytics-sdk] Error response: ${response.status}`, errorText);
178
+ return;
125
179
  }
126
- return {
127
- eventId: generateEventId(),
128
- eventName: normalizedEventName,
129
- eventTime: (/* @__PURE__ */ new Date()).toISOString(),
130
- sessionId: getSession(),
131
- clientId: config.clientId,
132
- clientName: config.clientName,
133
- pageView: input?.pageView ?? currentPageView,
134
- user: input?.user ?? currentUser,
135
- content: input?.content ?? currentContent,
136
- // ip/city/country intentionally omitted here and expected from ingestion side.
137
- device: getDevice(),
138
- meta: input?.meta
139
- };
140
- };
141
- const track = async (eventName, input) => {
142
- const payload = buildPayload(eventName, input);
143
- await postEvent(fetchImpl, config.endpoint, payload, config.apiKey);
144
- };
145
- const initial = (input) => {
146
- if (input?.pageView) currentPageView = input.pageView;
147
- if (input?.user) currentUser = input.user;
148
- if (input?.content) currentContent = input.content;
149
- getSession();
150
- };
180
+ debugLog("event sent", payload.eventName);
181
+ } catch (error) {
182
+ console.error("[analytics-sdk] Network error:", error);
183
+ }
184
+ }
185
+ function buildEventPayload(eventName, content) {
186
+ const session = getSessionData();
151
187
  return {
152
- initial,
153
- setPageView: (pageView) => {
154
- currentPageView = pageView;
155
- },
156
- setUser: (user) => {
157
- currentUser = user;
158
- },
159
- setContent: (content) => {
160
- currentContent = content;
161
- },
162
- getSession,
163
- getDevice,
164
- track,
165
- trackPageView: (input) => track("event.pageView", input),
166
- trackSearched: (input) => track("event.searched", input),
167
- trackDownloaded: (input) => track("event.downloaded", input),
168
- trackClicked: (input) => track("event.clicked", input),
169
- trackSubmitted: (input) => track("event.submitted", input),
170
- trackLogin: (input) => track("event.login", input),
171
- trackSessionStart: (input) => track("event.sessionStart", input),
172
- trackCustom: (customEventName, input) => track(customEventName || "custom", input)
188
+ eventId: `evt_${uuid()}`,
189
+ eventName,
190
+ eventTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
191
+ sessionId: session.id,
192
+ clientName: _config?.client.clientName ?? "",
193
+ clientId: _config?.client.clientId ?? "",
194
+ pageView: getCurrentPageView(),
195
+ user: _user,
196
+ device: buildDeviceInfo(),
197
+ ...content && Object.keys(content).length > 0 ? { content } : {}
173
198
  };
174
199
  }
200
+ var analytics = {
201
+ init(cfg) {
202
+ _config = {
203
+ client: cfg.client,
204
+ endpoint: resolveEndpoint(cfg.endpoint),
205
+ debug: cfg.debug ?? false,
206
+ fetchImpl: cfg.fetchImpl ?? fetch
207
+ };
208
+ if (cfg.user) {
209
+ _user = { ...cfg.user };
210
+ }
211
+ getSessionData();
212
+ debugLog("initialized", {
213
+ clientId: cfg.client.clientId,
214
+ clientName: cfg.client.clientName
215
+ });
216
+ },
217
+ setUser(user) {
218
+ _user = { ...user };
219
+ debugLog("user set", user.userId);
220
+ },
221
+ clearUser() {
222
+ _user = null;
223
+ debugLog("user cleared");
224
+ },
225
+ getUser() {
226
+ return _user ? { ..._user } : null;
227
+ },
228
+ getClient() {
229
+ return _config ? { ..._config.client } : null;
230
+ },
231
+ pageView(contents) {
232
+ const urlParams = getUrlParams();
233
+ const payload = buildEventPayload("page_view", {
234
+ ...urlParams,
235
+ ...contents,
236
+ page_url: typeof window !== "undefined" ? window.location.href : "",
237
+ page_path: typeof window !== "undefined" ? window.location.pathname : "",
238
+ page_title: typeof document !== "undefined" ? document.title : "",
239
+ referrer_url: typeof document !== "undefined" ? document.referrer : ""
240
+ });
241
+ void sendEvent(payload);
242
+ },
243
+ eventViewed(contents) {
244
+ void sendEvent(buildEventPayload("event.viewed", contents));
245
+ },
246
+ eventSearched(contents) {
247
+ void sendEvent(buildEventPayload("event.searched", contents));
248
+ },
249
+ eventDownloaded(contents) {
250
+ void sendEvent(buildEventPayload("event.downloaded", contents));
251
+ },
252
+ eventClicked(contents) {
253
+ void sendEvent(buildEventPayload("event.clicked", contents));
254
+ },
255
+ eventSubmitted(contents) {
256
+ void sendEvent(buildEventPayload("event.submitted", contents));
257
+ },
258
+ eventLogin(contents) {
259
+ void sendEvent(buildEventPayload("event.login", contents));
260
+ },
261
+ eventSessionStart() {
262
+ void sendEvent(buildEventPayload("event.sessionStart"));
263
+ },
264
+ eventCustom(eventName, contents) {
265
+ const safeEventName = eventName.trim() || "custom";
266
+ void sendEvent(buildEventPayload(safeEventName, contents));
267
+ },
268
+ getSession() {
269
+ return getSessionInfo();
270
+ }
271
+ };
272
+ var sdk_default = analytics;
175
273
  export {
176
- createAnalytics
274
+ analytics,
275
+ sdk_default as default
177
276
  };
178
277
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/device.ts","../src/session.ts","../src/sdk.ts"],"sourcesContent":["import type { SdkDevice } from \"./types\";\n\nfunction parseOs(userAgent: string): Pick<SdkDevice, \"osName\" | \"osVersion\"> {\n if (/Windows NT/i.test(userAgent)) {\n const match = userAgent.match(/Windows NT ([\\d.]+)/i);\n return { osName: \"Windows\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/Android/i.test(userAgent)) {\n const match = userAgent.match(/Android ([\\d.]+)/i);\n return { osName: \"Android\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/iPhone|iPad|iPod/i.test(userAgent)) {\n const match = userAgent.match(/OS ([\\d_]+)/i);\n return { osName: \"iOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Mac OS X/i.test(userAgent)) {\n const match = userAgent.match(/Mac OS X ([\\d_]+)/i);\n return { osName: \"macOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Linux/i.test(userAgent)) {\n return { osName: \"Linux\", osVersion: \"unknown\" };\n }\n return { osName: \"unknown\", osVersion: \"unknown\" };\n}\n\nfunction parseBrowser(userAgent: string): Pick<SdkDevice, \"browserName\" | \"browserVersion\"> {\n const candidates: Array<{ name: string; regex: RegExp }> = [\n { name: \"Edge\", regex: /Edg\\/([\\d.]+)/i },\n { name: \"Chrome\", regex: /Chrome\\/([\\d.]+)/i },\n { name: \"Firefox\", regex: /Firefox\\/([\\d.]+)/i },\n { name: \"Safari\", regex: /Version\\/([\\d.]+).*Safari/i }\n ];\n\n for (const candidate of candidates) {\n const match = userAgent.match(candidate.regex);\n if (match) {\n return { browserName: candidate.name, browserVersion: match[1] };\n }\n }\n\n return { browserName: \"unknown\", browserVersion: \"unknown\" };\n}\n\nfunction detectDeviceType(userAgent: string): SdkDevice[\"deviceType\"] {\n if (/Tablet|iPad/i.test(userAgent)) return \"tablet\";\n if (/Mobile|Android|iPhone|iPod/i.test(userAgent)) return \"mobile\";\n if (!userAgent) return \"unknown\";\n return \"desktop\";\n}\n\nexport function getDeviceInfo(): SdkDevice {\n if (typeof navigator === \"undefined\") {\n return {\n deviceType: \"unknown\",\n osName: \"unknown\",\n osVersion: \"unknown\",\n browserName: \"unknown\",\n browserVersion: \"unknown\"\n };\n }\n\n const userAgent = navigator.userAgent ?? \"\";\n const os = parseOs(userAgent);\n const browser = parseBrowser(userAgent);\n\n return {\n deviceType: detectDeviceType(userAgent),\n osName: os.osName,\n osVersion: os.osVersion,\n browserName: browser.browserName,\n browserVersion: browser.browserVersion\n };\n}\n","const SESSION_STORAGE_KEY = \"analytics_sdk_session_id\";\n\nfunction generateId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n return `ses_${Date.now()}_${Math.random().toString(16).slice(2)}`;\n}\n\nexport function getOrCreateSessionId(): string {\n if (typeof sessionStorage === \"undefined\") {\n return generateId();\n }\n\n const existing = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (existing) return existing;\n\n const next = generateId();\n sessionStorage.setItem(SESSION_STORAGE_KEY, next);\n return next;\n}\n","import { getDeviceInfo } from \"./device\";\nimport { getOrCreateSessionId } from \"./session\";\nimport type {\n AnalyticsEventPayload,\n AnalyticsSdkConfig,\n KnownEventName,\n SdkContent,\n SdkUser,\n TrackInput\n} from \"./types\";\n\nfunction ensureRequiredConfig(config: AnalyticsSdkConfig): void {\n if (!config.endpoint) throw new Error(\"Analytics SDK: endpoint is required\");\n if (!config.clientId) throw new Error(\"Analytics SDK: clientId is required\");\n if (!config.clientName) throw new Error(\"Analytics SDK: clientName is required\");\n}\n\nfunction generateEventId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n return `evt_${Date.now()}_${Math.random().toString(16).slice(2)}`;\n}\n\nasync function postEvent(\n fetchImpl: typeof fetch,\n endpoint: string,\n payload: AnalyticsEventPayload,\n apiKey?: string\n): Promise<void> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\"\n };\n\n if (apiKey) headers[\"X-API-Key\"] = apiKey;\n\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n keepalive: true\n });\n\n if (!response.ok) {\n throw new Error(`Analytics SDK: ingestion error (${response.status})`);\n }\n}\n\nexport interface AnalyticsSdk {\n initial: (input?: Pick<TrackInput, \"pageView\" | \"user\" | \"content\">) => void;\n setPageView: (pageView: string) => void;\n setUser: (user?: SdkUser) => void;\n setContent: (content?: SdkContent) => void;\n getSession: () => string;\n getDevice: () => ReturnType<typeof getDeviceInfo>;\n track: (eventName: KnownEventName | string, input?: TrackInput) => Promise<void>;\n trackPageView: (input?: TrackInput) => Promise<void>;\n trackSearched: (input?: TrackInput) => Promise<void>;\n trackDownloaded: (input?: TrackInput) => Promise<void>;\n trackClicked: (input?: TrackInput) => Promise<void>;\n trackSubmitted: (input?: TrackInput) => Promise<void>;\n trackLogin: (input?: TrackInput) => Promise<void>;\n trackSessionStart: (input?: TrackInput) => Promise<void>;\n trackCustom: (customEventName: string, input?: TrackInput) => Promise<void>;\n}\n\nexport function createAnalytics(config: AnalyticsSdkConfig): AnalyticsSdk {\n ensureRequiredConfig(config);\n\n const fetchImpl = config.fetchImpl ?? fetch;\n\n let currentPageView = config.defaultPageView;\n let currentUser = config.user;\n let currentContent = config.content;\n\n const getSession = (): string => getOrCreateSessionId();\n const getDevice = () => getDeviceInfo();\n\n const buildPayload = (eventName: string, input?: TrackInput): AnalyticsEventPayload => {\n const normalizedEventName = (eventName || \"custom\").trim();\n if (!normalizedEventName) {\n throw new Error(\"Analytics SDK: eventName must not be empty\");\n }\n\n return {\n eventId: generateEventId(),\n eventName: normalizedEventName,\n eventTime: new Date().toISOString(),\n sessionId: getSession(),\n clientId: config.clientId,\n clientName: config.clientName,\n pageView: input?.pageView ?? currentPageView,\n user: input?.user ?? currentUser,\n content: input?.content ?? currentContent,\n // ip/city/country intentionally omitted here and expected from ingestion side.\n device: getDevice(),\n meta: input?.meta\n };\n };\n\n const track = async (eventName: KnownEventName | string, input?: TrackInput): Promise<void> => {\n const payload = buildPayload(eventName, input);\n await postEvent(fetchImpl, config.endpoint, payload, config.apiKey);\n };\n\n const initial = (input?: Pick<TrackInput, \"pageView\" | \"user\" | \"content\">): void => {\n if (input?.pageView) currentPageView = input.pageView;\n if (input?.user) currentUser = input.user;\n if (input?.content) currentContent = input.content;\n getSession();\n };\n\n return {\n initial,\n setPageView: (pageView: string): void => {\n currentPageView = pageView;\n },\n setUser: (user?: SdkUser): void => {\n currentUser = user;\n },\n setContent: (content?: SdkContent): void => {\n currentContent = content;\n },\n getSession,\n getDevice,\n track,\n trackPageView: (input?: TrackInput) => track(\"event.pageView\", input),\n trackSearched: (input?: TrackInput) => track(\"event.searched\", input),\n trackDownloaded: (input?: TrackInput) => track(\"event.downloaded\", input),\n trackClicked: (input?: TrackInput) => track(\"event.clicked\", input),\n trackSubmitted: (input?: TrackInput) => track(\"event.submitted\", input),\n trackLogin: (input?: TrackInput) => track(\"event.login\", input),\n trackSessionStart: (input?: TrackInput) => track(\"event.sessionStart\", input),\n trackCustom: (customEventName: string, input?: TrackInput) => track(customEventName || \"custom\", input)\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/device.ts","../src/session.ts","../src/sdk.ts"],"sourcesContent":["import type { DeviceInfo } from \"./types\";\n\nfunction parseOs(userAgent: string): Pick<DeviceInfo, \"osName\" | \"osVersion\"> {\n if (/Windows NT/i.test(userAgent)) {\n const match = userAgent.match(/Windows NT ([\\d.]+)/i);\n return { osName: \"Windows\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/Android/i.test(userAgent)) {\n const match = userAgent.match(/Android ([\\d.]+)/i);\n return { osName: \"Android\", osVersion: match?.[1] ?? \"unknown\" };\n }\n if (/iPhone|iPad|iPod/i.test(userAgent)) {\n const match = userAgent.match(/OS ([\\d_]+)/i);\n return { osName: \"iOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Mac OS X/i.test(userAgent)) {\n const match = userAgent.match(/Mac OS X ([\\d_]+)/i);\n return { osName: \"macOS\", osVersion: (match?.[1] ?? \"unknown\").split(\"_\").join(\".\") };\n }\n if (/Linux/i.test(userAgent)) {\n return { osName: \"Linux\", osVersion: \"unknown\" };\n }\n return { osName: \"unknown\", osVersion: \"unknown\" };\n}\n\nfunction parseBrowser(userAgent: string): Pick<DeviceInfo, \"browserName\" | \"browserVersion\"> {\n const candidates: Array<{ name: string; regex: RegExp }> = [\n { name: \"Edge\", regex: /Edg\\/([\\d.]+)/i },\n { name: \"Chrome\", regex: /Chrome\\/([\\d.]+)/i },\n { name: \"Firefox\", regex: /Firefox\\/([\\d.]+)/i },\n { name: \"Safari\", regex: /Version\\/([\\d.]+).*Safari/i }\n ];\n\n for (const candidate of candidates) {\n const match = userAgent.match(candidate.regex);\n if (match) {\n return { browserName: candidate.name, browserVersion: match[1] };\n }\n }\n\n return { browserName: \"unknown\", browserVersion: \"unknown\" };\n}\n\nfunction detectDeviceType(userAgent: string): DeviceInfo[\"deviceType\"] {\n if (/Tablet|iPad/i.test(userAgent)) return \"tablet\";\n if (/Mobile|Android|iPhone|iPod/i.test(userAgent)) return \"mobile\";\n if (!userAgent) return \"unknown\";\n return \"desktop\";\n}\n\nexport function buildDeviceInfo(): DeviceInfo {\n if (typeof navigator === \"undefined\") {\n return {\n deviceType: \"unknown\",\n osName: \"unknown\",\n osVersion: \"unknown\",\n browserName: \"unknown\",\n browserVersion: \"unknown\",\n country: \"\",\n city: \"\",\n ipAddress: \"\"\n };\n }\n\n const userAgent = navigator.userAgent ?? \"\";\n const os = parseOs(userAgent);\n const browser = parseBrowser(userAgent);\n\n return {\n deviceType: detectDeviceType(userAgent),\n osName: os.osName,\n osVersion: os.osVersion,\n browserName: browser.browserName,\n browserVersion: browser.browserVersion,\n // country/city/ipAddress will be enriched on ingestion side.\n country: \"\",\n city: \"\",\n ipAddress: \"\"\n };\n}\n\nexport const getDeviceInfo = buildDeviceInfo;\n","import type { SessionInfo } from \"./types\";\n\nconst SESSION_STORAGE_KEY = \"analytics_sdk_session\";\nconst SESSION_AGE_MS = 30 * 60 * 1000;\n\ninterface RawSessionData {\n id: string;\n startedAt: number;\n expiresAt: number;\n}\n\nfunction createSession(now = Date.now()): RawSessionData {\n const id =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? `ses_${crypto.randomUUID()}`\n : `ses_${now}_${Math.random().toString(16).slice(2)}`;\n\n return {\n id,\n startedAt: now,\n expiresAt: now + SESSION_AGE_MS\n };\n}\n\nexport function getSessionData(): RawSessionData {\n if (typeof sessionStorage === \"undefined\") {\n return createSession();\n }\n\n const now = Date.now();\n const raw = sessionStorage.getItem(SESSION_STORAGE_KEY);\n\n if (raw) {\n try {\n const parsed = JSON.parse(raw) as RawSessionData;\n if (now < parsed.expiresAt) {\n const extended = {\n ...parsed,\n expiresAt: now + SESSION_AGE_MS\n };\n sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(extended));\n return extended;\n }\n } catch {\n // Invalid session data is replaced by a new one.\n }\n }\n\n const fresh = createSession(now);\n sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(fresh));\n return fresh;\n}\n\nexport function getSessionInfo(): SessionInfo {\n const session = getSessionData();\n\n return {\n sessionId: session.id,\n startedAt: new Date(session.startedAt).toISOString(),\n expiresAt: new Date(session.expiresAt).toISOString(),\n isExpired: Date.now() > session.expiresAt\n };\n}\n","import { buildDeviceInfo } from \"./device\";\nimport { getSessionData, getSessionInfo } from \"./session\";\nimport type { ClientConfig, Contents, DefaultEventType, EventPayload, InitConfig, SessionInfo, UserInfo } from \"./types\";\n\nconst DEFAULT_INGESTION_ENDPOINT = \"http://localhost:3001\";\n\nlet _config: { client: ClientConfig; endpoint: string; debug: boolean; fetchImpl: typeof fetch } | null = null;\nlet _user: UserInfo | null = null;\n\nfunction uuid(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (char) => {\n const random = (Math.random() * 16) | 0;\n const value = char === \"x\" ? random : (random & 0x3) | 0x8;\n return value.toString(16);\n });\n}\n\nfunction debugLog(...args: unknown[]): void {\n if (_config?.debug) {\n console.log(\"[analytics-sdk]\", ...args);\n }\n}\n\nfunction getCurrentPageView(): string {\n if (typeof window === \"undefined\") return \"\";\n return window.location.pathname + window.location.search;\n}\n\nfunction getUrlParams(): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n const params: Record<string, string> = {};\n\n try {\n const url = new URL(window.location.href);\n url.searchParams.forEach((value, key) => {\n params[key] = value;\n });\n } catch {\n // Ignore invalid URL parsing and return empty params.\n }\n\n return params;\n}\n\nfunction resolveEndpoint(base?: string): string {\n const globalEnv = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n const source =\n base ||\n globalEnv?.NEXT_PUBLIC_INGESTION_URL ||\n DEFAULT_INGESTION_ENDPOINT;\n\n return source.endsWith(\"/v1/events/batch\") ? source : `${source.replace(/\\/$/, \"\")}/v1/events/batch`;\n}\n\nasync function sendEvent(payload: EventPayload): Promise<void> {\n if (!_config) {\n console.warn(\"[analytics-sdk] Please call analytics.init() before sending events.\");\n return;\n }\n\n try {\n const response = await _config.fetchImpl(_config.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": _config.client.apiKey,\n \"X-Client-ID\": _config.client.clientId\n },\n body: JSON.stringify({ events: [payload] }),\n keepalive: true\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n console.error(`[analytics-sdk] Error response: ${response.status}`, errorText);\n return;\n }\n\n debugLog(\"event sent\", payload.eventName);\n } catch (error) {\n console.error(\"[analytics-sdk] Network error:\", error);\n }\n}\n\nfunction buildEventPayload(eventName: DefaultEventType | string, content?: Contents): EventPayload {\n const session = getSessionData();\n\n return {\n eventId: `evt_${uuid()}`,\n eventName,\n eventTimestamp: new Date().toISOString(),\n sessionId: session.id,\n clientName: _config?.client.clientName ?? \"\",\n clientId: _config?.client.clientId ?? \"\",\n pageView: getCurrentPageView(),\n user: _user,\n device: buildDeviceInfo(),\n ...(content && Object.keys(content).length > 0 ? { content } : {})\n };\n}\n\nexport interface AnalyticsApi {\n init: (cfg: InitConfig) => void;\n setUser: (user: UserInfo) => void;\n clearUser: () => void;\n getUser: () => UserInfo | null;\n getClient: () => ClientConfig | null;\n pageView: (contents?: Contents) => void;\n eventViewed: (contents?: Contents) => void;\n eventSearched: (contents?: Contents) => void;\n eventDownloaded: (contents?: Contents) => void;\n eventClicked: (contents?: Contents) => void;\n eventSubmitted: (contents?: Contents) => void;\n eventLogin: (contents?: Contents) => void;\n eventSessionStart: () => void;\n eventCustom: (eventName: string, contents?: Contents) => void;\n getSession: () => SessionInfo;\n}\n\nexport const analytics: AnalyticsApi = {\n init(cfg: InitConfig): void {\n _config = {\n client: cfg.client,\n endpoint: resolveEndpoint(cfg.endpoint),\n debug: cfg.debug ?? false,\n fetchImpl: cfg.fetchImpl ?? fetch\n };\n\n if (cfg.user) {\n _user = { ...cfg.user };\n }\n\n getSessionData();\n debugLog(\"initialized\", {\n clientId: cfg.client.clientId,\n clientName: cfg.client.clientName\n });\n },\n\n setUser(user: UserInfo): void {\n _user = { ...user };\n debugLog(\"user set\", user.userId);\n },\n\n clearUser(): void {\n _user = null;\n debugLog(\"user cleared\");\n },\n\n getUser(): UserInfo | null {\n return _user ? { ..._user } : null;\n },\n\n getClient(): ClientConfig | null {\n return _config ? { ..._config.client } : null;\n },\n\n pageView(contents?: Contents): void {\n const urlParams = getUrlParams();\n const payload = buildEventPayload(\"page_view\", {\n ...urlParams,\n ...contents,\n page_url: typeof window !== \"undefined\" ? window.location.href : \"\",\n page_path: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n page_title: typeof document !== \"undefined\" ? document.title : \"\",\n referrer_url: typeof document !== \"undefined\" ? document.referrer : \"\"\n });\n\n void sendEvent(payload);\n },\n\n eventViewed(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.viewed\", contents));\n },\n\n eventSearched(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.searched\", contents));\n },\n\n eventDownloaded(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.downloaded\", contents));\n },\n\n eventClicked(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.clicked\", contents));\n },\n\n eventSubmitted(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.submitted\", contents));\n },\n\n eventLogin(contents?: Contents): void {\n void sendEvent(buildEventPayload(\"event.login\", contents));\n },\n\n eventSessionStart(): void {\n void sendEvent(buildEventPayload(\"event.sessionStart\"));\n },\n\n eventCustom(eventName: string, contents?: Contents): void {\n const safeEventName = eventName.trim() || \"custom\";\n void sendEvent(buildEventPayload(safeEventName, contents));\n },\n\n getSession(): SessionInfo {\n return getSessionInfo();\n }\n};\n\nexport default analytics;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analytics-compliance/analytics-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Lightweight analytics SDK for sending client events to ingestion service.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",