@analytics-compliance/analytics-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -0
- package/dist/index.cjs +205 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +71 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +178 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# @yourorg/analytics-sdk
|
|
2
|
+
|
|
3
|
+
Analytics SDK for sending client events to your ingestion service.
|
|
4
|
+
|
|
5
|
+
## What this SDK sends
|
|
6
|
+
|
|
7
|
+
- Required from client app:
|
|
8
|
+
- `clientName`
|
|
9
|
+
- `clientId`
|
|
10
|
+
- `pageView` (per event or default)
|
|
11
|
+
- Optional from client app:
|
|
12
|
+
- `user`
|
|
13
|
+
- `content`
|
|
14
|
+
- Added by SDK:
|
|
15
|
+
- `sessionId`
|
|
16
|
+
- `device` (`deviceType`, `osName`, `osVersion`, `browserName`, `browserVersion`)
|
|
17
|
+
- Added by ingestion (server side):
|
|
18
|
+
- `ip`, `city`, `country`
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i @yourorg/analytics-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { createAnalytics } from "@yourorg/analytics-sdk";
|
|
30
|
+
|
|
31
|
+
const analytics = createAnalytics({
|
|
32
|
+
endpoint: "https://your-ingestion.example.com/events",
|
|
33
|
+
clientId: "ci_a12345c5-3dggkdab222",
|
|
34
|
+
clientName: "onlearn-web",
|
|
35
|
+
apiKey: "your-api-key"
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
analytics.initial({
|
|
39
|
+
pageView: "/ebook-detail"
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
analytics.setUser({
|
|
43
|
+
userId: "usr_123",
|
|
44
|
+
userType: "teacher"
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
analytics.setContent({
|
|
48
|
+
itemId: "prod_xyz-123",
|
|
49
|
+
fileType: "pptx"
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await analytics.trackPageView();
|
|
53
|
+
await analytics.trackDownloaded();
|
|
54
|
+
await analytics.trackCustom("custom.anyAction", {
|
|
55
|
+
meta: { buttonId: "download-now" }
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## SDK API
|
|
60
|
+
|
|
61
|
+
- `initial({ pageView?, user?, content? })`
|
|
62
|
+
- `setPageView(pageView)`
|
|
63
|
+
- `setUser(user?)`
|
|
64
|
+
- `setContent(content?)`
|
|
65
|
+
- `getSession()`
|
|
66
|
+
- `getDevice()`
|
|
67
|
+
- `track(eventName, input?)`
|
|
68
|
+
- `trackPageView(input?)`
|
|
69
|
+
- `trackSearched(input?)`
|
|
70
|
+
- `trackDownloaded(input?)`
|
|
71
|
+
- `trackClicked(input?)`
|
|
72
|
+
- `trackSubmitted(input?)`
|
|
73
|
+
- `trackLogin(input?)`
|
|
74
|
+
- `trackSessionStart(input?)`
|
|
75
|
+
- `trackCustom(customEventName, input?)`
|
|
76
|
+
|
|
77
|
+
## Plug this SDK into other projects
|
|
78
|
+
|
|
79
|
+
### Option A: Published package (recommended)
|
|
80
|
+
|
|
81
|
+
1. Publish this package to npm (or private registry)
|
|
82
|
+
2. In client project:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm i @yourorg/analytics-sdk
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
3. Import and use as shown above
|
|
89
|
+
|
|
90
|
+
### Option B: Local package during development
|
|
91
|
+
|
|
92
|
+
In this SDK project:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npm run build
|
|
96
|
+
npm pack
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Then in client project install the generated `.tgz` file:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm i ../path-to-sdk/yourorg-analytics-sdk-1.0.0.tgz
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Option C: npm link for active local development
|
|
106
|
+
|
|
107
|
+
In SDK project:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm link
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
In client project:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npm link @yourorg/analytics-sdk
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Build
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npm run build
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Publish (manual)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npm login
|
|
129
|
+
npm publish --access public
|
|
130
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createAnalytics: () => createAnalytics
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/device.ts
|
|
28
|
+
function parseOs(userAgent) {
|
|
29
|
+
if (/Windows NT/i.test(userAgent)) {
|
|
30
|
+
const match = userAgent.match(/Windows NT ([\d.]+)/i);
|
|
31
|
+
return { osName: "Windows", osVersion: match?.[1] ?? "unknown" };
|
|
32
|
+
}
|
|
33
|
+
if (/Android/i.test(userAgent)) {
|
|
34
|
+
const match = userAgent.match(/Android ([\d.]+)/i);
|
|
35
|
+
return { osName: "Android", osVersion: match?.[1] ?? "unknown" };
|
|
36
|
+
}
|
|
37
|
+
if (/iPhone|iPad|iPod/i.test(userAgent)) {
|
|
38
|
+
const match = userAgent.match(/OS ([\d_]+)/i);
|
|
39
|
+
return { osName: "iOS", osVersion: (match?.[1] ?? "unknown").split("_").join(".") };
|
|
40
|
+
}
|
|
41
|
+
if (/Mac OS X/i.test(userAgent)) {
|
|
42
|
+
const match = userAgent.match(/Mac OS X ([\d_]+)/i);
|
|
43
|
+
return { osName: "macOS", osVersion: (match?.[1] ?? "unknown").split("_").join(".") };
|
|
44
|
+
}
|
|
45
|
+
if (/Linux/i.test(userAgent)) {
|
|
46
|
+
return { osName: "Linux", osVersion: "unknown" };
|
|
47
|
+
}
|
|
48
|
+
return { osName: "unknown", osVersion: "unknown" };
|
|
49
|
+
}
|
|
50
|
+
function parseBrowser(userAgent) {
|
|
51
|
+
const candidates = [
|
|
52
|
+
{ name: "Edge", regex: /Edg\/([\d.]+)/i },
|
|
53
|
+
{ name: "Chrome", regex: /Chrome\/([\d.]+)/i },
|
|
54
|
+
{ name: "Firefox", regex: /Firefox\/([\d.]+)/i },
|
|
55
|
+
{ name: "Safari", regex: /Version\/([\d.]+).*Safari/i }
|
|
56
|
+
];
|
|
57
|
+
for (const candidate of candidates) {
|
|
58
|
+
const match = userAgent.match(candidate.regex);
|
|
59
|
+
if (match) {
|
|
60
|
+
return { browserName: candidate.name, browserVersion: match[1] };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return { browserName: "unknown", browserVersion: "unknown" };
|
|
64
|
+
}
|
|
65
|
+
function detectDeviceType(userAgent) {
|
|
66
|
+
if (/Tablet|iPad/i.test(userAgent)) return "tablet";
|
|
67
|
+
if (/Mobile|Android|iPhone|iPod/i.test(userAgent)) return "mobile";
|
|
68
|
+
if (!userAgent) return "unknown";
|
|
69
|
+
return "desktop";
|
|
70
|
+
}
|
|
71
|
+
function getDeviceInfo() {
|
|
72
|
+
if (typeof navigator === "undefined") {
|
|
73
|
+
return {
|
|
74
|
+
deviceType: "unknown",
|
|
75
|
+
osName: "unknown",
|
|
76
|
+
osVersion: "unknown",
|
|
77
|
+
browserName: "unknown",
|
|
78
|
+
browserVersion: "unknown"
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const userAgent = navigator.userAgent ?? "";
|
|
82
|
+
const os = parseOs(userAgent);
|
|
83
|
+
const browser = parseBrowser(userAgent);
|
|
84
|
+
return {
|
|
85
|
+
deviceType: detectDeviceType(userAgent),
|
|
86
|
+
osName: os.osName,
|
|
87
|
+
osVersion: os.osVersion,
|
|
88
|
+
browserName: browser.browserName,
|
|
89
|
+
browserVersion: browser.browserVersion
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 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)}`;
|
|
100
|
+
}
|
|
101
|
+
function getOrCreateSessionId() {
|
|
102
|
+
if (typeof sessionStorage === "undefined") {
|
|
103
|
+
return generateId();
|
|
104
|
+
}
|
|
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;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 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() {
|
|
119
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
120
|
+
return crypto.randomUUID();
|
|
121
|
+
}
|
|
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
|
|
134
|
+
});
|
|
135
|
+
if (!response.ok) {
|
|
136
|
+
throw new Error(`Analytics SDK: ingestion error (${response.status})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
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");
|
|
151
|
+
}
|
|
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
|
+
};
|
|
177
|
+
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)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
202
|
+
0 && (module.exports = {
|
|
203
|
+
createAnalytics
|
|
204
|
+
});
|
|
205
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
type KnownEventName = "event.pageView" | "event.searched" | "event.downloaded" | "event.clicked" | "event.submitted" | "event.login" | "event.sessionStart";
|
|
2
|
+
interface SdkUser {
|
|
3
|
+
userId?: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
userType?: string;
|
|
6
|
+
roles?: string[];
|
|
7
|
+
schoolId?: string;
|
|
8
|
+
schoolNameTh?: string;
|
|
9
|
+
schoolNameEn?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
type SdkContent = Record<string, unknown>;
|
|
13
|
+
interface SdkDevice {
|
|
14
|
+
deviceType: "mobile" | "tablet" | "desktop" | "unknown";
|
|
15
|
+
osName: string;
|
|
16
|
+
osVersion: string;
|
|
17
|
+
browserName: string;
|
|
18
|
+
browserVersion: string;
|
|
19
|
+
}
|
|
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>;
|
|
35
|
+
}
|
|
36
|
+
interface AnalyticsEventPayload {
|
|
37
|
+
eventId: string;
|
|
38
|
+
eventName: string;
|
|
39
|
+
eventTime: string;
|
|
40
|
+
sessionId: string;
|
|
41
|
+
clientId: string;
|
|
42
|
+
clientName: string;
|
|
43
|
+
pageView?: string;
|
|
44
|
+
user?: SdkUser;
|
|
45
|
+
content?: SdkContent;
|
|
46
|
+
device: SdkDevice;
|
|
47
|
+
meta?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
|
|
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>;
|
|
68
|
+
}
|
|
69
|
+
declare function createAnalytics(config: AnalyticsSdkConfig): AnalyticsSdk;
|
|
70
|
+
|
|
71
|
+
export { type AnalyticsEventPayload, type AnalyticsSdkConfig, type KnownEventName, type SdkContent, type SdkDevice, type SdkUser, type TrackInput, createAnalytics };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
type KnownEventName = "event.pageView" | "event.searched" | "event.downloaded" | "event.clicked" | "event.submitted" | "event.login" | "event.sessionStart";
|
|
2
|
+
interface SdkUser {
|
|
3
|
+
userId?: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
userType?: string;
|
|
6
|
+
roles?: string[];
|
|
7
|
+
schoolId?: string;
|
|
8
|
+
schoolNameTh?: string;
|
|
9
|
+
schoolNameEn?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
type SdkContent = Record<string, unknown>;
|
|
13
|
+
interface SdkDevice {
|
|
14
|
+
deviceType: "mobile" | "tablet" | "desktop" | "unknown";
|
|
15
|
+
osName: string;
|
|
16
|
+
osVersion: string;
|
|
17
|
+
browserName: string;
|
|
18
|
+
browserVersion: string;
|
|
19
|
+
}
|
|
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>;
|
|
35
|
+
}
|
|
36
|
+
interface AnalyticsEventPayload {
|
|
37
|
+
eventId: string;
|
|
38
|
+
eventName: string;
|
|
39
|
+
eventTime: string;
|
|
40
|
+
sessionId: string;
|
|
41
|
+
clientId: string;
|
|
42
|
+
clientName: string;
|
|
43
|
+
pageView?: string;
|
|
44
|
+
user?: SdkUser;
|
|
45
|
+
content?: SdkContent;
|
|
46
|
+
device: SdkDevice;
|
|
47
|
+
meta?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
|
|
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>;
|
|
68
|
+
}
|
|
69
|
+
declare function createAnalytics(config: AnalyticsSdkConfig): AnalyticsSdk;
|
|
70
|
+
|
|
71
|
+
export { type AnalyticsEventPayload, type AnalyticsSdkConfig, type KnownEventName, type SdkContent, type SdkDevice, type SdkUser, type TrackInput, createAnalytics };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// src/device.ts
|
|
2
|
+
function parseOs(userAgent) {
|
|
3
|
+
if (/Windows NT/i.test(userAgent)) {
|
|
4
|
+
const match = userAgent.match(/Windows NT ([\d.]+)/i);
|
|
5
|
+
return { osName: "Windows", osVersion: match?.[1] ?? "unknown" };
|
|
6
|
+
}
|
|
7
|
+
if (/Android/i.test(userAgent)) {
|
|
8
|
+
const match = userAgent.match(/Android ([\d.]+)/i);
|
|
9
|
+
return { osName: "Android", osVersion: match?.[1] ?? "unknown" };
|
|
10
|
+
}
|
|
11
|
+
if (/iPhone|iPad|iPod/i.test(userAgent)) {
|
|
12
|
+
const match = userAgent.match(/OS ([\d_]+)/i);
|
|
13
|
+
return { osName: "iOS", osVersion: (match?.[1] ?? "unknown").split("_").join(".") };
|
|
14
|
+
}
|
|
15
|
+
if (/Mac OS X/i.test(userAgent)) {
|
|
16
|
+
const match = userAgent.match(/Mac OS X ([\d_]+)/i);
|
|
17
|
+
return { osName: "macOS", osVersion: (match?.[1] ?? "unknown").split("_").join(".") };
|
|
18
|
+
}
|
|
19
|
+
if (/Linux/i.test(userAgent)) {
|
|
20
|
+
return { osName: "Linux", osVersion: "unknown" };
|
|
21
|
+
}
|
|
22
|
+
return { osName: "unknown", osVersion: "unknown" };
|
|
23
|
+
}
|
|
24
|
+
function parseBrowser(userAgent) {
|
|
25
|
+
const candidates = [
|
|
26
|
+
{ name: "Edge", regex: /Edg\/([\d.]+)/i },
|
|
27
|
+
{ name: "Chrome", regex: /Chrome\/([\d.]+)/i },
|
|
28
|
+
{ name: "Firefox", regex: /Firefox\/([\d.]+)/i },
|
|
29
|
+
{ name: "Safari", regex: /Version\/([\d.]+).*Safari/i }
|
|
30
|
+
];
|
|
31
|
+
for (const candidate of candidates) {
|
|
32
|
+
const match = userAgent.match(candidate.regex);
|
|
33
|
+
if (match) {
|
|
34
|
+
return { browserName: candidate.name, browserVersion: match[1] };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { browserName: "unknown", browserVersion: "unknown" };
|
|
38
|
+
}
|
|
39
|
+
function detectDeviceType(userAgent) {
|
|
40
|
+
if (/Tablet|iPad/i.test(userAgent)) return "tablet";
|
|
41
|
+
if (/Mobile|Android|iPhone|iPod/i.test(userAgent)) return "mobile";
|
|
42
|
+
if (!userAgent) return "unknown";
|
|
43
|
+
return "desktop";
|
|
44
|
+
}
|
|
45
|
+
function getDeviceInfo() {
|
|
46
|
+
if (typeof navigator === "undefined") {
|
|
47
|
+
return {
|
|
48
|
+
deviceType: "unknown",
|
|
49
|
+
osName: "unknown",
|
|
50
|
+
osVersion: "unknown",
|
|
51
|
+
browserName: "unknown",
|
|
52
|
+
browserVersion: "unknown"
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const userAgent = navigator.userAgent ?? "";
|
|
56
|
+
const os = parseOs(userAgent);
|
|
57
|
+
const browser = parseBrowser(userAgent);
|
|
58
|
+
return {
|
|
59
|
+
deviceType: detectDeviceType(userAgent),
|
|
60
|
+
osName: os.osName,
|
|
61
|
+
osVersion: os.osVersion,
|
|
62
|
+
browserName: browser.browserName,
|
|
63
|
+
browserVersion: browser.browserVersion
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 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)}`;
|
|
74
|
+
}
|
|
75
|
+
function getOrCreateSessionId() {
|
|
76
|
+
if (typeof sessionStorage === "undefined") {
|
|
77
|
+
return generateId();
|
|
78
|
+
}
|
|
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;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 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() {
|
|
93
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
94
|
+
return crypto.randomUUID();
|
|
95
|
+
}
|
|
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
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new Error(`Analytics SDK: ingestion error (${response.status})`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
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");
|
|
125
|
+
}
|
|
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
|
+
};
|
|
151
|
+
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)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
createAnalytics
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":";AAEA,SAAS,QAAQ,WAA4D;AAC3E,MAAI,cAAc,KAAK,SAAS,GAAG;AACjC,UAAM,QAAQ,UAAU,MAAM,sBAAsB;AACpD,WAAO,EAAE,QAAQ,WAAW,WAAW,QAAQ,CAAC,KAAK,UAAU;AAAA,EACjE;AACA,MAAI,WAAW,KAAK,SAAS,GAAG;AAC9B,UAAM,QAAQ,UAAU,MAAM,mBAAmB;AACjD,WAAO,EAAE,QAAQ,WAAW,WAAW,QAAQ,CAAC,KAAK,UAAU;AAAA,EACjE;AACA,MAAI,oBAAoB,KAAK,SAAS,GAAG;AACvC,UAAM,QAAQ,UAAU,MAAM,cAAc;AAC5C,WAAO,EAAE,QAAQ,OAAO,YAAY,QAAQ,CAAC,KAAK,WAAW,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE;AAAA,EACpF;AACA,MAAI,YAAY,KAAK,SAAS,GAAG;AAC/B,UAAM,QAAQ,UAAU,MAAM,oBAAoB;AAClD,WAAO,EAAE,QAAQ,SAAS,YAAY,QAAQ,CAAC,KAAK,WAAW,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE;AAAA,EACtF;AACA,MAAI,SAAS,KAAK,SAAS,GAAG;AAC5B,WAAO,EAAE,QAAQ,SAAS,WAAW,UAAU;AAAA,EACjD;AACA,SAAO,EAAE,QAAQ,WAAW,WAAW,UAAU;AACnD;AAEA,SAAS,aAAa,WAAsE;AAC1F,QAAM,aAAqD;AAAA,IACzD,EAAE,MAAM,QAAQ,OAAO,iBAAiB;AAAA,IACxC,EAAE,MAAM,UAAU,OAAO,oBAAoB;AAAA,IAC7C,EAAE,MAAM,WAAW,OAAO,qBAAqB;AAAA,IAC/C,EAAE,MAAM,UAAU,OAAO,6BAA6B;AAAA,EACxD;AAEA,aAAW,aAAa,YAAY;AAClC,UAAM,QAAQ,UAAU,MAAM,UAAU,KAAK;AAC7C,QAAI,OAAO;AACT,aAAO,EAAE,aAAa,UAAU,MAAM,gBAAgB,MAAM,CAAC,EAAE;AAAA,IACjE;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,WAAW,gBAAgB,UAAU;AAC7D;AAEA,SAAS,iBAAiB,WAA4C;AACpE,MAAI,eAAe,KAAK,SAAS,EAAG,QAAO;AAC3C,MAAI,8BAA8B,KAAK,SAAS,EAAG,QAAO;AAC1D,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO;AACT;AAEO,SAAS,gBAA2B;AACzC,MAAI,OAAO,cAAc,aAAa;AACpC,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,aAAa;AAAA,MACb,gBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,YAAY,UAAU,aAAa;AACzC,QAAM,KAAK,QAAQ,SAAS;AAC5B,QAAM,UAAU,aAAa,SAAS;AAEtC,SAAO;AAAA,IACL,YAAY,iBAAiB,SAAS;AAAA,IACtC,QAAQ,GAAG;AAAA,IACX,WAAW,GAAG;AAAA,IACd,aAAa,QAAQ;AAAA,IACrB,gBAAgB,QAAQ;AAAA,EAC1B;AACF;;;ACxEA,IAAM,sBAAsB;AAE5B,SAAS,aAAqB;AAC5B,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AAEA,SAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AACjE;AAEO,SAAS,uBAA+B;AAC7C,MAAI,OAAO,mBAAmB,aAAa;AACzC,WAAO,WAAW;AAAA,EACpB;AAEA,QAAM,WAAW,eAAe,QAAQ,mBAAmB;AAC3D,MAAI,SAAU,QAAO;AAErB,QAAM,OAAO,WAAW;AACxB,iBAAe,QAAQ,qBAAqB,IAAI;AAChD,SAAO;AACT;;;ACVA,SAAS,qBAAqB,QAAkC;AAC9D,MAAI,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,qCAAqC;AAC3E,MAAI,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,qCAAqC;AAC3E,MAAI,CAAC,OAAO,WAAY,OAAM,IAAI,MAAM,uCAAuC;AACjF;AAEA,SAAS,kBAA0B;AACjC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AAEA,SAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AACjE;AAEA,eAAe,UACb,WACA,UACA,SACA,QACe;AACf,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,EAClB;AAEA,MAAI,OAAQ,SAAQ,WAAW,IAAI;AAEnC,QAAM,WAAW,MAAM,UAAU,UAAU;AAAA,IACzC,QAAQ;AAAA,IACR;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,IAC5B,WAAW;AAAA,EACb,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,mCAAmC,SAAS,MAAM,GAAG;AAAA,EACvE;AACF;AAoBO,SAAS,gBAAgB,QAA0C;AACxE,uBAAqB,MAAM;AAE3B,QAAM,YAAY,OAAO,aAAa;AAEtC,MAAI,kBAAkB,OAAO;AAC7B,MAAI,cAAc,OAAO;AACzB,MAAI,iBAAiB,OAAO;AAE5B,QAAM,aAAa,MAAc,qBAAqB;AACtD,QAAM,YAAY,MAAM,cAAc;AAEtC,QAAM,eAAe,CAAC,WAAmB,UAA8C;AACrF,UAAM,uBAAuB,aAAa,UAAU,KAAK;AACzD,QAAI,CAAC,qBAAqB;AACxB,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,WAAO;AAAA,MACL,SAAS,gBAAgB;AAAA,MACzB,WAAW;AAAA,MACX,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,WAAW,WAAW;AAAA,MACtB,UAAU,OAAO;AAAA,MACjB,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO,YAAY;AAAA,MAC7B,MAAM,OAAO,QAAQ;AAAA,MACrB,SAAS,OAAO,WAAW;AAAA;AAAA,MAE3B,QAAQ,UAAU;AAAA,MAClB,MAAM,OAAO;AAAA,IACf;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO,WAAoC,UAAsC;AAC7F,UAAM,UAAU,aAAa,WAAW,KAAK;AAC7C,UAAM,UAAU,WAAW,OAAO,UAAU,SAAS,OAAO,MAAM;AAAA,EACpE;AAEA,QAAM,UAAU,CAAC,UAAoE;AACnF,QAAI,OAAO,SAAU,mBAAkB,MAAM;AAC7C,QAAI,OAAO,KAAM,eAAc,MAAM;AACrC,QAAI,OAAO,QAAS,kBAAiB,MAAM;AAC3C,eAAW;AAAA,EACb;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,CAAC,aAA2B;AACvC,wBAAkB;AAAA,IACpB;AAAA,IACA,SAAS,CAAC,SAAyB;AACjC,oBAAc;AAAA,IAChB;AAAA,IACA,YAAY,CAAC,YAA+B;AAC1C,uBAAiB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,CAAC,UAAuB,MAAM,kBAAkB,KAAK;AAAA,IACpE,eAAe,CAAC,UAAuB,MAAM,kBAAkB,KAAK;AAAA,IACpE,iBAAiB,CAAC,UAAuB,MAAM,oBAAoB,KAAK;AAAA,IACxE,cAAc,CAAC,UAAuB,MAAM,iBAAiB,KAAK;AAAA,IAClE,gBAAgB,CAAC,UAAuB,MAAM,mBAAmB,KAAK;AAAA,IACtE,YAAY,CAAC,UAAuB,MAAM,eAAe,KAAK;AAAA,IAC9D,mBAAmB,CAAC,UAAuB,MAAM,sBAAsB,KAAK;AAAA,IAC5E,aAAa,CAAC,iBAAyB,UAAuB,MAAM,mBAAmB,UAAU,KAAK;AAAA,EACxG;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@analytics-compliance/analytics-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight analytics SDK for sending client events to ingestion service.",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsup",
|
|
13
|
+
"dev": "tsup --watch",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"require": "./dist/index.cjs"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"tsup": "^8.5.1",
|
|
30
|
+
"typescript": "^5.9.3"
|
|
31
|
+
}
|
|
32
|
+
}
|