web-manager 4.0.34 → 4.0.36

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 CHANGED
@@ -7,8 +7,6 @@
7
7
  <p align="center">
8
8
  <img src="https://img.shields.io/github/package-json/v/itw-creative-works/web-manager.svg">
9
9
  <br>
10
- <img src="https://img.shields.io/david/itw-creative-works/web-manager.svg">
11
- <img src="https://img.shields.io/david/dev/itw-creative-works/web-manager.svg">
12
10
  <img src="https://img.shields.io/bundlephobia/min/web-manager.svg">
13
11
  <img src="https://img.shields.io/codeclimate/maintainability-percentage/itw-creative-works/web-manager.svg">
14
12
  <img src="https://img.shields.io/npm/dm/web-manager.svg">
@@ -22,40 +20,49 @@
22
20
  <a href="https://itwcreativeworks.com">Site</a> | <a href="https://www.npmjs.com/package/web-manager">NPM Module</a> | <a href="https://github.com/itw-creative-works/web-manager">GitHub Repo</a>
23
21
  <br>
24
22
  <br>
25
- <strong>Web Manager</strong> is an NPM module for web developers using node to build beautiful websites. This module instantly implements a few common libraries and functions that every developer should be using on their websites to enhance the user experience.
23
+ <strong>Web Manager</strong> is a modern JavaScript utility library for building web applications with Firebase integration. It provides authentication, data binding, storage management, push notifications, error tracking, and more.
26
24
  <br>
27
25
  <br>
28
- This module is best used when bundled with <a href="https://www.npmjs.com/package/webpack">webpack</a>.
26
+ Optimized for use with <a href="https://www.npmjs.com/package/webpack">webpack</a> but works standalone too.
29
27
  </p>
30
28
 
31
- ## 📦 Install Web Manager
32
- Install with npm:
29
+ ## Table of Contents
30
+ - [Installation](#-installation)
31
+ - [Requirements](#-requirements)
32
+ - [Quick Start](#-quick-start)
33
+ - [Supported Environments](#-supported-environments)
34
+ - [Features](#-features)
35
+ - [Configuration](#-configuration)
36
+ - [API Reference](#-api-reference)
37
+ - [Manager Instance](#manager-instance)
38
+ - [Storage API](#storage-api)
39
+ - [Authentication](#authentication)
40
+ - [Data Binding System](#data-binding-system)
41
+ - [Firestore](#firestore)
42
+ - [Push Notifications](#push-notifications)
43
+ - [Service Worker](#service-worker)
44
+ - [Sentry Error Tracking](#sentry-error-tracking)
45
+ - [DOM Utilities](#dom-utilities)
46
+ - [Utility Functions](#utility-functions)
47
+ - [HTML Data Attributes](#-html-data-attributes)
48
+ - [Direct Module Imports](#-direct-module-imports)
49
+ - [Browser Support](#-browser-support)
50
+ - [Projects Using This Library](#-projects-using-this-library)
51
+ - [Support](#-support)
52
+
53
+ ## Installation
33
54
  ```shell
34
55
  npm install web-manager
35
56
  ```
36
57
 
37
- ## 🦄 Features
38
- * **Firebase v12 Integration**: Modern Firebase Auth, Firestore, and Cloud Messaging
39
- * **Data Binding System**: Reactive DOM updates with `data-wm-bind` attributes
40
- * **Storage API**: Enhanced localStorage/sessionStorage with automatic JSON serialization
41
- * **Utilities**: Essential functions like `clipboardCopy()`, `escapeHTML()`, `getContext()`, and `showNotification()`
42
- * **DOM Utilities**: Lightweight helpers for dynamic script loading and DOM ready detection
43
- * **Service Worker Management**: Easy registration and messaging with service workers
44
- * **Push Notifications**: Simplified Firebase Cloud Messaging subscription system
58
+ ## Requirements
59
+ - **Node.js**: >= 12
60
+ - **Browser**: Modern browsers (ES6+ support, transpiled to ES5 for older browsers)
45
61
 
46
- ## 📚 Integrated Libraries
47
- * **Firebase v12**: Firebase App, Firestore, Auth, and Cloud Messaging
48
- * **Sentry**: Comprehensive error tracking and session replay
49
- * **Firebase App Check**: Optional reCAPTCHA Enterprise protection
62
+ **Note**: This library does not include TypeScript definitions.
50
63
 
51
- ## 📘 Quick Start
64
+ ## Quick Start
52
65
 
53
- ### Installation
54
- ```bash
55
- npm install web-manager
56
- ```
57
-
58
- ### Basic Setup
59
66
  ```javascript
60
67
  import Manager from 'web-manager';
61
68
 
@@ -85,21 +92,46 @@ await Manager.initialize({
85
92
  console.log('Web Manager initialized!');
86
93
  ```
87
94
 
88
- ## 📘 API Reference
95
+ ## Supported Environments
96
+
97
+ Web Manager is designed to work in multiple environments:
89
98
 
90
- ### Configuration
99
+ | Environment | Support | Notes |
100
+ |-------------|---------|-------|
101
+ | **Web** | Full | Primary target, works with webpack bundlers |
102
+ | **Electron** | Full | Works in renderer process |
103
+ | **Chrome Extension** | Full | Content scripts and popup pages |
104
+ | **Firefox Extension** | Full | Content scripts and popup pages |
105
+ | **Safari Extension** | Partial | Basic functionality supported |
91
106
 
92
- Here's a comprehensive configuration example with all available options:
107
+ ## Features
108
+ - **Firebase v12 Integration**: Modern Firebase Auth, Firestore, and Cloud Messaging
109
+ - **Data Binding System**: Reactive DOM updates with `data-wm-bind` attributes
110
+ - **Storage API**: Enhanced localStorage/sessionStorage with path-based access and JSON serialization
111
+ - **Utilities**: `clipboardCopy()`, `escapeHTML()`, `getContext()`, `showNotification()`, `getPlatform()`, `getRuntime()`, `isMobile()`, `getDeviceType()`
112
+ - **DOM Utilities**: Dynamic script loading with retry/timeout support
113
+ - **Service Worker Management**: Registration, messaging, and state tracking
114
+ - **Push Notifications**: Firebase Cloud Messaging with auto-subscription
115
+ - **Error Tracking**: Sentry integration with session replay
116
+ - **App Check**: Optional reCAPTCHA Enterprise protection
117
+ - **Version Checking**: Auto-reload when new version is deployed
118
+ - **HTML Data Attributes**: Automatic `data-platform`, `data-runtime`, `data-device` on `<html>`
119
+
120
+ ## Configuration
121
+
122
+ ### Full Configuration Reference
93
123
 
94
124
  ```javascript
95
125
  await Manager.initialize({
96
- // Environment and build info
97
- environment: 'production', // 'development' or 'production'
126
+ // Environment: 'development' or 'production'
127
+ environment: 'production',
128
+
129
+ // Build timestamp for version checking
98
130
  buildTime: Date.now(),
99
131
 
100
132
  // Brand information
101
133
  brand: {
102
- id: 'my-app',
134
+ id: 'my-app', // Used for custom protocol URLs
103
135
  name: 'My Application',
104
136
  description: 'App description',
105
137
  type: 'Organization',
@@ -130,7 +162,18 @@ await Manager.initialize({
130
162
  appCheck: {
131
163
  enabled: false,
132
164
  config: {
133
- siteKey: 'your-recaptcha-site-key'
165
+ siteKey: 'your-recaptcha-enterprise-site-key'
166
+ }
167
+ }
168
+ },
169
+
170
+ // Authentication settings
171
+ auth: {
172
+ enabled: true,
173
+ config: {
174
+ redirects: {
175
+ authenticated: '/account', // Redirect after login
176
+ unauthenticated: '/signup' // Redirect when not logged in
134
177
  }
135
178
  }
136
179
  },
@@ -140,8 +183,9 @@ await Manager.initialize({
140
183
  enabled: true,
141
184
  config: {
142
185
  dsn: 'https://your-sentry-dsn',
143
- replaysSessionSampleRate: 0.01,
144
- replaysOnErrorSampleRate: 0.01
186
+ release: '1.0.0',
187
+ replaysSessionSampleRate: 0.01, // 1% of sessions
188
+ replaysOnErrorSampleRate: 0.01 // 1% of error sessions
145
189
  }
146
190
  },
147
191
 
@@ -149,7 +193,8 @@ await Manager.initialize({
149
193
  pushNotifications: {
150
194
  enabled: true,
151
195
  config: {
152
- autoRequest: 60000 // Auto-request after 60s of first user interaction
196
+ autoRequest: 60000, // Auto-request after 60s of first click
197
+ vapidKey: 'your-vapid-key' // Optional VAPID key
153
198
  }
154
199
  },
155
200
 
@@ -161,389 +206,367 @@ await Manager.initialize({
161
206
  }
162
207
  },
163
208
 
164
- // Valid redirect hosts for auth
209
+ // Version checking (auto-reload on new version)
210
+ refreshNewVersion: {
211
+ enabled: true,
212
+ config: {
213
+ interval: 3600000 // Check every hour (1000 * 60 * 60)
214
+ }
215
+ },
216
+
217
+ // Valid hosts for auth redirects (security)
165
218
  validRedirectHosts: ['example.com', 'app.example.com']
166
219
  });
167
220
  ```
168
221
 
169
- ### DOM Utilities
222
+ ### Configuration Notes
170
223
 
171
- The DOM utilities provide essential functions for working with the DOM:
224
+ - **Timeout values** can be specified as strings with math expressions: `'1000 * 60 * 60'` (evaluated safely)
225
+ - **Deep merge**: Your config is deep-merged with defaults, so you only need to specify what you want to change
226
+ - **Firebase required**: Most features require Firebase to be configured and enabled
172
227
 
173
- ```javascript
174
- import { loadScript, ready } from 'web-manager';
228
+ ## API Reference
175
229
 
176
- // Wait for DOM to be ready
177
- await ready();
178
- console.log('DOM is ready!');
230
+ ### Manager Instance
179
231
 
180
- // Load an external script dynamically
181
- await loadScript({
182
- src: 'https://example.com/script.js',
183
- async: true,
184
- crossorigin: 'anonymous',
185
- timeout: 30000,
186
- retries: 2
187
- });
188
-
189
- // Or simply pass a URL string
190
- await loadScript('https://example.com/script.js');
191
- ```
192
-
193
- You can also access these via the Manager instance:
232
+ The Manager is a singleton that provides access to all modules:
194
233
 
195
234
  ```javascript
196
- const domUtils = Manager.dom();
197
- await domUtils.loadScript('https://example.com/script.js');
198
- await domUtils.ready();
235
+ import Manager from 'web-manager';
236
+
237
+ // Module getters
238
+ Manager.storage(); // Storage API
239
+ Manager.auth(); // Firebase Auth wrapper
240
+ Manager.bindings(); // Data binding system
241
+ Manager.firestore(); // Firestore wrapper
242
+ Manager.notifications(); // Push notifications
243
+ Manager.serviceWorker(); // Service worker management
244
+ Manager.sentry(); // Error tracking
245
+ Manager.dom(); // DOM utilities
246
+ Manager.utilities(); // Utility functions
247
+
248
+ // Helper methods
249
+ Manager.isDevelopment(); // Check if in development mode
250
+ Manager.getFunctionsUrl(); // Get Firebase Functions URL
251
+ Manager.getFunctionsUrl('development'); // Force development URL
252
+ Manager.getApiUrl(); // Get API URL (derived from authDomain)
253
+ Manager.isValidRedirectUrl('https://...'); // Validate redirect URL
254
+
255
+ // Firebase instances (after initialization)
256
+ Manager.firebaseApp; // Firebase App instance
257
+ Manager.firebaseAuth; // Firebase Auth instance
258
+ Manager.firebaseFirestore; // Firestore instance
259
+ Manager.firebaseMessaging; // FCM instance
260
+
261
+ // Configuration
262
+ Manager.config; // Access full configuration
199
263
  ```
200
264
 
201
- ### Utilities
265
+ ### Storage API
202
266
 
203
- The utilities module provides essential helper functions:
267
+ Enhanced localStorage and sessionStorage with path-based access:
204
268
 
205
269
  ```javascript
206
- import { clipboardCopy, escapeHTML, getContext, showNotification } from 'web-manager';
270
+ const storage = Manager.storage();
207
271
 
208
- // Copy text to clipboard
209
- await clipboardCopy('Text to copy');
272
+ // LocalStorage (persists across browser sessions)
273
+ storage.set('user.name', 'John');
274
+ storage.set('user.preferences', { theme: 'dark', lang: 'en' });
210
275
 
211
- // Escape HTML to prevent XSS attacks
212
- const safe = escapeHTML('<script>alert("xss")</script>');
213
- // Returns: &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;
276
+ const name = storage.get('user.name'); // 'John'
277
+ const theme = storage.get('user.preferences.theme'); // 'dark'
278
+ const all = storage.get(); // Entire storage object
279
+ const fallback = storage.get('missing.path', 'default'); // 'default'
214
280
 
215
- // Get client context information
216
- const context = getContext();
217
- // Returns: {
218
- // client: { language, mobile, platform, userAgent, url },
219
- // browser: { vendor }
220
- // }
281
+ storage.remove('user.name');
282
+ storage.clear();
221
283
 
222
- // Show Bootstrap-styled notification
223
- showNotification('Success!', { type: 'success', timeout: 5000 });
224
- showNotification('Error occurred', 'danger'); // Shorthand
225
- showNotification(new Error('Something went wrong')); // Auto-detects error
284
+ // SessionStorage (cleared when browser closes)
285
+ storage.session.set('temp.token', 'abc123');
286
+ storage.session.get('temp.token');
287
+ storage.session.remove('temp.token');
288
+ storage.session.clear();
226
289
  ```
227
290
 
228
- Access via Manager instance:
291
+ **Features**:
292
+ - Automatic JSON serialization/deserialization
293
+ - Nested path access using dot notation
294
+ - Fallback to in-memory storage if localStorage unavailable
295
+ - Uses lodash `get`/`set` for reliable path access
296
+
297
+ ### Authentication
298
+
299
+ Firebase Authentication wrapper with automatic account data fetching:
229
300
 
230
301
  ```javascript
231
- const utils = Manager.utilities();
232
- utils.clipboardCopy('Hello!');
233
- utils.escapeHTML('<div>Test</div>');
234
- utils.getContext();
235
- utils.showNotification('Message', 'info');
236
- ```
302
+ const auth = Manager.auth();
237
303
 
238
- ### Storage API
304
+ // Listen for auth state changes
305
+ const unsubscribe = auth.listen({ account: true }, (result) => {
306
+ console.log('User:', result.user); // Firebase user or null
307
+ console.log('Account:', result.account); // Firestore account data or null
308
+ });
239
309
 
240
- Enhanced localStorage and sessionStorage with automatic JSON serialization and nested path support:
310
+ // Listen once (useful for initial state)
311
+ auth.listen({ once: true }, (result) => {
312
+ console.log('Initial state:', result);
313
+ });
241
314
 
242
- ```javascript
243
- const storage = Manager.storage();
315
+ // Check authentication status
316
+ if (auth.isAuthenticated()) {
317
+ const user = auth.getUser();
318
+ console.log('Logged in as:', user.email);
319
+ }
244
320
 
245
- // LocalStorage operations (persists across sessions)
246
- storage.set('user.name', 'John');
247
- storage.set('user.preferences', { theme: 'dark', lang: 'en' });
321
+ // Sign in
322
+ try {
323
+ const user = await auth.signInWithEmailAndPassword('user@example.com', 'password');
324
+ } catch (error) {
325
+ console.error('Sign in failed:', error.message);
326
+ }
248
327
 
249
- const name = storage.get('user.name'); // 'John'
250
- const theme = storage.get('user.preferences.theme'); // 'dark'
251
- const all = storage.get(); // Get entire storage object
328
+ // Sign in with custom token (from backend)
329
+ await auth.signInWithCustomToken('custom-jwt-token');
252
330
 
253
- storage.remove('user.name');
254
- storage.clear(); // Clear all data
331
+ // Get ID token for API calls
332
+ const idToken = await auth.getIdToken();
333
+ const freshToken = await auth.getIdToken(true); // Force refresh
255
334
 
256
- // SessionStorage operations (cleared when browser closes)
257
- storage.session.set('temp.data', 'value');
258
- const tempData = storage.session.get('temp.data');
259
- storage.session.remove('temp.data');
260
- storage.session.clear();
335
+ // Sign out
336
+ await auth.signOut();
337
+
338
+ // Stop listening
339
+ unsubscribe();
261
340
  ```
262
341
 
263
- All data is automatically serialized to JSON, so you can store objects, arrays, and primitives without manual conversion.
342
+ **getUser() returns enhanced user object**:
343
+ ```javascript
344
+ {
345
+ uid: 'abc123',
346
+ email: 'user@example.com',
347
+ displayName: 'John Doe', // Falls back to email or 'User'
348
+ photoURL: 'https://...', // Falls back to ui-avatars.com
349
+ emailVerified: true
350
+ }
351
+ ```
264
352
 
265
- ### Utilizing the Data Binding System
266
- Web Manager includes a powerful data binding system that automatically updates your DOM elements based on data changes. Simply add the `data-wm-bind` attribute to any element.
353
+ **HTML Auth Classes**:
354
+ Add these classes to elements for automatic auth functionality:
355
+ - `.auth-signout-btn` - Sign out button (shows confirmation dialog)
356
+
357
+ ### Data Binding System
358
+
359
+ Reactive DOM updates with `data-wm-bind` attributes:
267
360
 
268
361
  #### Basic Text Binding
269
362
  ```html
270
- <!-- Display user email -->
363
+ <!-- Display text content (default action) -->
271
364
  <span data-wm-bind="auth.user.email"></span>
272
-
273
- <!-- Display nested properties -->
274
- <div data-wm-bind="auth.account.subscription.plan"></div>
365
+ <span data-wm-bind="@text auth.user.displayName"></span>
275
366
  ```
276
367
 
277
368
  #### Input/Textarea Value Binding
278
369
  ```html
279
- <!-- Set input value -->
280
- <input data-wm-bind="@value settings.theme" />
281
-
282
- <!-- Set textarea value -->
370
+ <input data-wm-bind="@value settings.email" />
283
371
  <textarea data-wm-bind="@value user.bio"></textarea>
284
-
285
- <!-- Combine with other actions -->
286
- <input data-wm-bind="@value auth.user.email, @attr disabled auth.user.emailVerified" />
287
372
  ```
288
373
 
289
374
  #### Conditional Visibility
290
375
  ```html
291
- <!-- Show element when condition is true -->
292
- <div data-wm-bind="@show auth.user">Welcome!</div>
293
- <div data-wm-bind="@show auth.user.emailVerified">Email is verified</div>
376
+ <!-- Show when truthy -->
377
+ <div data-wm-bind="@show auth.user">Welcome back!</div>
294
378
 
295
- <!-- Hide element when condition is true -->
379
+ <!-- Hide when truthy -->
296
380
  <div data-wm-bind="@hide auth.user">Please log in</div>
297
381
 
298
- <!-- Or, show element when condition is false -->
299
- <div data-wm-bind="@show !auth.user">Please log in</div>
382
+ <!-- Negation -->
383
+ <div data-wm-bind="@show !auth.user">Not logged in</div>
300
384
 
301
385
  <!-- Comparisons -->
302
- <div data-wm-bind="@show auth.account.subscription.plan === 'premium'">Premium features</div>
303
- <div data-wm-bind="@hide settings.custom === 'value">Notifications enabled</div>
304
- ```
305
-
306
- #### Usage in JavaScript
307
- ```javascript
308
- // Auth data is automatically bound when using auth().listen()
309
- Manager.auth().listen({ account: true }, (result) => {
310
- // auth.user and auth.account data are automatically bound to the DOM
311
- });
312
-
313
- // Update bindings with custom data
314
- Manager.bindings().update({
315
- settings: { custom: 'value' },
316
- });
317
-
318
- // Get current binding context
319
- const context = Manager.bindings().getContext();
320
-
321
- // Clear all bindings
322
- Manager.bindings().clear();
386
+ <div data-wm-bind="@show auth.account.plan === 'premium'">Premium content</div>
387
+ <div data-wm-bind="@hide settings.notifications === false">Notifications on</div>
323
388
  ```
324
389
 
325
- #### Attribute Actions
390
+ #### Attribute Binding
326
391
  ```html
327
- <!-- Set an attribute value -->
328
392
  <img data-wm-bind="@attr src auth.user.photoURL" />
329
393
  <a data-wm-bind="@attr href settings.profileUrl">Profile</a>
330
-
331
- <!-- Multiple attributes on same element -->
332
- <img data-wm-bind="@attr src auth.user.photoURL, @attr alt auth.user.displayName" />
394
+ <input data-wm-bind="@attr disabled auth.loading" />
333
395
  ```
334
396
 
335
- #### Multiple Actions
336
- You can combine multiple actions on a single element by separating them with commas:
337
-
397
+ #### Style Binding
338
398
  ```html
339
- <!-- Set text AND show/hide -->
340
- <div data-wm-bind="@show auth.user, @text auth.user.displayName"></div>
399
+ <!-- CSS custom properties -->
400
+ <div data-wm-bind="@style --rating-width ratings.percent"></div>
341
401
 
342
- <!-- Set text AND multiple attributes -->
343
- <img data-wm-bind="@text auth.user.displayName, @attr src auth.user.photoURL, @attr title auth.user.email" />
344
-
345
- <!-- Multiple attributes -->
346
- <a data-wm-bind="@attr href settings.url, @attr target settings.target, @text settings.linkText"></a>
402
+ <!-- Inline styles -->
403
+ <div data-wm-bind="@style background-color theme.primary"></div>
347
404
  ```
348
405
 
349
- #### Skeleton Loaders
350
- Add the `wm-binding-skeleton` class to show a loading skeleton while data is being bound:
351
-
406
+ #### Multiple Actions
407
+ Combine actions with commas:
352
408
  ```html
353
- <!-- Shows a shimmer loading effect until data is bound -->
354
- <span data-wm-bind="auth.user.displayName" class="wm-binding-skeleton"></span>
355
-
356
- <!-- Profile card with multiple skeleton loaders -->
357
- <div class="profile-card">
358
- <img data-wm-bind="@attr src auth.user.photoURL" class="wm-binding-skeleton">
359
- <h3 data-wm-bind="auth.user.displayName" class="wm-binding-skeleton"></h3>
360
- <p data-wm-bind="auth.user.email" class="wm-binding-skeleton"></p>
361
- </div>
362
-
363
- <!-- Elements without the class won't show skeleton loaders -->
364
- <span data-wm-bind="settings.theme"></span>
409
+ <img data-wm-bind="@show auth.user, @attr src auth.user.photoURL, @attr alt auth.user.displayName" />
365
410
  ```
366
411
 
367
- The skeleton loader automatically:
368
- - Displays a shimmer animation while the element is unbound
369
- - Hides the text content during loading
370
- - Prevents interaction until data is loaded
371
- - Fades in smoothly when data arrives
372
- - Adapts to dark themes
373
- - Respects `prefers-reduced-motion` accessibility settings
412
+ #### JavaScript API
413
+ ```javascript
414
+ const bindings = Manager.bindings();
374
415
 
375
- #### Visual Feedback
376
- When an element is bound, Web Manager automatically adds the `wm-bound` class to it. You can use this class for styling or debugging:
416
+ // Update context data
417
+ bindings.update({
418
+ settings: { theme: 'dark', email: 'user@example.com' },
419
+ custom: { value: 123 }
420
+ });
377
421
 
378
- ```css
379
- /* Add a subtle indicator for bound elements in development */
380
- .wm-bound {
381
- outline: 1px dashed rgba(0, 123, 255, 0.3);
382
- }
422
+ // Get current context
423
+ const context = bindings.getContext();
383
424
 
384
- /* Custom styling after binding */
385
- .wm-bound {
386
- /* Element has been successfully bound */
387
- }
425
+ // Clear all bindings
426
+ bindings.clear();
388
427
  ```
389
428
 
390
- #### Style Bindings
391
- Set CSS custom properties (CSS variables) or inline styles dynamically:
392
-
429
+ #### Skeleton Loaders
393
430
  ```html
394
- <!-- Set CSS custom property -->
395
- <div data-wm-bind="@style --rating-percent site.ratings.starWidth"></div>
396
-
397
- <!-- Set regular style property -->
398
- <div data-wm-bind="@style width user.profile.width"></div>
399
-
400
- <!-- Multiple styles -->
401
- <div data-wm-bind="@style --primary-color theme.primaryColor, @style --secondary-color theme.secondaryColor"></div>
431
+ <!-- Shows shimmer animation until bound -->
432
+ <span data-wm-bind="auth.user.name" class="wm-binding-skeleton"></span>
402
433
  ```
403
434
 
404
- Then use the custom property in your CSS:
405
-
406
- ```css
407
- .rating-stars::before {
408
- width: var(--rating-percent, 0%);
409
- background: var(--primary-color, #007bff);
410
- }
411
- ```
435
+ The skeleton automatically:
436
+ - Displays shimmer animation while loading
437
+ - Fades in smoothly when data arrives
438
+ - Adds `wm-bound` class when complete
439
+ - Respects `prefers-reduced-motion`
412
440
 
413
441
  #### Supported Actions
414
- - **`@text`** (default): Sets the text content of the element
415
- - **`@value`**: Sets the value of an input or textarea element
416
- - **`@show`**: Shows the element when condition is true
417
- - **`@hide`**: Hides the element when condition is true
418
- - **`@attr`**: Sets an attribute value (format: `@attr attributeName expression`)
419
- - **`@style`**: Sets a CSS custom property or inline style (format: `@style propertyName expression`)
420
442
 
421
- Future actions like `@class` can be easily added.
443
+ | Action | Syntax | Description |
444
+ |--------|--------|-------------|
445
+ | `@text` | `@text path` | Set text content (default) |
446
+ | `@value` | `@value path` | Set input/textarea value |
447
+ | `@show` | `@show condition` | Show element if truthy |
448
+ | `@hide` | `@hide condition` | Hide element if truthy |
449
+ | `@attr` | `@attr name path` | Set attribute value |
450
+ | `@style` | `@style prop path` | Set CSS property or variable |
422
451
 
423
- ### Firebase Authentication
452
+ ### Firestore
424
453
 
425
- The auth module provides Firebase Authentication integration with automatic account data fetching:
454
+ Simplified Firestore wrapper with chainable queries:
426
455
 
427
456
  ```javascript
428
- const auth = Manager.auth();
429
-
430
- // Listen for auth state changes (waits for settled state)
431
- const unsubscribe = auth.listen({ account: true }, (result) => {
432
- console.log('User:', result.user);
433
- console.log('Account:', result.account);
434
-
435
- // result.user contains: uid, email, displayName, photoURL, emailVerified
436
- // result.account contains resolved account data from Firestore
437
- });
457
+ const db = Manager.firestore();
438
458
 
439
- // Listen only once
440
- auth.listen({ once: true }, (result) => {
441
- console.log('Initial auth state:', result);
442
- });
459
+ // Document operations - two syntax options
460
+ await db.doc('users/user123').set({ name: 'John', age: 30 });
461
+ await db.doc('users', 'user123').update({ age: 31 });
443
462
 
444
- // Check if user is authenticated
445
- if (auth.isAuthenticated()) {
446
- const user = auth.getUser();
447
- console.log('Current user:', user);
463
+ const docSnap = await db.doc('users/user123').get();
464
+ if (docSnap.exists()) {
465
+ console.log('Data:', docSnap.data());
466
+ console.log('ID:', docSnap.id);
448
467
  }
449
468
 
450
- // Sign in with email and password
451
- try {
452
- const user = await auth.signInWithEmailAndPassword('user@example.com', 'password');
453
- console.log('Signed in:', user);
454
- } catch (error) {
455
- console.error('Sign in failed:', error);
456
- }
469
+ await db.doc('users/user123').delete();
457
470
 
458
- // Sign in with custom token
459
- await auth.signInWithCustomToken('custom-token');
471
+ // Collection queries
472
+ const snapshot = await db.collection('users').get();
473
+ console.log('Count:', snapshot.size);
474
+ console.log('Empty:', snapshot.empty);
475
+ snapshot.docs.forEach(doc => {
476
+ console.log(doc.id, doc.data());
477
+ });
460
478
 
461
- // Sign out
462
- await auth.signOut();
479
+ // Query with filters (chainable)
480
+ const results = await db.collection('users')
481
+ .where('age', '>=', 18)
482
+ .where('active', '==', true)
483
+ .orderBy('createdAt', 'desc')
484
+ .limit(20)
485
+ .get();
463
486
 
464
- // Get ID token for API calls
465
- const idToken = await auth.getIdToken(forceRefresh = false);
487
+ // Pagination
488
+ const page2 = await db.collection('users')
489
+ .orderBy('name')
490
+ .startAt('M')
491
+ .endAt('N')
492
+ .get();
466
493
  ```
467
494
 
468
- #### Built-in Auth UI Classes
469
-
470
- Add these CSS classes to HTML elements for automatic auth functionality:
471
-
472
- * `.auth-signout-btn` - Sign out button (shows confirmation)
473
-
474
- The auth system automatically updates DOM elements with `data-wm-bind` attributes (see Data Binding section).
495
+ **Where Operators**: `<`, `<=`, `==`, `!=`, `>=`, `>`, `array-contains`, `in`, `array-contains-any`, `not-in`
475
496
 
476
497
  ### Push Notifications
477
498
 
478
- Simplified Firebase Cloud Messaging integration:
499
+ Firebase Cloud Messaging integration:
479
500
 
480
501
  ```javascript
481
502
  const notifications = Manager.notifications();
482
503
 
483
- // Check if notifications are supported
504
+ // Check support
484
505
  if (notifications.isSupported()) {
485
- console.log('Push notifications are supported!');
506
+ console.log('Push notifications available');
486
507
  }
487
508
 
488
509
  // Check subscription status
489
510
  const isSubscribed = await notifications.isSubscribed();
490
511
 
491
- // Subscribe to push notifications
512
+ // Subscribe
492
513
  try {
493
514
  const result = await notifications.subscribe({
494
515
  vapidKey: 'your-vapid-key' // Optional
495
516
  });
496
- console.log('Subscribed!', result.token);
517
+ console.log('Token:', result.token);
497
518
  } catch (error) {
498
- console.error('Subscription failed:', error);
519
+ if (error.message.includes('permission')) {
520
+ console.log('User denied permission');
521
+ }
499
522
  }
500
523
 
501
524
  // Unsubscribe
502
525
  await notifications.unsubscribe();
503
526
 
504
- // Get current FCM token
527
+ // Get current token
505
528
  const token = await notifications.getToken();
506
529
 
507
530
  // Listen for foreground messages
508
531
  const unsubscribe = await notifications.onMessage((payload) => {
509
- console.log('Message received:', payload);
532
+ console.log('Received:', payload);
510
533
  });
511
534
 
512
- // Sync subscription with current auth state
535
+ // Sync subscription with auth state
513
536
  await notifications.syncSubscription();
514
537
  ```
515
538
 
516
- The notification system automatically:
517
- - Requests permission after user interaction (configurable via `pushNotifications.config.autoRequest`)
518
- - Stores subscription info in Firestore
539
+ **Features**:
540
+ - Stores subscription in localStorage and Firestore
541
+ - Tracks device context (platform, runtime, deviceType)
542
+ - Auto-requests after configurable delay post-click
519
543
  - Syncs with user authentication state
520
- - Shows notifications when app is in foreground
521
544
 
522
545
  ### Service Worker
523
546
 
524
- Manage service workers with automatic support detection:
547
+ Service worker registration and messaging:
525
548
 
526
549
  ```javascript
527
550
  const sw = Manager.serviceWorker();
528
551
 
529
- // Check if service workers are supported
552
+ // Check support
530
553
  if (sw.isSupported()) {
531
- console.log('Service workers are supported!');
554
+ console.log('Service workers available');
532
555
  }
533
556
 
534
- // Register service worker (done automatically during initialization)
557
+ // Register (done automatically during init if enabled)
535
558
  const registration = await sw.register({
536
559
  path: '/service-worker.js',
537
560
  scope: '/'
538
561
  });
539
562
 
540
- // Wait for service worker to be ready
563
+ // Wait for ready state
541
564
  await sw.ready();
542
565
 
543
- // Get current registration
566
+ // Get registration
544
567
  const reg = sw.getRegistration();
545
568
 
546
- // Post message to service worker
569
+ // Post message with response
547
570
  try {
548
571
  const response = await sw.postMessage({
549
572
  command: 'cache-clear',
@@ -551,62 +574,21 @@ try {
551
574
  }, { timeout: 5000 });
552
575
  console.log('Response:', response);
553
576
  } catch (error) {
554
- console.error('Message failed:', error);
577
+ console.error('Timeout or error:', error);
555
578
  }
556
579
 
557
580
  // Listen for messages from service worker
558
581
  const unsubscribe = sw.onMessage('notification-click', (data, event) => {
559
- console.log('Notification clicked:', data);
582
+ console.log('Clicked:', data);
560
583
  });
561
584
 
562
- // Get service worker state
563
- const state = sw.getState(); // 'none', 'installing', 'waiting', 'active'
585
+ // Get current state
586
+ const state = sw.getState(); // 'none', 'installing', 'waiting', 'active', 'unknown'
564
587
  ```
565
588
 
566
- ### Firestore
589
+ ### Sentry Error Tracking
567
590
 
568
- Simplified Firestore wrapper with chainable queries:
569
-
570
- ```javascript
571
- const db = Manager.firestore();
572
-
573
- // Document operations
574
- await db.doc('users/user123').set({ name: 'John', age: 30 });
575
- await db.doc('users', 'user123').update({ age: 31 });
576
-
577
- const docSnap = await db.doc('users/user123').get();
578
- if (docSnap.exists()) {
579
- console.log('User data:', docSnap.data());
580
- }
581
-
582
- await db.doc('users/user123').delete();
583
-
584
- // Collection queries
585
- const snapshot = await db.collection('users').get();
586
- snapshot.docs.forEach(doc => {
587
- console.log(doc.id, doc.data());
588
- });
589
-
590
- // Query with filters
591
- const result = await db.collection('users')
592
- .where('age', '>=', 18)
593
- .orderBy('age', 'desc')
594
- .limit(10)
595
- .get();
596
-
597
- // Chainable queries
598
- const adults = await db.collection('users')
599
- .where('age', '>=', 18)
600
- .where('active', '==', true)
601
- .orderBy('createdAt', 'desc')
602
- .limit(20)
603
- .startAt(lastDoc)
604
- .get();
605
- ```
606
-
607
- ### Sentry Integration
608
-
609
- Error tracking with automatic configuration:
591
+ Automatic error tracking with Sentry:
610
592
 
611
593
  ```javascript
612
594
  const sentry = Manager.sentry();
@@ -622,54 +604,191 @@ try {
622
604
  }
623
605
  ```
624
606
 
625
- Sentry is automatically configured with:
626
- - Environment and release tracking
627
- - User context from auth state
628
- - Session replay (if configured)
629
- - Filtering for development/automated browsers
607
+ **Automatic Features**:
608
+ - Environment and release tracking from config
609
+ - User context from auth state (uid, email)
610
+ - Session duration tracking
611
+ - Filters out Lighthouse and automated browsers (Selenium, Puppeteer)
612
+ - Blocks sending in development mode
613
+ - Dynamic import to reduce bundle size
614
+
615
+ ### DOM Utilities
616
+
617
+ ```javascript
618
+ import { loadScript, ready } from 'web-manager/modules/dom';
619
+ // Or: const { loadScript, ready } = Manager.dom();
620
+
621
+ // Wait for DOM ready
622
+ await ready();
623
+
624
+ // Load external script
625
+ await loadScript({
626
+ src: 'https://example.com/script.js',
627
+ async: true,
628
+ defer: false,
629
+ crossorigin: 'anonymous',
630
+ integrity: 'sha384-...',
631
+ timeout: 30000,
632
+ retries: 2,
633
+ parent: document.head,
634
+ attributes: { 'data-custom': 'value' }
635
+ });
636
+
637
+ // Simple string syntax
638
+ await loadScript('https://example.com/script.js');
639
+ ```
640
+
641
+ **loadScript Options**:
630
642
 
631
- ### Manager Helper Methods
643
+ | Option | Type | Default | Description |
644
+ |--------|------|---------|-------------|
645
+ | `src` | string | required | Script URL |
646
+ | `async` | boolean | `true` | Load asynchronously |
647
+ | `defer` | boolean | `false` | Defer execution |
648
+ | `crossorigin` | boolean/string | `false` | CORS setting |
649
+ | `integrity` | string | `null` | SRI hash |
650
+ | `timeout` | number | `60000` | Timeout in ms |
651
+ | `retries` | number | `0` | Retry attempts |
652
+ | `parent` | Element | `document.head` | Parent element |
653
+ | `attributes` | object | `{}` | Custom attributes |
632
654
 
633
- The Manager instance provides several utility methods:
655
+ ### Utility Functions
634
656
 
635
657
  ```javascript
636
- // Check if running in development mode
637
- if (Manager.isDevelopment()) {
638
- console.log('Running in development');
639
- }
658
+ import {
659
+ clipboardCopy,
660
+ escapeHTML,
661
+ showNotification,
662
+ getPlatform,
663
+ getRuntime,
664
+ isMobile,
665
+ getDeviceType,
666
+ getContext
667
+ } from 'web-manager/modules/utilities';
668
+ // Or: const utils = Manager.utilities();
669
+
670
+ // Copy to clipboard
671
+ await clipboardCopy('Text to copy');
672
+ await clipboardCopy(document.querySelector('#input')); // From element
673
+
674
+ // Escape HTML (XSS prevention)
675
+ const safe = escapeHTML('<script>alert("xss")</script>');
676
+ // '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'
677
+
678
+ // Show notification (Bootstrap-styled)
679
+ showNotification('Success!', { type: 'success', timeout: 5000 });
680
+ showNotification('Error!', 'danger');
681
+ showNotification(new Error('Failed'), { timeout: 0 }); // No auto-dismiss
682
+
683
+ // Platform detection
684
+ getPlatform(); // 'windows', 'mac', 'linux', 'ios', 'android', 'chromeos', 'unknown'
685
+
686
+ // Runtime detection
687
+ getRuntime(); // 'web', 'browser-extension'
688
+
689
+ // Device detection
690
+ isMobile(); // true/false
691
+ getDeviceType(); // 'mobile' (<768px), 'tablet' (768-1199px), 'desktop' (>=1200px)
692
+
693
+ // Full context
694
+ getContext();
695
+ // {
696
+ // client: { language, mobile, deviceType, platform, runtime, userAgent, url },
697
+ // browser: { vendor }
698
+ // }
699
+ ```
700
+
701
+ **showNotification Options**:
640
702
 
641
- // Get Firebase Functions URL
642
- const functionsUrl = Manager.getFunctionsUrl(); // Uses config environment
643
- const devUrl = Manager.getFunctionsUrl('development'); // http://localhost:5001/...
644
- const prodUrl = Manager.getFunctionsUrl('production'); // https://us-central1-...
703
+ | Option | Type | Default | Description |
704
+ |--------|------|---------|-------------|
705
+ | `type` | string | `'info'` | `'info'`, `'success'`, `'warning'`, `'danger'` |
706
+ | `timeout` | number | `5000` | Auto-dismiss after ms (0 = never) |
645
707
 
646
- // Get API URL (derives from Firebase config)
647
- const apiUrl = Manager.getApiUrl(); // https://api.your-domain.com
708
+ ## HTML Data Attributes
648
709
 
649
- // Validate redirect URLs (for auth flows)
650
- const isValid = Manager.isValidRedirectUrl('https://example.com/callback');
710
+ Web Manager automatically sets these attributes on the `<html>` element during initialization:
651
711
 
652
- // Access Firebase instances directly
653
- const app = Manager.firebaseApp;
654
- const auth = Manager.firebaseAuth;
655
- const firestore = Manager.firebaseFirestore;
656
- const messaging = Manager.firebaseMessaging;
712
+ ```html
713
+ <html data-platform="mac" data-runtime="web" data-device="desktop">
714
+ ```
715
+
716
+ | Attribute | Values | Description |
717
+ |-----------|--------|-------------|
718
+ | `data-platform` | `windows`, `mac`, `linux`, `ios`, `android`, `chromeos`, `unknown` | Operating system |
719
+ | `data-runtime` | `web`, `browser-extension` | Runtime environment |
720
+ | `data-device` | `mobile`, `tablet`, `desktop` | Device type by screen width |
721
+
722
+ **CSS Usage**:
723
+ ```css
724
+ /* Platform-specific styles */
725
+ [data-platform="ios"] .download-btn { display: none; }
726
+ [data-platform="windows"] .app-icon { content: url('windows-icon.png'); }
657
727
 
658
- // Access configuration
659
- const config = Manager.config;
660
- console.log('Brand:', config.brand);
661
- console.log('Environment:', config.environment);
728
+ /* Device-responsive styles */
729
+ [data-device="mobile"] .sidebar { display: none; }
730
+ [data-device="desktop"] .mobile-menu { display: none; }
662
731
  ```
663
732
 
664
- ## 🗨️ Final Words
665
- If you are still having difficulty, we would love for you to post
666
- a question to [the Web Manager issues page](https://github.com/itw-creative-works/web-manager/issues). It is much easier to answer questions that include your code and relevant files! So if you can provide them, we'd be extremely grateful (and more likely to help you find the answer!)
733
+ ## Direct Module Imports
667
734
 
668
- ## 📚 Projects Using this Library
669
- [Somiibo](https://somiibo.com/): A Social Media Bot with an open-source module library. <br>
670
- [JekyllUp](https://jekyllup.com/): A website devoted to sharing the best Jekyll themes. <br>
671
- [Slapform](https://slapform.com/): A backend processor for your HTML forms on static sites. <br>
672
- [SoundGrail Music App](https://app.soundgrail.com/): A resource for producers, musicians, and DJs. <br>
673
- [Hammock Report](https://hammockreport.com/): An API for exploring and listing backyard products. <br>
735
+ Import individual modules to reduce bundle size:
736
+
737
+ ```javascript
738
+ // Storage only
739
+ import Storage from 'web-manager/modules/storage';
740
+ const storage = new Storage();
741
+
742
+ // Utilities only
743
+ import { clipboardCopy, escapeHTML } from 'web-manager/modules/utilities';
744
+
745
+ // DOM utilities only
746
+ import { loadScript, ready } from 'web-manager/modules/dom';
747
+
748
+ // Full manager (default)
749
+ import Manager from 'web-manager';
750
+ ```
674
751
 
675
- Ask us to have your project listed! :)
752
+ **Available Modules**:
753
+ - `web-manager/modules/storage` - Storage class
754
+ - `web-manager/modules/utilities` - Utility functions
755
+ - `web-manager/modules/dom` - DOM utilities
756
+ - `web-manager/modules/auth` - Auth class (requires Manager)
757
+ - `web-manager/modules/bindings` - Bindings class (requires Manager)
758
+ - `web-manager/modules/firestore` - Firestore class (requires Manager)
759
+ - `web-manager/modules/notifications` - Notifications class (requires Manager)
760
+ - `web-manager/modules/service-worker` - ServiceWorker class (requires Manager)
761
+ - `web-manager/modules/sentry` - Sentry class (requires Manager)
762
+
763
+ ## Browser Support
764
+
765
+ Web Manager is transpiled to ES5 for broad browser support:
766
+
767
+ | Browser | Version | Support |
768
+ |---------|---------|---------|
769
+ | Chrome | 60+ | Full |
770
+ | Firefox | 55+ | Full |
771
+ | Safari | 11+ | Full |
772
+ | Edge | 79+ | Full |
773
+ | IE | 11 | Not supported |
774
+
775
+ **Notes**:
776
+ - Service Workers require HTTPS (except localhost)
777
+ - Push Notifications require Service Worker support
778
+ - Some features use modern APIs with fallbacks
779
+
780
+ ## Projects Using This Library
781
+
782
+ - [Somiibo](https://somiibo.com/): A Social Media Bot with an open-source module library
783
+ - [JekyllUp](https://jekyllup.com/): A website devoted to sharing the best Jekyll themes
784
+ - [Slapform](https://slapform.com/): A backend processor for HTML forms on static sites
785
+ - [SoundGrail Music App](https://app.soundgrail.com/): A resource for producers, musicians, and DJs
786
+ - [Hammock Report](https://hammockreport.com/): An API for exploring and listing backyard products
787
+
788
+ *Want your project listed? [Open an issue](https://github.com/itw-creative-works/web-manager/issues)!*
789
+
790
+ ## Support
791
+
792
+ If you're having issues or have questions:
793
+ - [Open an issue](https://github.com/itw-creative-works/web-manager/issues) on GitHub
794
+ - Include code samples and relevant files to help us help you faster