@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 +195 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -48
- package/dist/index.d.ts +50 -48
- package/dist/index.js +194 -95
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
|
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 = "
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
|
112
|
+
function getSessionData() {
|
|
102
113
|
if (typeof sessionStorage === "undefined") {
|
|
103
|
-
return
|
|
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
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
136
|
-
|
|
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
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
302
|
+
analytics
|
|
204
303
|
});
|
|
205
304
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
13
|
-
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
39
|
+
type Contents = Record<string, unknown>;
|
|
40
|
+
interface EventPayload {
|
|
37
41
|
eventId: string;
|
|
38
42
|
eventName: string;
|
|
39
|
-
|
|
43
|
+
eventTimestamp: string;
|
|
40
44
|
sessionId: string;
|
|
41
|
-
clientId: string;
|
|
42
45
|
clientName: string;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
device:
|
|
47
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
|
71
|
+
declare const analytics: AnalyticsApi;
|
|
70
72
|
|
|
71
|
-
export { type
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
13
|
-
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
39
|
+
type Contents = Record<string, unknown>;
|
|
40
|
+
interface EventPayload {
|
|
37
41
|
eventId: string;
|
|
38
42
|
eventName: string;
|
|
39
|
-
|
|
43
|
+
eventTimestamp: string;
|
|
40
44
|
sessionId: string;
|
|
41
|
-
clientId: string;
|
|
42
45
|
clientName: string;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
device:
|
|
47
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
|
71
|
+
declare const analytics: AnalyticsApi;
|
|
70
72
|
|
|
71
|
-
export { type
|
|
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
|
|
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 = "
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
85
|
+
function getSessionData() {
|
|
76
86
|
if (typeof sessionStorage === "undefined") {
|
|
77
|
-
return
|
|
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
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
110
|
-
|
|
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
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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