@mostly-good-metrics/javascript 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.
Files changed (54) hide show
  1. package/README.md +319 -0
  2. package/dist/cjs/client.js +416 -0
  3. package/dist/cjs/client.js.map +1 -0
  4. package/dist/cjs/index.js +65 -0
  5. package/dist/cjs/index.js.map +1 -0
  6. package/dist/cjs/logger.js +64 -0
  7. package/dist/cjs/logger.js.map +1 -0
  8. package/dist/cjs/network.js +192 -0
  9. package/dist/cjs/network.js.map +1 -0
  10. package/dist/cjs/storage.js +227 -0
  11. package/dist/cjs/storage.js.map +1 -0
  12. package/dist/cjs/types.js +70 -0
  13. package/dist/cjs/types.js.map +1 -0
  14. package/dist/cjs/utils.js +249 -0
  15. package/dist/cjs/utils.js.map +1 -0
  16. package/dist/esm/client.js +412 -0
  17. package/dist/esm/client.js.map +1 -0
  18. package/dist/esm/index.js +40 -0
  19. package/dist/esm/index.js.map +1 -0
  20. package/dist/esm/logger.js +55 -0
  21. package/dist/esm/logger.js.map +1 -0
  22. package/dist/esm/network.js +187 -0
  23. package/dist/esm/network.js.map +1 -0
  24. package/dist/esm/storage.js +221 -0
  25. package/dist/esm/storage.js.map +1 -0
  26. package/dist/esm/types.js +66 -0
  27. package/dist/esm/types.js.map +1 -0
  28. package/dist/esm/utils.js +236 -0
  29. package/dist/esm/utils.js.map +1 -0
  30. package/dist/types/client.d.ts +126 -0
  31. package/dist/types/client.d.ts.map +1 -0
  32. package/dist/types/index.d.ts +34 -0
  33. package/dist/types/index.d.ts.map +1 -0
  34. package/dist/types/logger.d.ts +37 -0
  35. package/dist/types/logger.d.ts.map +1 -0
  36. package/dist/types/network.d.ts +28 -0
  37. package/dist/types/network.d.ts.map +1 -0
  38. package/dist/types/storage.d.ts +76 -0
  39. package/dist/types/storage.d.ts.map +1 -0
  40. package/dist/types/types.d.ts +279 -0
  41. package/dist/types/types.d.ts.map +1 -0
  42. package/dist/types/utils.d.ts +48 -0
  43. package/dist/types/utils.d.ts.map +1 -0
  44. package/package.json +68 -0
  45. package/src/client.test.ts +346 -0
  46. package/src/client.ts +510 -0
  47. package/src/index.ts +79 -0
  48. package/src/logger.ts +63 -0
  49. package/src/network.ts +230 -0
  50. package/src/storage.test.ts +175 -0
  51. package/src/storage.ts +249 -0
  52. package/src/types.ts +347 -0
  53. package/src/utils.test.ts +239 -0
  54. package/src/utils.ts +315 -0
@@ -0,0 +1,236 @@
1
+ import { logger } from './logger';
2
+ import { Constraints, DefaultConfiguration, EVENT_NAME_REGEX, MGMError, } from './types';
3
+ /**
4
+ * Generate a UUID v4 string.
5
+ */
6
+ export function generateUUID() {
7
+ // Use crypto.randomUUID if available (modern browsers and Node.js 19+)
8
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
9
+ return crypto.randomUUID();
10
+ }
11
+ // Fallback implementation
12
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
13
+ const r = (Math.random() * 16) | 0;
14
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
15
+ return v.toString(16);
16
+ });
17
+ }
18
+ /**
19
+ * Get the current timestamp in ISO8601 format.
20
+ */
21
+ export function getISOTimestamp() {
22
+ return new Date().toISOString();
23
+ }
24
+ /**
25
+ * Validate an event name.
26
+ * Must match pattern: ^$?[a-zA-Z][a-zA-Z0-9_]*$
27
+ * Max 255 characters.
28
+ */
29
+ export function isValidEventName(name) {
30
+ if (!name || name.length > Constraints.MAX_EVENT_NAME_LENGTH) {
31
+ return false;
32
+ }
33
+ return EVENT_NAME_REGEX.test(name);
34
+ }
35
+ /**
36
+ * Validate an event name and throw if invalid.
37
+ */
38
+ export function validateEventName(name) {
39
+ if (!name) {
40
+ throw new MGMError('INVALID_EVENT_NAME', 'Event name is required');
41
+ }
42
+ if (name.length > Constraints.MAX_EVENT_NAME_LENGTH) {
43
+ throw new MGMError('INVALID_EVENT_NAME', `Event name must be ${Constraints.MAX_EVENT_NAME_LENGTH} characters or less`);
44
+ }
45
+ if (!EVENT_NAME_REGEX.test(name)) {
46
+ throw new MGMError('INVALID_EVENT_NAME', 'Event name must start with a letter (or $ for system events) and contain only alphanumeric characters and underscores');
47
+ }
48
+ }
49
+ /**
50
+ * Sanitize event properties by truncating strings and limiting depth.
51
+ */
52
+ export function sanitizeProperties(properties, maxDepth = Constraints.MAX_PROPERTY_DEPTH) {
53
+ if (!properties || typeof properties !== 'object') {
54
+ return undefined;
55
+ }
56
+ const sanitized = sanitizeValue(properties, 0, maxDepth);
57
+ if (typeof sanitized === 'object' && sanitized !== null && !Array.isArray(sanitized)) {
58
+ return sanitized;
59
+ }
60
+ return undefined;
61
+ }
62
+ /**
63
+ * Recursively sanitize a property value.
64
+ */
65
+ function sanitizeValue(value, depth, maxDepth) {
66
+ // Null is valid
67
+ if (value === null) {
68
+ return null;
69
+ }
70
+ // Primitives
71
+ if (typeof value === 'boolean' || typeof value === 'number') {
72
+ return value;
73
+ }
74
+ // Strings - truncate if needed
75
+ if (typeof value === 'string') {
76
+ if (value.length > Constraints.MAX_STRING_PROPERTY_LENGTH) {
77
+ logger.debug(`Truncating string property from ${value.length} to ${Constraints.MAX_STRING_PROPERTY_LENGTH} characters`);
78
+ return value.substring(0, Constraints.MAX_STRING_PROPERTY_LENGTH);
79
+ }
80
+ return value;
81
+ }
82
+ // Arrays
83
+ if (Array.isArray(value)) {
84
+ if (depth >= maxDepth) {
85
+ logger.debug(`Max property depth reached, omitting nested array`);
86
+ return null;
87
+ }
88
+ return value.map((item) => sanitizeValue(item, depth + 1, maxDepth));
89
+ }
90
+ // Objects
91
+ if (typeof value === 'object') {
92
+ if (depth >= maxDepth) {
93
+ logger.debug(`Max property depth reached, omitting nested object`);
94
+ return null;
95
+ }
96
+ const result = {};
97
+ for (const [key, val] of Object.entries(value)) {
98
+ result[key] = sanitizeValue(val, depth + 1, maxDepth);
99
+ }
100
+ return result;
101
+ }
102
+ // Unknown type - convert to null
103
+ return null;
104
+ }
105
+ /**
106
+ * Resolve configuration with defaults.
107
+ */
108
+ export function resolveConfiguration(config) {
109
+ const maxBatchSize = Math.min(Math.max(config.maxBatchSize ?? DefaultConfiguration.maxBatchSize, Constraints.MIN_BATCH_SIZE), Constraints.MAX_BATCH_SIZE);
110
+ const flushInterval = Math.max(config.flushInterval ?? DefaultConfiguration.flushInterval, Constraints.MIN_FLUSH_INTERVAL);
111
+ const maxStoredEvents = Math.max(config.maxStoredEvents ?? DefaultConfiguration.maxStoredEvents, Constraints.MIN_STORED_EVENTS);
112
+ return {
113
+ apiKey: config.apiKey,
114
+ baseURL: config.baseURL ?? DefaultConfiguration.baseURL,
115
+ environment: config.environment ?? DefaultConfiguration.environment,
116
+ maxBatchSize,
117
+ flushInterval,
118
+ maxStoredEvents,
119
+ enableDebugLogging: config.enableDebugLogging ?? DefaultConfiguration.enableDebugLogging,
120
+ trackAppLifecycleEvents: config.trackAppLifecycleEvents ?? DefaultConfiguration.trackAppLifecycleEvents,
121
+ bundleId: config.bundleId ?? detectBundleId(),
122
+ appVersion: config.appVersion ?? '',
123
+ osVersion: config.osVersion ?? '',
124
+ storage: config.storage,
125
+ networkClient: config.networkClient,
126
+ };
127
+ }
128
+ /**
129
+ * Detect the bundle ID from the current environment.
130
+ */
131
+ function detectBundleId() {
132
+ // In browser, use the hostname
133
+ if (typeof window !== 'undefined' && window.location) {
134
+ return window.location.hostname;
135
+ }
136
+ // In Node.js, could use package.json name but that requires fs access
137
+ return '';
138
+ }
139
+ /**
140
+ * Detect the current platform.
141
+ */
142
+ export function detectPlatform() {
143
+ // Check for React Native / Expo
144
+ if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
145
+ // Could check for Expo-specific globals here
146
+ return 'react-native';
147
+ }
148
+ // Check for Node.js
149
+ if (typeof process !== 'undefined' && process.versions?.node) {
150
+ return 'node';
151
+ }
152
+ // Default to web for browser environments
153
+ return 'web';
154
+ }
155
+ /**
156
+ * Detect the device type from user agent.
157
+ */
158
+ export function detectDeviceType() {
159
+ if (typeof navigator === 'undefined' || !navigator.userAgent) {
160
+ return 'unknown';
161
+ }
162
+ const ua = navigator.userAgent.toLowerCase();
163
+ // Check for specific device types
164
+ if (/tablet|ipad|playbook|silk/i.test(ua)) {
165
+ return 'tablet';
166
+ }
167
+ if (/mobile|iphone|ipod|android.*mobile|blackberry|opera mini|opera mobi/i.test(ua)) {
168
+ return 'phone';
169
+ }
170
+ if (/smart-tv|smarttv|googletv|appletv|hbbtv|pov_tv|netcast.tv/i.test(ua)) {
171
+ return 'tv';
172
+ }
173
+ // Default to desktop for other browsers
174
+ if (typeof window !== 'undefined') {
175
+ return 'desktop';
176
+ }
177
+ return 'unknown';
178
+ }
179
+ /**
180
+ * Get the OS version string.
181
+ */
182
+ export function getOSVersion() {
183
+ if (typeof navigator === 'undefined' || !navigator.userAgent) {
184
+ return '';
185
+ }
186
+ const ua = navigator.userAgent;
187
+ // Try to extract OS version from user agent
188
+ const patterns = [
189
+ [/Windows NT ([\d.]+)/i, 'Windows'],
190
+ [/Mac OS X ([\d_.]+)/i, 'macOS'],
191
+ [/iPhone OS ([\d_]+)/i, 'iOS'],
192
+ [/iPad.*OS ([\d_]+)/i, 'iPadOS'],
193
+ [/Android ([\d.]+)/i, 'Android'],
194
+ [/Linux/i, 'Linux'],
195
+ ];
196
+ for (const [pattern, osName] of patterns) {
197
+ const match = ua.match(pattern);
198
+ if (match) {
199
+ const version = match[1]?.replace(/_/g, '.') ?? '';
200
+ return version ? `${osName} ${version}` : osName;
201
+ }
202
+ }
203
+ return '';
204
+ }
205
+ /**
206
+ * Get the browser/device model.
207
+ */
208
+ export function getDeviceModel() {
209
+ if (typeof navigator === 'undefined' || !navigator.userAgent) {
210
+ return '';
211
+ }
212
+ const ua = navigator.userAgent;
213
+ // Try to extract browser name and version
214
+ const patterns = [
215
+ [/Chrome\/([\d.]+)/i, 'Chrome'],
216
+ [/Firefox\/([\d.]+)/i, 'Firefox'],
217
+ [/Safari\/([\d.]+)/i, 'Safari'],
218
+ [/Edge\/([\d.]+)/i, 'Edge'],
219
+ [/MSIE ([\d.]+)/i, 'IE'],
220
+ [/Trident.*rv:([\d.]+)/i, 'IE'],
221
+ ];
222
+ for (const [pattern, browserName] of patterns) {
223
+ const match = ua.match(pattern);
224
+ if (match) {
225
+ return `${browserName} ${match[1]}`;
226
+ }
227
+ }
228
+ return '';
229
+ }
230
+ /**
231
+ * Delay execution for a specified number of milliseconds.
232
+ */
233
+ export function delay(ms) {
234
+ return new Promise((resolve) => setTimeout(resolve, ms));
235
+ }
236
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import { EventProperties, MGMConfiguration, ResolvedConfiguration } from './types';
2
+ /**
3
+ * Main client for MostlyGoodMetrics.
4
+ * Use the static `configure` method to initialize, then use static methods or the instance.
5
+ */
6
+ export declare class MostlyGoodMetrics {
7
+ private static instance;
8
+ private config;
9
+ private storage;
10
+ private networkClient;
11
+ private flushTimer;
12
+ private isFlushingInternal;
13
+ private sessionIdValue;
14
+ private lifecycleSetup;
15
+ /**
16
+ * Private constructor - use `configure` to create an instance.
17
+ */
18
+ private constructor();
19
+ /**
20
+ * Configure and initialize the SDK.
21
+ * Returns the singleton instance.
22
+ */
23
+ static configure(config: MGMConfiguration): MostlyGoodMetrics;
24
+ /**
25
+ * Get the shared instance, or null if not configured.
26
+ */
27
+ static get shared(): MostlyGoodMetrics | null;
28
+ /**
29
+ * Check if the SDK has been configured.
30
+ */
31
+ static get isConfigured(): boolean;
32
+ /**
33
+ * Reset the SDK (primarily for testing).
34
+ */
35
+ static reset(): void;
36
+ /**
37
+ * Track an event with the given name and optional properties.
38
+ */
39
+ static track(name: string, properties?: EventProperties): void;
40
+ /**
41
+ * Identify the current user.
42
+ */
43
+ static identify(userId: string): void;
44
+ /**
45
+ * Reset user identity.
46
+ */
47
+ static resetIdentity(): void;
48
+ /**
49
+ * Flush pending events to the server.
50
+ */
51
+ static flush(): Promise<void>;
52
+ /**
53
+ * Start a new session.
54
+ */
55
+ static startNewSession(): void;
56
+ /**
57
+ * Clear all pending events.
58
+ */
59
+ static clearPendingEvents(): Promise<void>;
60
+ /**
61
+ * Get the count of pending events.
62
+ */
63
+ static getPendingEventCount(): Promise<number>;
64
+ /**
65
+ * Get the current user ID.
66
+ */
67
+ get userId(): string | null;
68
+ /**
69
+ * Get the current session ID.
70
+ */
71
+ get sessionId(): string;
72
+ /**
73
+ * Check if a flush operation is in progress.
74
+ */
75
+ get isFlushing(): boolean;
76
+ /**
77
+ * Get the resolved configuration.
78
+ */
79
+ get configuration(): ResolvedConfiguration;
80
+ /**
81
+ * Track an event with the given name and optional properties.
82
+ */
83
+ track(name: string, properties?: EventProperties): void;
84
+ /**
85
+ * Identify the current user.
86
+ */
87
+ identify(userId: string): void;
88
+ /**
89
+ * Reset user identity.
90
+ */
91
+ resetIdentity(): void;
92
+ /**
93
+ * Start a new session.
94
+ */
95
+ startNewSession(): void;
96
+ /**
97
+ * Flush pending events to the server.
98
+ */
99
+ flush(): Promise<void>;
100
+ /**
101
+ * Clear all pending events.
102
+ */
103
+ clearPendingEvents(): Promise<void>;
104
+ /**
105
+ * Get the count of pending events.
106
+ */
107
+ getPendingEventCount(): Promise<number>;
108
+ /**
109
+ * Clean up resources (stop timers, etc.).
110
+ */
111
+ destroy(): void;
112
+ private checkBatchSize;
113
+ private performFlush;
114
+ private buildPayload;
115
+ private startFlushTimer;
116
+ private stopFlushTimer;
117
+ private setupLifecycleTracking;
118
+ private removeLifecycleListeners;
119
+ private trackInstallOrUpdate;
120
+ private trackAppOpened;
121
+ private handleVisibilityChange;
122
+ private handleBeforeUnload;
123
+ private handlePageHide;
124
+ private flushWithBeacon;
125
+ }
126
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,eAAe,EAGf,gBAAgB,EAIhB,qBAAqB,EAGtB,MAAM,SAAS,CAAC;AAgBjB;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAkC;IAEzD,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,cAAc,CAAS;IAE/B;;OAEG;IACH,OAAO;IAwBP;;;OAGG;IACH,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB;IAc7D;;OAEG;IACH,MAAM,KAAK,MAAM,IAAI,iBAAiB,GAAG,IAAI,CAE5C;IAED;;OAEG;IACH,MAAM,KAAK,YAAY,IAAI,OAAO,CAEjC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,IAAI,IAAI;IAWpB;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI;IAI9D;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIrC;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;IAI5B;;OAEG;IACH,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B;;OAEG;IACH,MAAM,CAAC,eAAe,IAAI,IAAI;IAI9B;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI1C;;OAEG;IACH,MAAM,CAAC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ9C;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,GAAG,IAAI,CAE1B;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,qBAAqB,CAEzC;IAMD;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI;IAwCvD;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAU9B;;OAEG;IACH,aAAa,IAAI,IAAI;IAKrB;;OAEG;IACH,eAAe,IAAI,IAAI;IAKvB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7C;;OAEG;IACH,OAAO,IAAI,IAAI;YAUD,cAAc;YAQd,YAAY;IA4C1B,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,sBAAsB;IA4B9B,OAAO,CAAC,wBAAwB;IAUhC,OAAO,CAAC,oBAAoB;IA4B5B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,sBAAsB,CAS5B;IAEF,OAAO,CAAC,kBAAkB,CAGxB;IAEF,OAAO,CAAC,cAAc,CAGpB;IAEF,OAAO,CAAC,eAAe;CAWxB"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * MostlyGoodMetrics JavaScript SDK
3
+ *
4
+ * A lightweight, framework-agnostic analytics library for web applications.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { MostlyGoodMetrics } from '@mostly-good-metrics/javascript';
9
+ *
10
+ * // Initialize the SDK
11
+ * MostlyGoodMetrics.configure({
12
+ * apiKey: 'mgm_proj_your_api_key',
13
+ * environment: 'production',
14
+ * });
15
+ *
16
+ * // Track events
17
+ * MostlyGoodMetrics.track('button_clicked', {
18
+ * button_id: 'submit',
19
+ * page: '/checkout',
20
+ * });
21
+ *
22
+ * // Identify users
23
+ * MostlyGoodMetrics.identify('user_123');
24
+ * ```
25
+ */
26
+ export { MostlyGoodMetrics } from './client';
27
+ export type { MGMConfiguration, ResolvedConfiguration, EventProperties, EventPropertyValue, MGMEvent, MGMEventContext, MGMEventsPayload, Platform, DeviceType, MGMErrorType, SendResult, IEventStorage, INetworkClient, } from './types';
28
+ export { MGMError } from './types';
29
+ export { SystemEvents, SystemProperties, DefaultConfiguration, Constraints, EVENT_NAME_REGEX, } from './types';
30
+ export { InMemoryEventStorage, LocalStorageEventStorage, createDefaultStorage } from './storage';
31
+ export { FetchNetworkClient, createDefaultNetworkClient } from './network';
32
+ export { generateUUID, getISOTimestamp, isValidEventName, validateEventName, sanitizeProperties, detectPlatform, detectDeviceType, getOSVersion, getDeviceModel, } from './utils';
33
+ export { logger } from './logger';
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG7C,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,cAAc,GACf,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,WAAW,EACX,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGjG,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAG3E,OAAO,EACL,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,cAAc,GACf,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Internal logger for the MostlyGoodMetrics SDK.
3
+ * Only outputs when debug logging is enabled.
4
+ */
5
+ /**
6
+ * Enable or disable debug logging.
7
+ */
8
+ export declare function setDebugLogging(enabled: boolean): void;
9
+ /**
10
+ * Check if debug logging is enabled.
11
+ */
12
+ export declare function isDebugEnabled(): boolean;
13
+ /**
14
+ * Log a debug message (only when debug logging is enabled).
15
+ */
16
+ export declare function debug(message: string, ...args: unknown[]): void;
17
+ /**
18
+ * Log an info message (only when debug logging is enabled).
19
+ */
20
+ export declare function info(message: string, ...args: unknown[]): void;
21
+ /**
22
+ * Log a warning message (always shown).
23
+ */
24
+ export declare function warn(message: string, ...args: unknown[]): void;
25
+ /**
26
+ * Log an error message (always shown).
27
+ */
28
+ export declare function error(message: string, ...args: unknown[]): void;
29
+ export declare const logger: {
30
+ setDebugLogging: typeof setDebugLogging;
31
+ isDebugEnabled: typeof isDebugEnabled;
32
+ debug: typeof debug;
33
+ info: typeof info;
34
+ warn: typeof warn;
35
+ error: typeof error;
36
+ };
37
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEtD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAI/D;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAI9D;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAE9D;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAE/D;AAED,eAAO,MAAM,MAAM;;;;;;;CAOlB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { INetworkClient, MGMEventsPayload, ResolvedConfiguration, SendResult } from './types';
2
+ /**
3
+ * Default network client using the Fetch API.
4
+ */
5
+ export declare class FetchNetworkClient implements INetworkClient {
6
+ private retryAfterTime;
7
+ /**
8
+ * Send events to the MostlyGoodMetrics API.
9
+ */
10
+ sendEvents(payload: MGMEventsPayload, config: ResolvedConfiguration): Promise<SendResult>;
11
+ /**
12
+ * Handle the API response and return appropriate result.
13
+ */
14
+ private handleResponse;
15
+ /**
16
+ * Check if currently rate limited.
17
+ */
18
+ isRateLimited(): boolean;
19
+ /**
20
+ * Get the time when rate limiting expires.
21
+ */
22
+ getRetryAfterTime(): Date | null;
23
+ }
24
+ /**
25
+ * Create the default network client.
26
+ */
27
+ export declare function createDefaultNetworkClient(): INetworkClient;
28
+ //# sourceMappingURL=network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/network.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,cAAc,EAEd,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACX,MAAM,SAAS,CAAC;AAqCjB;;GAEG;AACH,qBAAa,kBAAmB,YAAW,cAAc;IACvD,OAAO,CAAC,cAAc,CAAqB;IAE3C;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC;IAuE/F;;OAEG;IACH,OAAO,CAAC,cAAc;IAwEtB;;OAEG;IACH,aAAa,IAAI,OAAO;IAaxB;;OAEG;IACH,iBAAiB,IAAI,IAAI,GAAG,IAAI;CAGjC;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,cAAc,CAE3D"}
@@ -0,0 +1,76 @@
1
+ import { IEventStorage, MGMEvent } from './types';
2
+ /**
3
+ * In-memory event storage implementation.
4
+ * Used as a fallback when localStorage is not available,
5
+ * or for testing purposes.
6
+ */
7
+ export declare class InMemoryEventStorage implements IEventStorage {
8
+ private events;
9
+ private maxEvents;
10
+ constructor(maxEvents?: number);
11
+ store(event: MGMEvent): Promise<void>;
12
+ fetchEvents(limit: number): Promise<MGMEvent[]>;
13
+ removeEvents(count: number): Promise<void>;
14
+ eventCount(): Promise<number>;
15
+ clear(): Promise<void>;
16
+ /**
17
+ * Update the maximum number of stored events.
18
+ */
19
+ setMaxEvents(maxEvents: number): void;
20
+ }
21
+ /**
22
+ * LocalStorage-based event storage implementation.
23
+ * Persists events across page reloads and browser restarts.
24
+ */
25
+ export declare class LocalStorageEventStorage implements IEventStorage {
26
+ private maxEvents;
27
+ private events;
28
+ constructor(maxEvents?: number);
29
+ private loadEvents;
30
+ private saveEvents;
31
+ store(event: MGMEvent): Promise<void>;
32
+ fetchEvents(limit: number): Promise<MGMEvent[]>;
33
+ removeEvents(count: number): Promise<void>;
34
+ eventCount(): Promise<number>;
35
+ clear(): Promise<void>;
36
+ /**
37
+ * Update the maximum number of stored events.
38
+ */
39
+ setMaxEvents(maxEvents: number): void;
40
+ }
41
+ /**
42
+ * Create the appropriate storage implementation based on the environment.
43
+ */
44
+ export declare function createDefaultStorage(maxEvents: number): IEventStorage;
45
+ /**
46
+ * Persistence helpers for user ID and app version.
47
+ * These use localStorage when available, otherwise fall back to in-memory.
48
+ */
49
+ declare class PersistenceManager {
50
+ private inMemoryUserId;
51
+ private inMemoryAppVersion;
52
+ /**
53
+ * Get the persisted user ID.
54
+ */
55
+ getUserId(): string | null;
56
+ /**
57
+ * Set the user ID (persists across sessions).
58
+ */
59
+ setUserId(userId: string | null): void;
60
+ /**
61
+ * Get the persisted app version (for detecting updates).
62
+ */
63
+ getAppVersion(): string | null;
64
+ /**
65
+ * Set the app version.
66
+ */
67
+ setAppVersion(version: string | null): void;
68
+ /**
69
+ * Check if this is the first time the app has been opened.
70
+ * Uses localStorage to detect first-ever installation.
71
+ */
72
+ isFirstLaunch(): boolean;
73
+ }
74
+ export declare const persistence: PersistenceManager;
75
+ export {};
76
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,aAAa,EAAY,QAAQ,EAAE,MAAM,SAAS,CAAC;AAuBzE;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IACxD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,GAAE,MAAsC;IAIvD,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAI/C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAGtC;AAED;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,aAAa;IAC5D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAA2B;gBAE7B,SAAS,GAAE,MAAsC;IAI7D,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,UAAU;IASZ,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAK/C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM1C,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAGtC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAQrE;AAED;;;GAGG;AACH,cAAM,kBAAkB;IACtB,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,kBAAkB,CAAuB;IAEjD;;OAEG;IACH,SAAS,IAAI,MAAM,GAAG,IAAI;IAO1B;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAWtC;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;IAO9B;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAW3C;;;OAGG;IACH,aAAa,IAAI,OAAO;CAczB;AAED,eAAO,MAAM,WAAW,oBAA2B,CAAC"}