@mostly-good-metrics/javascript 0.2.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/types.ts CHANGED
@@ -134,6 +134,11 @@ export interface MGMEvent {
134
134
  */
135
135
  name: string;
136
136
 
137
+ /**
138
+ * Unique client-generated ID for deduplication.
139
+ */
140
+ client_event_id: string;
141
+
137
142
  /**
138
143
  * ISO8601 timestamp when the event occurred.
139
144
  */
@@ -159,6 +164,11 @@ export interface MGMEvent {
159
164
  */
160
165
  appVersion?: string;
161
166
 
167
+ /**
168
+ * The app build number (separate from version).
169
+ */
170
+ appBuildNumber?: string;
171
+
162
172
  /**
163
173
  * The OS version string.
164
174
  */
@@ -169,6 +179,21 @@ export interface MGMEvent {
169
179
  */
170
180
  environment: string;
171
181
 
182
+ /**
183
+ * The device manufacturer (e.g., "Apple", "Samsung").
184
+ */
185
+ deviceManufacturer?: string;
186
+
187
+ /**
188
+ * The user's locale (e.g., "en-US").
189
+ */
190
+ locale?: string;
191
+
192
+ /**
193
+ * The user's timezone (e.g., "America/New_York").
194
+ */
195
+ timezone?: string;
196
+
172
197
  /**
173
198
  * Custom properties attached to this event.
174
199
  */
@@ -182,10 +207,14 @@ export interface MGMEvent {
182
207
  export interface MGMEventContext {
183
208
  platform: Platform;
184
209
  appVersion?: string;
210
+ appBuildNumber?: string;
185
211
  osVersion?: string;
186
212
  userId?: string;
187
213
  sessionId?: string;
188
214
  environment: string;
215
+ deviceManufacturer?: string;
216
+ locale?: string;
217
+ timezone?: string;
189
218
  }
190
219
 
191
220
  /**
package/src/utils.test.ts CHANGED
@@ -5,6 +5,8 @@ import {
5
5
  validateEventName,
6
6
  sanitizeProperties,
7
7
  resolveConfiguration,
8
+ getLocale,
9
+ getTimezone,
8
10
  } from './utils';
9
11
  import { Constraints, DefaultConfiguration, MGMError } from './types';
10
12
 
@@ -237,3 +239,32 @@ describe('resolveConfiguration', () => {
237
239
  expect(config.maxStoredEvents).toBe(Constraints.MIN_STORED_EVENTS);
238
240
  });
239
241
  });
242
+
243
+ describe('getLocale', () => {
244
+ it('should return a non-empty string', () => {
245
+ const locale = getLocale();
246
+ expect(typeof locale).toBe('string');
247
+ expect(locale.length).toBeGreaterThan(0);
248
+ });
249
+
250
+ it('should return a locale-like string (e.g., en, en-US)', () => {
251
+ const locale = getLocale();
252
+ // Locale should be something like "en", "en-US", "fr-FR", etc.
253
+ expect(locale).toMatch(/^[a-z]{2}(-[A-Z]{2})?$/i);
254
+ });
255
+ });
256
+
257
+ describe('getTimezone', () => {
258
+ it('should return a string', () => {
259
+ const timezone = getTimezone();
260
+ expect(typeof timezone).toBe('string');
261
+ });
262
+
263
+ it('should return a valid IANA timezone or empty string', () => {
264
+ const timezone = getTimezone();
265
+ // Should be empty or a valid IANA timezone like "America/New_York" or "UTC"
266
+ if (timezone) {
267
+ expect(timezone).toMatch(/^([A-Za-z_]+\/[A-Za-z_]+|UTC)$/);
268
+ }
269
+ });
270
+ });
package/src/utils.ts CHANGED
@@ -310,3 +310,24 @@ export function getDeviceModel(): string {
310
310
  export function delay(ms: number): Promise<void> {
311
311
  return new Promise((resolve) => setTimeout(resolve, ms));
312
312
  }
313
+
314
+ /**
315
+ * Get the user's locale.
316
+ */
317
+ export function getLocale(): string {
318
+ if (typeof navigator !== 'undefined') {
319
+ return navigator.language || 'en';
320
+ }
321
+ return 'en';
322
+ }
323
+
324
+ /**
325
+ * Get the user's timezone.
326
+ */
327
+ export function getTimezone(): string {
328
+ try {
329
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || '';
330
+ } catch {
331
+ return '';
332
+ }
333
+ }