web-manager 4.1.0 → 4.1.2

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/CHANGELOG.md CHANGED
@@ -14,6 +14,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
14
14
  - `Fixed` for any bug fixes.
15
15
  - `Security` in case of vulnerabilities.
16
16
 
17
+ ---
18
+ ## [4.1.1] - 2025-12-17
19
+ ### Added
20
+ - Added `getBrowser()` utility to detect browser type (chrome, firefox, safari, edge, opera, brave).
21
+ - Added `data-browser` HTML attribute set during initialization.
22
+ - Added `browser` and `vendor` fields to `getContext().client`.
23
+ - Added `geolocation` object to `getContext()` with placeholder fields (ip, country, region, city, latitude, longitude).
24
+
25
+ ### Changed
26
+ - Moved `vendor` from `browser` object to `client` object in `getContext()`.
27
+ - Replaced `browser` object with `geolocation` object in `getContext()` return structure.
28
+
17
29
  ---
18
30
  ## [4.1.0] - 2025-12-16
19
31
  ### Added
package/CLAUDE.md CHANGED
@@ -181,7 +181,7 @@ document.body.addEventListener('click', (e) => {
181
181
  - **loadScript Options**: src, async, defer, crossorigin, integrity, timeout, retries
182
182
 
183
183
  ### Utilities (`utilities.js`)
184
- - **Exports**: `clipboardCopy()`, `escapeHTML()`, `showNotification()`, `getPlatform()`, `getRuntime()`, `isMobile()`, `getDeviceType()`, `getContext()`
184
+ - **Exports**: `clipboardCopy()`, `escapeHTML()`, `showNotification()`, `getPlatform()`, `getBrowser()`, `getRuntime()`, `isMobile()`, `getDeviceType()`, `getContext()`
185
185
 
186
186
  ## Build System
187
187
 
package/README.md CHANGED
@@ -108,14 +108,14 @@ Web Manager is designed to work in multiple environments:
108
108
  - **Firebase v12 Integration**: Modern Firebase Auth, Firestore, and Cloud Messaging
109
109
  - **Data Binding System**: Reactive DOM updates with `data-wm-bind` attributes
110
110
  - **Storage API**: Enhanced localStorage/sessionStorage with path-based access and JSON serialization
111
- - **Utilities**: `clipboardCopy()`, `escapeHTML()`, `getContext()`, `showNotification()`, `getPlatform()`, `getRuntime()`, `isMobile()`, `getDeviceType()`
111
+ - **Utilities**: `clipboardCopy()`, `escapeHTML()`, `getContext()`, `showNotification()`, `getPlatform()`, `getBrowser()`, `getRuntime()`, `isMobile()`, `getDeviceType()`
112
112
  - **DOM Utilities**: Dynamic script loading with retry/timeout support
113
113
  - **Service Worker Management**: Registration, messaging, and state tracking
114
114
  - **Push Notifications**: Firebase Cloud Messaging with auto-subscription
115
115
  - **Error Tracking**: Sentry integration with session replay
116
116
  - **App Check**: Optional reCAPTCHA Enterprise protection
117
117
  - **Version Checking**: Auto-reload when new version is deployed
118
- - **HTML Data Attributes**: Automatic `data-platform`, `data-runtime`, `data-device` on `<html>`
118
+ - **HTML Data Attributes**: Automatic `data-platform`, `data-browser`, `data-runtime`, `data-device` on `<html>`
119
119
 
120
120
  ## Configuration
121
121
 
@@ -660,6 +660,7 @@ import {
660
660
  escapeHTML,
661
661
  showNotification,
662
662
  getPlatform,
663
+ getBrowser,
663
664
  getRuntime,
664
665
  isMobile,
665
666
  getDeviceType,
@@ -683,6 +684,9 @@ showNotification(new Error('Failed'), { timeout: 0 }); // No auto-dismiss
683
684
  // Platform detection
684
685
  getPlatform(); // 'windows', 'mac', 'linux', 'ios', 'android', 'chromeos', 'unknown'
685
686
 
687
+ // Browser detection
688
+ getBrowser(); // 'chrome', 'firefox', 'safari', 'edge', 'opera', 'brave', null
689
+
686
690
  // Runtime detection
687
691
  getRuntime(); // 'web', 'browser-extension'
688
692
 
@@ -693,8 +697,8 @@ getDeviceType(); // 'mobile' (<768px), 'tablet' (768-1199px), 'desktop' (>=1200p
693
697
  // Full context
694
698
  getContext();
695
699
  // {
696
- // client: { language, mobile, deviceType, platform, runtime, userAgent, url },
697
- // browser: { vendor }
700
+ // client: { language, mobile, deviceType, platform, browser, vendor, runtime, userAgent, url },
701
+ // geolocation: { ip, country, region, city, latitude, longitude }
698
702
  // }
699
703
  ```
700
704
 
@@ -710,12 +714,13 @@ getContext();
710
714
  Web Manager automatically sets these attributes on the `<html>` element during initialization:
711
715
 
712
716
  ```html
713
- <html data-platform="mac" data-runtime="web" data-device="desktop">
717
+ <html data-platform="mac" data-browser="chrome" data-runtime="web" data-device="desktop">
714
718
  ```
715
719
 
716
720
  | Attribute | Values | Description |
717
721
  |-----------|--------|-------------|
718
722
  | `data-platform` | `windows`, `mac`, `linux`, `ios`, `android`, `chromeos`, `unknown` | Operating system |
723
+ | `data-browser` | `chrome`, `firefox`, `safari`, `edge`, `opera`, `brave` | Browser name |
719
724
  | `data-runtime` | `web`, `browser-extension` | Runtime environment |
720
725
  | `data-device` | `mobile`, `tablet`, `desktop` | Device type by screen width |
721
726
 
@@ -725,6 +730,10 @@ Web Manager automatically sets these attributes on the `<html>` element during i
725
730
  [data-platform="ios"] .download-btn { display: none; }
726
731
  [data-platform="windows"] .app-icon { content: url('windows-icon.png'); }
727
732
 
733
+ /* Browser-specific styles */
734
+ [data-browser="safari"] .webkit-fix { -webkit-transform: translateZ(0); }
735
+ [data-browser="firefox"] .gecko-fix { overflow: hidden; }
736
+
728
737
  /* Device-responsive styles */
729
738
  [data-device="mobile"] .sidebar { display: none; }
730
739
  [data-device="desktop"] .mobile-menu { display: none; }
package/dist/index.js CHANGED
@@ -361,6 +361,9 @@ class Manager {
361
361
  // Set platform (OS) - windows, mac, linux, ios, android, chromeos, unknown
362
362
  $html.dataset.platform = this._utilities.getPlatform();
363
363
 
364
+ // Set browser - chrome, firefox, safari, edge, opera, brave
365
+ $html.dataset.browser = this._utilities.getBrowser();
366
+
364
367
  // Set runtime - web, browser-extension, electron, node
365
368
  $html.dataset.runtime = this._utilities.getRuntime();
366
369
 
@@ -261,14 +261,12 @@ class Notifications {
261
261
  return;
262
262
  }
263
263
 
264
- const { getContext } = await import('./utilities.js');
265
-
266
264
  const now = new Date();
267
265
  const timestamp = now.toISOString();
268
266
  const timestampUNIX = Math.floor(now.getTime() / 1000);
269
267
 
270
268
  // Get context for client information
271
- const context = getContext();
269
+ const context = this.manager.utilities().getContext();
272
270
  const clientData = context.client;
273
271
 
274
272
  // Reference to the notification document (ID is the token)
@@ -283,41 +281,33 @@ class Notifications {
283
281
  const existingUid = existingData?.uid || null;
284
282
  const needsUpdate = existingUid !== currentUid;
285
283
 
284
+ // Common data for both create and update
285
+ const baseData = {
286
+ context: {
287
+ client: clientData
288
+ },
289
+ updated: {
290
+ timestamp,
291
+ timestampUNIX
292
+ },
293
+ uid: currentUid
294
+ };
295
+
296
+ // Create or update the document as needed
286
297
  if (!existingData) {
287
298
  // New subscription - create the document
288
- const subscriptionData = {
299
+ await notificationDoc.set({
300
+ ...baseData,
289
301
  token,
290
- context: {
291
- client: clientData
292
- },
293
302
  tags: ['general'],
294
303
  created: {
295
304
  timestamp,
296
305
  timestampUNIX
297
306
  },
298
- updated: {
299
- timestamp,
300
- timestampUNIX
301
- },
302
- uid: currentUid
303
- };
304
-
305
- await notificationDoc.set(subscriptionData);
306
-
307
+ });
307
308
  } else if (needsUpdate) {
308
309
  // Existing subscription needs update (userId changed)
309
- const updateData = {
310
- context: {
311
- client: clientData
312
- },
313
- updated: {
314
- timestamp,
315
- timestampUNIX
316
- },
317
- uid: currentUid
318
- };
319
-
320
- await notificationDoc.update(updateData);
310
+ await notificationDoc.update(baseData);
321
311
  }
322
312
  // If no update needed, do nothing
323
313
 
@@ -128,6 +128,40 @@ class Utilities {
128
128
  return 'unknown';
129
129
  }
130
130
 
131
+ // Get browser name
132
+ getBrowser() {
133
+ const ua = navigator.userAgent;
134
+
135
+ // Order matters - check more specific browsers first
136
+ // Edge before Chrome (Edge includes "Chrome" in UA)
137
+ if (/edg/i.test(ua)) {
138
+ return 'edge';
139
+ }
140
+ // Opera before Chrome (Opera includes "Chrome" in UA)
141
+ if (/opera|opr/i.test(ua)) {
142
+ return 'opera';
143
+ }
144
+ // Brave before Chrome (Brave includes "Chrome" in UA)
145
+ if (navigator.brave || /brave/i.test(ua)) {
146
+ return 'brave';
147
+ }
148
+ // Chrome (including Chromium-based browsers)
149
+ if (/chrome|chromium|crios/i.test(ua)) {
150
+ return 'chrome';
151
+ }
152
+ // Firefox
153
+ if (/firefox|fxios/i.test(ua)) {
154
+ return 'firefox';
155
+ }
156
+ // Safari last (most browsers include "Safari" in UA)
157
+ if (/safari/i.test(ua)) {
158
+ return 'safari';
159
+ }
160
+
161
+ // Fallback
162
+ return null;
163
+ }
164
+
131
165
  // Get runtime environment
132
166
  getRuntime() {
133
167
  // Use config runtime if provided
@@ -195,12 +229,19 @@ class Utilities {
195
229
  mobile: this.isMobile(),
196
230
  deviceType: this.getDeviceType(),
197
231
  platform: this.getPlatform(),
232
+ browser: this.getBrowser(),
233
+ vendor: navigator.vendor,
198
234
  runtime: this.getRuntime(),
199
235
  userAgent: navigator.userAgent,
200
236
  url: window.location.href,
201
237
  },
202
- browser: {
203
- vendor: navigator.vendor,
238
+ geolocation: {
239
+ ip: null,
240
+ country: null,
241
+ region: null,
242
+ city: null,
243
+ latitude: null,
244
+ longitude: null,
204
245
  },
205
246
  };
206
247
  }
@@ -798,3 +798,31 @@
798
798
  [debug] [2025-12-17T01:04:07.263Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
799
799
  [debug] [2025-12-17T01:04:07.264Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
800
800
  [debug] [2025-12-17T01:04:07.264Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
801
+ [debug] [2025-12-17T22:53:29.414Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
802
+ [debug] [2025-12-17T22:53:29.418Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
803
+ [debug] [2025-12-17T22:53:29.417Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
804
+ [debug] [2025-12-17T22:53:29.417Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
805
+ [debug] [2025-12-17T22:53:29.417Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
806
+ [debug] [2025-12-17T22:53:29.426Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
807
+ [debug] [2025-12-17T22:53:29.427Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
808
+ [debug] [2025-12-17T22:53:29.420Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
809
+ [debug] [2025-12-17T22:53:29.420Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
810
+ [debug] [2025-12-17T22:53:29.420Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
811
+ [debug] [2025-12-17T22:53:29.432Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
812
+ [debug] [2025-12-17T22:53:29.432Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
813
+ [debug] [2025-12-17T22:53:29.445Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
814
+ [debug] [2025-12-17T22:53:29.445Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
815
+ [debug] [2025-12-17T22:53:29.446Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
816
+ [debug] [2025-12-17T22:53:29.446Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
817
+ [debug] [2025-12-17T22:53:29.448Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
818
+ [debug] [2025-12-17T22:53:29.448Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
819
+ [debug] [2025-12-17T22:53:29.448Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
820
+ [debug] [2025-12-17T22:53:29.448Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
821
+ [debug] [2025-12-17T22:53:29.452Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
822
+ [debug] [2025-12-17T22:53:29.452Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
823
+ [debug] [2025-12-17T22:53:29.453Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
824
+ [debug] [2025-12-17T22:53:29.453Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
825
+ [debug] [2025-12-17T22:53:29.455Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
826
+ [debug] [2025-12-17T22:53:29.455Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
827
+ [debug] [2025-12-17T22:53:29.456Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
828
+ [debug] [2025-12-17T22:53:29.456Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-manager",
3
- "version": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "Easily access important variables such as the query string, current domain, and current page in a single object.",
5
5
  "main": "dist/index.js",
6
6
  "module": "src/index.js",