@armco/analytics 0.2.10 → 0.2.12
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/core/analytics.d.ts +48 -0
- package/core/analytics.js +311 -0
- package/core/errors.d.ts +26 -0
- package/core/errors.js +54 -0
- package/core/types.d.ts +133 -0
- package/index.d.ts +24 -2
- package/index.js +24 -13
- package/package.json +9 -28
- package/plugins/auto-track/click.d.ts +15 -0
- package/plugins/auto-track/click.js +95 -0
- package/plugins/auto-track/error.d.ts +15 -0
- package/plugins/auto-track/error.js +65 -0
- package/plugins/auto-track/form.d.ts +13 -0
- package/plugins/auto-track/form.js +54 -0
- package/plugins/auto-track/page.d.ts +14 -0
- package/plugins/auto-track/page.js +71 -0
- package/plugins/enrichment/session.d.ts +18 -0
- package/plugins/enrichment/session.js +81 -0
- package/plugins/enrichment/user.d.ts +20 -0
- package/plugins/enrichment/user.js +152 -0
- package/plugins/node/http-request-tracking.d.ts +54 -0
- package/plugins/node/http-request-tracking.js +158 -0
- package/storage/cookie-storage.d.ts +8 -0
- package/storage/cookie-storage.js +60 -0
- package/storage/hybrid-storage.d.ts +12 -0
- package/storage/hybrid-storage.js +108 -0
- package/storage/local-storage.d.ts +8 -0
- package/storage/local-storage.js +65 -0
- package/storage/memory-storage.d.ts +9 -0
- package/storage/memory-storage.js +22 -0
- package/transport/beacon-transport.d.ts +16 -0
- package/transport/beacon-transport.js +50 -0
- package/transport/fetch-transport.d.ts +20 -0
- package/transport/fetch-transport.js +112 -0
- package/utils/config-loader.d.ts +3 -0
- package/utils/config-loader.js +59 -0
- package/utils/helpers.d.ts +15 -0
- package/utils/helpers.js +148 -0
- package/utils/logging.d.ts +17 -0
- package/utils/logging.js +54 -0
- package/utils/validation.d.ts +9 -0
- package/utils/validation.js +146 -0
- package/.npmignore +0 -6
- package/analytics.d.ts +0 -19
- package/analytics.js +0 -537
- package/constants.d.ts +0 -3
- package/constants.js +0 -3
- package/flush.d.ts +0 -3
- package/flush.js +0 -36
- package/helper.d.ts +0 -1
- package/helper.js +0 -3
- package/index.interface.d.ts +0 -28
- package/location.d.ts +0 -6
- package/location.js +0 -42
- package/session.d.ts +0 -4
- package/session.js +0 -76
- package/tsconfig.prod.tsbuildinfo +0 -1
- /package/{index.interface.js → core/types.js} +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AnalyticsConfig, IAnalytics, Plugin, EventData, PageViewEvent, ClickEvent, ErrorEvent, User, StorageManager, Transport } from "./types";
|
|
2
|
+
export declare class AnalyticsBuilder {
|
|
3
|
+
private config;
|
|
4
|
+
private plugins;
|
|
5
|
+
private storage?;
|
|
6
|
+
private transport?;
|
|
7
|
+
withApiKey(apiKey: string): this;
|
|
8
|
+
withEndpoint(endpoint: string): this;
|
|
9
|
+
withHostProjectName(name: string): this;
|
|
10
|
+
withLogLevel(level: AnalyticsConfig["logLevel"]): this;
|
|
11
|
+
withSubmissionStrategy(strategy: AnalyticsConfig["submissionStrategy"]): this;
|
|
12
|
+
withSamplingRate(rate: number): this;
|
|
13
|
+
withPlugin(plugin: Plugin): this;
|
|
14
|
+
withStorage(storage: StorageManager): this;
|
|
15
|
+
withTransport(transport: Transport): this;
|
|
16
|
+
withConfig(config: Partial<AnalyticsConfig>): this;
|
|
17
|
+
build(): Analytics;
|
|
18
|
+
}
|
|
19
|
+
export declare class Analytics implements IAnalytics {
|
|
20
|
+
private config;
|
|
21
|
+
private storage;
|
|
22
|
+
private transport;
|
|
23
|
+
private beaconTransport;
|
|
24
|
+
private plugins;
|
|
25
|
+
private logger;
|
|
26
|
+
private initialized;
|
|
27
|
+
private enabled;
|
|
28
|
+
private eventQueue;
|
|
29
|
+
private flushInterval?;
|
|
30
|
+
private sessionPlugin?;
|
|
31
|
+
private userPlugin?;
|
|
32
|
+
constructor(config: AnalyticsConfig, storage: StorageManager, transport: Transport, plugins: Plugin[]);
|
|
33
|
+
private addCorePlugins;
|
|
34
|
+
init(): void;
|
|
35
|
+
track<T extends EventData>(eventType: string, data?: T): Promise<void>;
|
|
36
|
+
trackPageView(data: PageViewEvent): Promise<void>;
|
|
37
|
+
trackClick(data: ClickEvent): Promise<void>;
|
|
38
|
+
trackError(data: ErrorEvent): Promise<void>;
|
|
39
|
+
identify(user: User): Promise<void>;
|
|
40
|
+
getSessionId(): string | null;
|
|
41
|
+
getUserId(): string | null;
|
|
42
|
+
private queueEvent;
|
|
43
|
+
private sendEvent;
|
|
44
|
+
flush(): Promise<void>;
|
|
45
|
+
private handleBeforeUnload;
|
|
46
|
+
private getEndpoint;
|
|
47
|
+
destroy(): void;
|
|
48
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
import { ConfigurationError, InitializationError } from "./errors";
|
|
3
|
+
import { HybridStorage } from "../storage/hybrid-storage";
|
|
4
|
+
import { MemoryStorage } from "../storage/memory-storage";
|
|
5
|
+
import { FetchTransport } from "../transport/fetch-transport";
|
|
6
|
+
import { BeaconTransport } from "../transport/beacon-transport";
|
|
7
|
+
import { SessionPlugin } from "../plugins/enrichment/session";
|
|
8
|
+
import { UserPlugin } from "../plugins/enrichment/user";
|
|
9
|
+
import { validateConfig, sanitizeEventData } from "../utils/validation";
|
|
10
|
+
import { createLogger } from "../utils/logging";
|
|
11
|
+
import { getEnvironmentType, isDoNotTrackEnabled, getTimestamp, deepMerge, } from "../utils/helpers";
|
|
12
|
+
export class AnalyticsBuilder {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.config = {};
|
|
15
|
+
this.plugins = [];
|
|
16
|
+
}
|
|
17
|
+
withApiKey(apiKey) {
|
|
18
|
+
this.config.apiKey = apiKey;
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
withEndpoint(endpoint) {
|
|
22
|
+
this.config.endpoint = endpoint;
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
withHostProjectName(name) {
|
|
26
|
+
this.config.hostProjectName = name;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
withLogLevel(level) {
|
|
30
|
+
this.config.logLevel = level;
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
withSubmissionStrategy(strategy) {
|
|
34
|
+
this.config.submissionStrategy = strategy;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
withSamplingRate(rate) {
|
|
38
|
+
if (rate < 0 || rate > 1) {
|
|
39
|
+
throw new ConfigurationError("Sampling rate must be between 0 and 1");
|
|
40
|
+
}
|
|
41
|
+
this.config.samplingRate = rate;
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
withPlugin(plugin) {
|
|
45
|
+
this.plugins.push(plugin);
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
withStorage(storage) {
|
|
49
|
+
this.storage = storage;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
withTransport(transport) {
|
|
53
|
+
this.transport = transport;
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
withConfig(config) {
|
|
57
|
+
this.config = deepMerge(this.config, config);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
build() {
|
|
61
|
+
const validatedConfig = validateConfig(this.config);
|
|
62
|
+
const finalConfig = {
|
|
63
|
+
submissionStrategy: "ONEVENT",
|
|
64
|
+
logLevel: "info",
|
|
65
|
+
samplingRate: 1,
|
|
66
|
+
enableLocation: false,
|
|
67
|
+
enableAutoTrack: true,
|
|
68
|
+
respectDoNotTrack: true,
|
|
69
|
+
batchSize: 100,
|
|
70
|
+
flushInterval: 15000,
|
|
71
|
+
maxRetries: 3,
|
|
72
|
+
retryDelay: 1000,
|
|
73
|
+
showConsentPopup: false,
|
|
74
|
+
maxQueueSize: 1000,
|
|
75
|
+
...validatedConfig,
|
|
76
|
+
};
|
|
77
|
+
if (!finalConfig.apiKey && !finalConfig.endpoint) {
|
|
78
|
+
throw new ConfigurationError("Either apiKey or endpoint must be provided");
|
|
79
|
+
}
|
|
80
|
+
const storage = this.storage ||
|
|
81
|
+
(getEnvironmentType() === "node"
|
|
82
|
+
? new MemoryStorage()
|
|
83
|
+
: new HybridStorage());
|
|
84
|
+
const transport = this.transport || new FetchTransport({
|
|
85
|
+
apiKey: finalConfig.apiKey,
|
|
86
|
+
maxRetries: finalConfig.maxRetries,
|
|
87
|
+
retryDelay: finalConfig.retryDelay,
|
|
88
|
+
});
|
|
89
|
+
return new Analytics(finalConfig, storage, transport, this.plugins);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export class Analytics {
|
|
93
|
+
constructor(config, storage, transport, plugins) {
|
|
94
|
+
this.plugins = [];
|
|
95
|
+
this.initialized = false;
|
|
96
|
+
this.enabled = true;
|
|
97
|
+
this.eventQueue = [];
|
|
98
|
+
this.config = config;
|
|
99
|
+
this.storage = storage;
|
|
100
|
+
this.transport = transport;
|
|
101
|
+
this.beaconTransport =
|
|
102
|
+
getEnvironmentType() === "browser"
|
|
103
|
+
? new BeaconTransport({ apiKey: config.apiKey })
|
|
104
|
+
: null;
|
|
105
|
+
this.plugins = plugins;
|
|
106
|
+
this.logger = createLogger(config.logLevel || "info");
|
|
107
|
+
this.addCorePlugins();
|
|
108
|
+
}
|
|
109
|
+
addCorePlugins() {
|
|
110
|
+
const hasSessionPlugin = this.plugins.some((p) => p.name === "SessionPlugin");
|
|
111
|
+
if (!hasSessionPlugin) {
|
|
112
|
+
this.sessionPlugin = new SessionPlugin();
|
|
113
|
+
this.plugins.push(this.sessionPlugin);
|
|
114
|
+
}
|
|
115
|
+
const hasUserPlugin = this.plugins.some((p) => p.name === "UserPlugin");
|
|
116
|
+
if (!hasUserPlugin) {
|
|
117
|
+
this.userPlugin = new UserPlugin();
|
|
118
|
+
this.plugins.push(this.userPlugin);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
init() {
|
|
122
|
+
if (this.initialized) {
|
|
123
|
+
throw new InitializationError("Analytics already initialized");
|
|
124
|
+
}
|
|
125
|
+
if (this.config.respectDoNotTrack && isDoNotTrackEnabled()) {
|
|
126
|
+
this.logger.warn("Do Not Track is enabled, analytics will be disabled");
|
|
127
|
+
this.enabled = false;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const context = {
|
|
131
|
+
config: this.config,
|
|
132
|
+
storage: this.storage,
|
|
133
|
+
transport: this.transport,
|
|
134
|
+
track: this.track.bind(this),
|
|
135
|
+
getSessionId: this.getSessionId.bind(this),
|
|
136
|
+
getUserId: this.getUserId.bind(this),
|
|
137
|
+
};
|
|
138
|
+
for (const plugin of this.plugins) {
|
|
139
|
+
try {
|
|
140
|
+
this.logger.debug(`Initializing plugin: ${plugin.name}`);
|
|
141
|
+
plugin.init(context);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
this.logger.error(`Failed to initialize plugin ${plugin.name}:`, error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (this.config.submissionStrategy === "DEFER") {
|
|
148
|
+
this.flushInterval = setInterval(() => {
|
|
149
|
+
this.flush();
|
|
150
|
+
}, this.config.flushInterval);
|
|
151
|
+
}
|
|
152
|
+
if (getEnvironmentType() === "browser") {
|
|
153
|
+
window.addEventListener("beforeunload", () => {
|
|
154
|
+
this.handleBeforeUnload();
|
|
155
|
+
});
|
|
156
|
+
document.addEventListener("visibilitychange", () => {
|
|
157
|
+
if (document.visibilityState === "hidden") {
|
|
158
|
+
this.handleBeforeUnload();
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
this.initialized = true;
|
|
163
|
+
this.logger.info("Analytics initialized");
|
|
164
|
+
this.track("ANALYTICS_INITIALIZED");
|
|
165
|
+
}
|
|
166
|
+
async track(eventType, data) {
|
|
167
|
+
if (!this.initialized) {
|
|
168
|
+
throw new InitializationError("Analytics not initialized. Call init() first");
|
|
169
|
+
}
|
|
170
|
+
if (!this.enabled) {
|
|
171
|
+
this.logger.debug("Analytics disabled, event not tracked");
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (Math.random() > (this.config.samplingRate ?? 1)) {
|
|
175
|
+
this.logger.debug("Event sampled out");
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const event = {
|
|
179
|
+
eventType,
|
|
180
|
+
timestamp: getTimestamp(),
|
|
181
|
+
eventId: uuidv4(),
|
|
182
|
+
data: sanitizeEventData(data || {}),
|
|
183
|
+
};
|
|
184
|
+
for (const plugin of this.plugins) {
|
|
185
|
+
if (plugin.processEvent) {
|
|
186
|
+
try {
|
|
187
|
+
await plugin.processEvent(event);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
this.logger.error(`Plugin ${plugin.name} failed to process event:`, error);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (this.config.submissionStrategy === "DEFER") {
|
|
195
|
+
this.queueEvent(event);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
await this.sendEvent(event);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async trackPageView(data) {
|
|
202
|
+
return this.track("PAGE_VIEW", data);
|
|
203
|
+
}
|
|
204
|
+
async trackClick(data) {
|
|
205
|
+
return this.track("CLICK", data);
|
|
206
|
+
}
|
|
207
|
+
async trackError(data) {
|
|
208
|
+
return this.track("ERROR", data);
|
|
209
|
+
}
|
|
210
|
+
async identify(user) {
|
|
211
|
+
if (!this.initialized) {
|
|
212
|
+
throw new InitializationError("Analytics not initialized. Call init() first");
|
|
213
|
+
}
|
|
214
|
+
if (this.userPlugin) {
|
|
215
|
+
await this.userPlugin.identify(user);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
this.logger.error("User plugin not available");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
getSessionId() {
|
|
222
|
+
if (this.sessionPlugin) {
|
|
223
|
+
return this.sessionPlugin.getSessionId();
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
getUserId() {
|
|
228
|
+
if (this.userPlugin) {
|
|
229
|
+
return this.userPlugin.getUserId();
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
queueEvent(event) {
|
|
234
|
+
this.eventQueue.push({
|
|
235
|
+
event,
|
|
236
|
+
retries: 0,
|
|
237
|
+
timestamp: new Date(),
|
|
238
|
+
});
|
|
239
|
+
const maxQueueSize = this.config.maxQueueSize ?? 1000;
|
|
240
|
+
if (this.eventQueue.length > maxQueueSize) {
|
|
241
|
+
this.logger.warn(`Queue size exceeded ${maxQueueSize}, dropping oldest events`);
|
|
242
|
+
this.eventQueue = this.eventQueue.slice(-maxQueueSize);
|
|
243
|
+
}
|
|
244
|
+
if (this.eventQueue.length >= (this.config.batchSize ?? 100)) {
|
|
245
|
+
this.flush();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async sendEvent(event) {
|
|
249
|
+
const endpoint = this.getEndpoint();
|
|
250
|
+
try {
|
|
251
|
+
await this.transport.send(endpoint, event);
|
|
252
|
+
this.logger.debug("Event sent successfully:", event.eventType);
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
this.logger.error("Failed to send event:", error);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async flush() {
|
|
259
|
+
if (this.eventQueue.length === 0) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const events = this.eventQueue.map((qe) => qe.event);
|
|
263
|
+
const endpoint = this.getEndpoint();
|
|
264
|
+
try {
|
|
265
|
+
await this.transport.sendBatch(endpoint, events);
|
|
266
|
+
this.logger.debug(`Flushed ${events.length} events`);
|
|
267
|
+
this.eventQueue = [];
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
this.logger.error("Failed to flush events:", error);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
handleBeforeUnload() {
|
|
274
|
+
if (!this.beaconTransport || this.eventQueue.length === 0) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const events = this.eventQueue.map((qe) => qe.event);
|
|
278
|
+
const endpoint = this.getEndpoint();
|
|
279
|
+
try {
|
|
280
|
+
this.beaconTransport.sendBatch(endpoint, events);
|
|
281
|
+
this.logger.debug("Events sent via beacon on unload");
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
this.logger.error("Failed to send events on unload:", error);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
getEndpoint() {
|
|
288
|
+
if (this.config.endpoint) {
|
|
289
|
+
return this.config.endpoint;
|
|
290
|
+
}
|
|
291
|
+
return "https://telemetry.armco.dev/events/add";
|
|
292
|
+
}
|
|
293
|
+
destroy() {
|
|
294
|
+
this.flush();
|
|
295
|
+
if (this.flushInterval) {
|
|
296
|
+
clearInterval(this.flushInterval);
|
|
297
|
+
}
|
|
298
|
+
for (const plugin of this.plugins) {
|
|
299
|
+
if (plugin.destroy) {
|
|
300
|
+
try {
|
|
301
|
+
plugin.destroy();
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
this.logger.error(`Failed to destroy plugin ${plugin.name}:`, error);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
this.initialized = false;
|
|
309
|
+
this.logger.info("Analytics destroyed");
|
|
310
|
+
}
|
|
311
|
+
}
|
package/core/errors.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare class AnalyticsError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare class ConfigurationError extends AnalyticsError {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class ValidationError extends AnalyticsError {
|
|
8
|
+
readonly field?: string;
|
|
9
|
+
readonly value?: unknown;
|
|
10
|
+
constructor(message: string, field?: string, value?: unknown);
|
|
11
|
+
}
|
|
12
|
+
export declare class NetworkError extends AnalyticsError {
|
|
13
|
+
readonly statusCode?: number;
|
|
14
|
+
readonly endpoint?: string;
|
|
15
|
+
constructor(message: string, statusCode?: number, endpoint?: string);
|
|
16
|
+
}
|
|
17
|
+
export declare class StorageError extends AnalyticsError {
|
|
18
|
+
constructor(message: string);
|
|
19
|
+
}
|
|
20
|
+
export declare class PluginError extends AnalyticsError {
|
|
21
|
+
readonly pluginName?: string;
|
|
22
|
+
constructor(message: string, pluginName?: string);
|
|
23
|
+
}
|
|
24
|
+
export declare class InitializationError extends AnalyticsError {
|
|
25
|
+
constructor(message: string);
|
|
26
|
+
}
|
package/core/errors.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export class AnalyticsError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "AnalyticsError";
|
|
5
|
+
Object.setPrototypeOf(this, AnalyticsError.prototype);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class ConfigurationError extends AnalyticsError {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "ConfigurationError";
|
|
12
|
+
Object.setPrototypeOf(this, ConfigurationError.prototype);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class ValidationError extends AnalyticsError {
|
|
16
|
+
constructor(message, field, value) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "ValidationError";
|
|
19
|
+
this.field = field;
|
|
20
|
+
this.value = value;
|
|
21
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class NetworkError extends AnalyticsError {
|
|
25
|
+
constructor(message, statusCode, endpoint) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "NetworkError";
|
|
28
|
+
this.statusCode = statusCode;
|
|
29
|
+
this.endpoint = endpoint;
|
|
30
|
+
Object.setPrototypeOf(this, NetworkError.prototype);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class StorageError extends AnalyticsError {
|
|
34
|
+
constructor(message) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = "StorageError";
|
|
37
|
+
Object.setPrototypeOf(this, StorageError.prototype);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class PluginError extends AnalyticsError {
|
|
41
|
+
constructor(message, pluginName) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "PluginError";
|
|
44
|
+
this.pluginName = pluginName;
|
|
45
|
+
Object.setPrototypeOf(this, PluginError.prototype);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export class InitializationError extends AnalyticsError {
|
|
49
|
+
constructor(message) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = "InitializationError";
|
|
52
|
+
Object.setPrototypeOf(this, InitializationError.prototype);
|
|
53
|
+
}
|
|
54
|
+
}
|
package/core/types.d.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export type Environment = "browser" | "node" | "unknown";
|
|
2
|
+
export type SubmissionStrategy = "ONEVENT" | "DEFER";
|
|
3
|
+
export type LogLevel = "debug" | "info" | "warn" | "error" | "none";
|
|
4
|
+
export interface EventData {
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface TrackingEvent<T extends EventData = EventData> {
|
|
8
|
+
eventType: string;
|
|
9
|
+
timestamp: Date;
|
|
10
|
+
eventId: string;
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
userId?: string;
|
|
13
|
+
data: T;
|
|
14
|
+
}
|
|
15
|
+
export interface PageViewEvent extends EventData {
|
|
16
|
+
pageName: string;
|
|
17
|
+
url: string;
|
|
18
|
+
referrer?: string;
|
|
19
|
+
title?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ClickEvent extends EventData {
|
|
22
|
+
elementId?: string;
|
|
23
|
+
elementType: string;
|
|
24
|
+
elementText?: string;
|
|
25
|
+
elementClasses?: string[];
|
|
26
|
+
elementPath?: string;
|
|
27
|
+
href?: string;
|
|
28
|
+
value?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface FormEvent extends EventData {
|
|
31
|
+
formId?: string;
|
|
32
|
+
formName?: string;
|
|
33
|
+
formAction?: string;
|
|
34
|
+
formMethod?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface ErrorEvent extends EventData {
|
|
37
|
+
errorMessage: string;
|
|
38
|
+
errorStack?: string;
|
|
39
|
+
errorType?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface User {
|
|
42
|
+
email: string;
|
|
43
|
+
id?: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
[key: string]: unknown;
|
|
46
|
+
}
|
|
47
|
+
export interface LocationData {
|
|
48
|
+
region?: string;
|
|
49
|
+
timezone?: string;
|
|
50
|
+
latitude?: number;
|
|
51
|
+
longitude?: number;
|
|
52
|
+
city?: string;
|
|
53
|
+
country?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface AnalyticsConfig {
|
|
56
|
+
apiKey?: string;
|
|
57
|
+
endpoint?: string;
|
|
58
|
+
updateEndpoint?: string;
|
|
59
|
+
hostProjectName?: string;
|
|
60
|
+
trackEvents?: string[];
|
|
61
|
+
submissionStrategy?: SubmissionStrategy;
|
|
62
|
+
showConsentPopup?: boolean;
|
|
63
|
+
logLevel?: LogLevel;
|
|
64
|
+
samplingRate?: number;
|
|
65
|
+
enableLocation?: boolean;
|
|
66
|
+
enableAutoTrack?: boolean;
|
|
67
|
+
respectDoNotTrack?: boolean;
|
|
68
|
+
batchSize?: number;
|
|
69
|
+
flushInterval?: number;
|
|
70
|
+
maxRetries?: number;
|
|
71
|
+
retryDelay?: number;
|
|
72
|
+
maxQueueSize?: number;
|
|
73
|
+
}
|
|
74
|
+
export interface ValidationResult {
|
|
75
|
+
valid: boolean;
|
|
76
|
+
errors: string[];
|
|
77
|
+
}
|
|
78
|
+
export interface Plugin {
|
|
79
|
+
name: string;
|
|
80
|
+
version?: string;
|
|
81
|
+
init(context: PluginContext): void | Promise<void>;
|
|
82
|
+
processEvent?(event: TrackingEvent): void | Promise<void>;
|
|
83
|
+
destroy?(): void | Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
export interface PluginContext {
|
|
86
|
+
config: AnalyticsConfig;
|
|
87
|
+
storage: StorageManager;
|
|
88
|
+
transport: Transport;
|
|
89
|
+
track(eventType: string, data?: EventData): void;
|
|
90
|
+
getSessionId(): string | null;
|
|
91
|
+
getUserId(): string | null;
|
|
92
|
+
}
|
|
93
|
+
export interface StorageManager {
|
|
94
|
+
getItem(key: string): string | null;
|
|
95
|
+
setItem(key: string, value: string, options?: StorageOptions): void;
|
|
96
|
+
removeItem(key: string): void;
|
|
97
|
+
clear(): void;
|
|
98
|
+
}
|
|
99
|
+
export interface StorageOptions {
|
|
100
|
+
expires?: Date;
|
|
101
|
+
secure?: boolean;
|
|
102
|
+
sameSite?: "strict" | "lax" | "none";
|
|
103
|
+
}
|
|
104
|
+
export interface Transport {
|
|
105
|
+
send(endpoint: string, event: TrackingEvent): Promise<TransportResponse>;
|
|
106
|
+
sendBatch(endpoint: string, events: TrackingEvent[]): Promise<TransportResponse>;
|
|
107
|
+
update?(endpoint: string, payload: {
|
|
108
|
+
email: string;
|
|
109
|
+
anonymousId: string;
|
|
110
|
+
}): Promise<TransportResponse>;
|
|
111
|
+
}
|
|
112
|
+
export interface TransportResponse {
|
|
113
|
+
success: boolean;
|
|
114
|
+
statusCode?: number;
|
|
115
|
+
error?: string;
|
|
116
|
+
}
|
|
117
|
+
export interface QueuedEvent {
|
|
118
|
+
event: TrackingEvent;
|
|
119
|
+
retries: number;
|
|
120
|
+
timestamp: Date;
|
|
121
|
+
}
|
|
122
|
+
export interface IAnalytics {
|
|
123
|
+
init(): void;
|
|
124
|
+
track<T extends EventData>(eventType: string, data?: T): Promise<void>;
|
|
125
|
+
trackPageView(data: PageViewEvent): Promise<void>;
|
|
126
|
+
trackClick(data: ClickEvent): Promise<void>;
|
|
127
|
+
trackError(data: ErrorEvent): Promise<void>;
|
|
128
|
+
identify(user: User): Promise<void>;
|
|
129
|
+
getSessionId(): string | null;
|
|
130
|
+
getUserId(): string | null;
|
|
131
|
+
flush(): Promise<void>;
|
|
132
|
+
destroy(): void;
|
|
133
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
1
|
+
export { Analytics, AnalyticsBuilder } from "./core/analytics";
|
|
2
|
+
export type { AnalyticsConfig, IAnalytics, EventData, TrackingEvent, PageViewEvent, ClickEvent, FormEvent, ErrorEvent, User, Plugin, PluginContext, StorageManager, StorageOptions, Transport, TransportResponse, LogLevel, SubmissionStrategy, Environment, } from "./core/types";
|
|
3
|
+
export { AnalyticsError, ConfigurationError, ValidationError, NetworkError, StorageError, PluginError, InitializationError, } from "./core/errors";
|
|
4
|
+
export { CookieStorage } from "./storage/cookie-storage";
|
|
5
|
+
export { LocalStorage } from "./storage/local-storage";
|
|
6
|
+
export { HybridStorage } from "./storage/hybrid-storage";
|
|
7
|
+
export { MemoryStorage } from "./storage/memory-storage";
|
|
8
|
+
export { FetchTransport } from "./transport/fetch-transport";
|
|
9
|
+
export { BeaconTransport } from "./transport/beacon-transport";
|
|
10
|
+
export { SessionPlugin } from "./plugins/enrichment/session";
|
|
11
|
+
export { UserPlugin } from "./plugins/enrichment/user";
|
|
12
|
+
export { ClickTrackingPlugin } from "./plugins/auto-track/click";
|
|
13
|
+
export { PageTrackingPlugin } from "./plugins/auto-track/page";
|
|
14
|
+
export { FormTrackingPlugin } from "./plugins/auto-track/form";
|
|
15
|
+
export { ErrorTrackingPlugin } from "./plugins/auto-track/error";
|
|
16
|
+
export { HTTPRequestTrackingPlugin } from "./plugins/node/http-request-tracking";
|
|
17
|
+
export type { HTTPRequestEvent, HTTPRequestMetadata } from "./plugins/node/http-request-tracking";
|
|
18
|
+
export { validateConfig, validateUser, validatePageView, validateClickEvent, validateFormEvent, validateErrorEvent, sanitizeEventData, } from "./utils/validation";
|
|
19
|
+
export { Logger, getLogger, createLogger } from "./utils/logging";
|
|
20
|
+
export { generateId, getEnvironmentType, getEnvironment, isDoNotTrackEnabled, isBrowser, areCookiesAvailable, isLocalStorageAvailable, debounce, throttle, deepClone, deepMerge, } from "./utils/helpers";
|
|
21
|
+
export { loadConfigFromFile, loadConfig } from "./utils/config-loader";
|
|
22
|
+
import { AnalyticsBuilder as Builder } from "./core/analytics";
|
|
23
|
+
export declare function createAnalytics(): Builder;
|
|
24
|
+
export default Builder;
|
package/index.js
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
export {
|
|
1
|
+
export { Analytics, AnalyticsBuilder } from "./core/analytics";
|
|
2
|
+
export { AnalyticsError, ConfigurationError, ValidationError, NetworkError, StorageError, PluginError, InitializationError, } from "./core/errors";
|
|
3
|
+
export { CookieStorage } from "./storage/cookie-storage";
|
|
4
|
+
export { LocalStorage } from "./storage/local-storage";
|
|
5
|
+
export { HybridStorage } from "./storage/hybrid-storage";
|
|
6
|
+
export { MemoryStorage } from "./storage/memory-storage";
|
|
7
|
+
export { FetchTransport } from "./transport/fetch-transport";
|
|
8
|
+
export { BeaconTransport } from "./transport/beacon-transport";
|
|
9
|
+
export { SessionPlugin } from "./plugins/enrichment/session";
|
|
10
|
+
export { UserPlugin } from "./plugins/enrichment/user";
|
|
11
|
+
export { ClickTrackingPlugin } from "./plugins/auto-track/click";
|
|
12
|
+
export { PageTrackingPlugin } from "./plugins/auto-track/page";
|
|
13
|
+
export { FormTrackingPlugin } from "./plugins/auto-track/form";
|
|
14
|
+
export { ErrorTrackingPlugin } from "./plugins/auto-track/error";
|
|
15
|
+
export { HTTPRequestTrackingPlugin } from "./plugins/node/http-request-tracking";
|
|
16
|
+
export { validateConfig, validateUser, validatePageView, validateClickEvent, validateFormEvent, validateErrorEvent, sanitizeEventData, } from "./utils/validation";
|
|
17
|
+
export { Logger, getLogger, createLogger } from "./utils/logging";
|
|
18
|
+
export { generateId, getEnvironmentType, getEnvironment, isDoNotTrackEnabled, isBrowser, areCookiesAvailable, isLocalStorageAvailable, debounce, throttle, deepClone, deepMerge, } from "./utils/helpers";
|
|
19
|
+
export { loadConfigFromFile, loadConfig } from "./utils/config-loader";
|
|
20
|
+
import { AnalyticsBuilder as Builder } from "./core/analytics";
|
|
21
|
+
export function createAnalytics() {
|
|
22
|
+
return new Builder();
|
|
23
|
+
}
|
|
24
|
+
export default Builder;
|