@angular-helpers/browser-web-apis 21.3.0 → 21.5.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.
@@ -1,77 +1,62 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, DestroyRef, PLATFORM_ID, signal, computed, isSignal, effect, ElementRef, makeEnvironmentProviders } from '@angular/core';
2
+ import { InjectionToken, inject, DestroyRef, PLATFORM_ID, Injectable, signal, computed, isSignal, effect, ElementRef, makeEnvironmentProviders } from '@angular/core';
3
3
  import { isPlatformBrowser, isPlatformServer } from '@angular/common';
4
- import { Observable, fromEvent, Subject, of, map as map$1 } from 'rxjs';
4
+ import { Observable, fromEvent, BehaviorSubject, Subject, of, map as map$1 } from 'rxjs';
5
5
  import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
6
6
  import { filter, distinctUntilChanged, map } from 'rxjs/operators';
7
7
  import { Router } from '@angular/router';
8
8
 
9
- class PermissionsService {
10
- async query(descriptor) {
11
- if (!this.isSupported()) {
12
- throw new Error('Permissions API not supported');
13
- }
14
- try {
15
- return await navigator.permissions.query(descriptor);
16
- }
17
- catch (error) {
18
- console.error('Error querying permission:', error);
19
- throw error;
20
- }
21
- }
22
- isSupported() {
23
- return typeof navigator !== 'undefined' && 'permissions' in navigator;
24
- }
25
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PermissionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
26
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PermissionsService });
27
- }
28
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PermissionsService, decorators: [{
29
- type: Injectable
30
- }] });
9
+ const BROWSER_API_LOGGER = new InjectionToken('BROWSER_API_LOGGER', {
10
+ providedIn: 'root',
11
+ factory: () => ({
12
+ // oxlint-disable-next-line no-console
13
+ info: (message) => console.info(message),
14
+ // oxlint-disable-next-line no-console
15
+ warn: (message) => console.warn(message),
16
+ // oxlint-disable-next-line no-console
17
+ error: (message, error) => console.error(message, error),
18
+ }),
19
+ });
31
20
 
32
21
  /**
33
- * Base class for all Browser Web API services
22
+ * Base class for all Browser Web API services.
34
23
  * Provides common functionality for:
35
- * - Support checking
36
- * - Permission management
37
- * - Error handling
24
+ * - Platform detection (browser vs server)
25
+ * - Support assertion via Template Method
26
+ * - Error creation with cause chaining
27
+ * - Structured logging via injectable BROWSER_API_LOGGER token
38
28
  * - Lifecycle management with destroyRef
39
- * - Logging
29
+ *
30
+ * Services that also need permission querying should extend
31
+ * `PermissionAwareBrowserApiBaseService` instead.
40
32
  */
41
33
  class BrowserApiBaseService {
42
- permissionsService = inject(PermissionsService);
43
34
  destroyRef = inject(DestroyRef);
44
35
  platformId = inject(PLATFORM_ID);
36
+ logger = inject(BROWSER_API_LOGGER);
45
37
  /**
46
- * Check if running in browser environment using Angular's platform detection
38
+ * Check if running in browser environment using Angular's platform detection.
47
39
  */
48
40
  isBrowserEnvironment() {
49
41
  return isPlatformBrowser(this.platformId);
50
42
  }
51
43
  /**
52
- * Check if running in server environment using Angular's platform detection
44
+ * Check if running in server environment using Angular's platform detection.
53
45
  */
54
46
  isServerEnvironment() {
55
47
  return isPlatformServer(this.platformId);
56
48
  }
57
49
  /**
58
- * Request a permission
50
+ * Template Method: asserts the service can run in the current environment.
51
+ * Subclasses must call super.ensureSupported() and then add their own API check.
59
52
  */
60
- async requestPermission(permission) {
61
- if (this.isServerEnvironment()) {
53
+ ensureSupported() {
54
+ if (!this.isBrowserEnvironment()) {
62
55
  throw new Error(`${this.getApiName()} API not available in server environment`);
63
56
  }
64
- try {
65
- const status = await this.permissionsService.query({ name: permission });
66
- return status.state === 'granted';
67
- }
68
- catch (error) {
69
- console.error(`[${this.getApiName()}] Error requesting permission for ${permission}:`, error);
70
- return false;
71
- }
72
57
  }
73
58
  /**
74
- * Create an error with proper cause chaining
59
+ * Create an error with proper cause chaining.
75
60
  */
76
61
  createError(message, cause) {
77
62
  const error = new Error(message);
@@ -80,6 +65,24 @@ class BrowserApiBaseService {
80
65
  }
81
66
  return error;
82
67
  }
68
+ /**
69
+ * Log an error through the injected BROWSER_API_LOGGER (default: console).
70
+ */
71
+ logError(message, error) {
72
+ this.logger.error(`[${this.getApiName()}] ${message}`, error);
73
+ }
74
+ /**
75
+ * Log a warning through the injected BROWSER_API_LOGGER (default: console).
76
+ */
77
+ logWarn(message) {
78
+ this.logger.warn(`[${this.getApiName()}] ${message}`);
79
+ }
80
+ /**
81
+ * Log an informational message through the injected BROWSER_API_LOGGER (default: console).
82
+ */
83
+ logInfo(message) {
84
+ this.logger.info(`[${this.getApiName()}] ${message}`);
85
+ }
83
86
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BrowserApiBaseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
84
87
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BrowserApiBaseService });
85
88
  }
@@ -87,25 +90,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
87
90
  type: Injectable
88
91
  }] });
89
92
 
93
+ class PermissionsService extends BrowserApiBaseService {
94
+ getApiName() {
95
+ return 'permissions';
96
+ }
97
+ async query(descriptor) {
98
+ if (!this.isSupported()) {
99
+ throw new Error('Permissions API not supported in this environment');
100
+ }
101
+ try {
102
+ return await navigator.permissions.query(descriptor);
103
+ }
104
+ catch (error) {
105
+ // Firefox does not support querying 'camera', 'microphone', or 'speaker' via
106
+ // the Permissions API and throws a TypeError. Return a synthetic 'prompt' status
107
+ // so callers fall through to the native getUserMedia / requestPermission flow.
108
+ if (error instanceof TypeError) {
109
+ return { state: 'prompt', onchange: null };
110
+ }
111
+ this.logError(`Error querying permission for ${descriptor.name}:`, error);
112
+ throw error;
113
+ }
114
+ }
115
+ isSupported() {
116
+ return this.isBrowserEnvironment() && 'permissions' in navigator;
117
+ }
118
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PermissionsService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
119
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PermissionsService });
120
+ }
121
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PermissionsService, decorators: [{
122
+ type: Injectable
123
+ }] });
124
+
90
125
  class CameraService extends BrowserApiBaseService {
91
126
  currentStream = null;
92
127
  getApiName() {
93
128
  return 'camera';
94
129
  }
95
- ensureCameraSupport() {
96
- if (!('mediaDevices' in navigator) || !('getUserMedia' in navigator.mediaDevices)) {
97
- throw new Error('Camera API not supported in this browser');
130
+ ensureSupported() {
131
+ super.ensureSupported();
132
+ if (!navigator.mediaDevices?.getUserMedia) {
133
+ throw new Error('Camera API not supported — a secure context (HTTPS) is required');
98
134
  }
99
135
  }
100
136
  async startCamera(constraints) {
101
- this.ensureCameraSupport();
137
+ this.ensureSupported();
102
138
  if (this.currentStream) {
103
139
  this.stopCamera();
104
140
  }
105
- const permissionStatus = await this.permissionsService.query({ name: 'camera' });
106
- if (permissionStatus.state !== 'granted') {
107
- throw new Error('Camera permission required. Please grant camera access and try again.');
108
- }
109
141
  try {
110
142
  const streamConstraints = constraints || {
111
143
  video: {
@@ -118,7 +150,7 @@ class CameraService extends BrowserApiBaseService {
118
150
  return this.currentStream;
119
151
  }
120
152
  catch (error) {
121
- console.error('[CameraService] Error starting camera:', error);
153
+ this.logError('Error starting camera:', error);
122
154
  if (error instanceof Error && error.name === 'NotAllowedError') {
123
155
  throw this.createError('Camera permission denied by user. Please allow camera access in your browser settings and refresh the page.', error);
124
156
  }
@@ -160,19 +192,24 @@ class CameraService extends BrowserApiBaseService {
160
192
  return this.startCamera(finalConstraints);
161
193
  }
162
194
  async getCameraCapabilities(deviceId) {
163
- this.ensureCameraSupport();
195
+ this.ensureSupported();
164
196
  try {
197
+ const activeTrack = this.currentStream
198
+ ?.getVideoTracks()
199
+ .find((t) => t.getSettings().deviceId === deviceId);
200
+ if (activeTrack) {
201
+ return activeTrack.getCapabilities() ?? null;
202
+ }
165
203
  const stream = await navigator.mediaDevices.getUserMedia({
166
204
  video: { deviceId: { exact: deviceId } },
167
205
  });
168
206
  const videoTrack = stream.getVideoTracks()[0];
169
207
  const capabilities = videoTrack.getCapabilities();
170
- // Clean up the stream
171
208
  stream.getTracks().forEach((track) => track.stop());
172
- return capabilities || null;
209
+ return capabilities ?? null;
173
210
  }
174
211
  catch (error) {
175
- console.error('[CameraService] Error getting camera capabilities:', error);
212
+ this.logError('Error getting camera capabilities:', error);
176
213
  return null;
177
214
  }
178
215
  }
@@ -183,19 +220,19 @@ class CameraService extends BrowserApiBaseService {
183
220
  return this.currentStream !== null;
184
221
  }
185
222
  async getVideoInputDevices() {
186
- this.ensureCameraSupport();
223
+ this.ensureSupported();
187
224
  try {
188
225
  const devices = await navigator.mediaDevices.enumerateDevices();
189
226
  return devices.filter((device) => device.kind === 'videoinput');
190
227
  }
191
228
  catch (error) {
192
- console.error('[CameraService] Error enumerating video devices:', error);
229
+ this.logError('Error enumerating video devices:', error);
193
230
  throw this.createError('Failed to enumerate video devices', error);
194
231
  }
195
232
  }
196
233
  // Direct access to native camera API
197
234
  getNativeMediaDevices() {
198
- this.ensureCameraSupport();
235
+ this.ensureSupported();
199
236
  return navigator.mediaDevices;
200
237
  }
201
238
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CameraService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
@@ -209,25 +246,26 @@ class GeolocationService extends BrowserApiBaseService {
209
246
  getApiName() {
210
247
  return 'geolocation';
211
248
  }
212
- ensureGeolocationSupport() {
249
+ ensureSupported() {
250
+ super.ensureSupported();
213
251
  if (!('geolocation' in navigator)) {
214
- throw new Error('Geolocation API not supported in this browser');
252
+ throw new Error('Geolocation API not supported a secure context (HTTPS) is required');
215
253
  }
216
254
  }
217
255
  getCurrentPosition(options) {
218
- this.ensureGeolocationSupport();
256
+ this.ensureSupported();
219
257
  return new Promise((resolve, reject) => {
220
258
  navigator.geolocation.getCurrentPosition((position) => resolve(position), (error) => {
221
- console.error('[GeolocationService] Error getting position:', error);
259
+ this.logError('Error getting position:', error);
222
260
  reject(error);
223
261
  }, options);
224
262
  });
225
263
  }
226
264
  watchPosition(options) {
227
- this.ensureGeolocationSupport();
265
+ this.ensureSupported();
228
266
  return new Observable((observer) => {
229
267
  const watchId = navigator.geolocation.watchPosition((position) => observer.next(position), (error) => {
230
- console.error('[GeolocationService] Error watching position:', error);
268
+ this.logError('Error watching position:', error);
231
269
  observer.error(error);
232
270
  }, options);
233
271
  return () => {
@@ -240,7 +278,7 @@ class GeolocationService extends BrowserApiBaseService {
240
278
  }
241
279
  // Direct access to native geolocation API
242
280
  getNativeGeolocation() {
243
- this.ensureGeolocationSupport();
281
+ this.ensureSupported();
244
282
  return navigator.geolocation;
245
283
  }
246
284
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GeolocationService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
@@ -254,24 +292,25 @@ class MediaDevicesService extends BrowserApiBaseService {
254
292
  getApiName() {
255
293
  return 'media-devices';
256
294
  }
257
- ensureMediaDevicesSupport() {
258
- if (!('mediaDevices' in navigator)) {
259
- throw new Error('MediaDevices API not supported in this browser');
295
+ ensureSupported() {
296
+ super.ensureSupported();
297
+ if (!navigator.mediaDevices) {
298
+ throw new Error('MediaDevices API not supported — a secure context (HTTPS) is required');
260
299
  }
261
300
  }
262
301
  async getDevices() {
263
- this.ensureMediaDevicesSupport();
302
+ this.ensureSupported();
264
303
  try {
265
304
  const devices = await navigator.mediaDevices.enumerateDevices();
266
305
  return devices;
267
306
  }
268
307
  catch (error) {
269
- console.error('[MediaDevicesService] Error enumerating devices:', error);
308
+ this.logError('Error enumerating devices:', error);
270
309
  throw this.createError('Failed to enumerate media devices', error);
271
310
  }
272
311
  }
273
312
  async getUserMedia(constraints) {
274
- this.ensureMediaDevicesSupport();
313
+ this.ensureSupported();
275
314
  try {
276
315
  const defaultConstraints = {
277
316
  video: true,
@@ -281,12 +320,12 @@ class MediaDevicesService extends BrowserApiBaseService {
281
320
  return await navigator.mediaDevices.getUserMedia(finalConstraints);
282
321
  }
283
322
  catch (error) {
284
- console.error('[MediaDevicesService] Error getting user media:', error);
323
+ this.logError('Error getting user media:', error);
285
324
  throw this.handleMediaError(error);
286
325
  }
287
326
  }
288
327
  async getDisplayMedia(constraints) {
289
- this.ensureMediaDevicesSupport();
328
+ this.ensureSupported();
290
329
  if (!('getDisplayMedia' in navigator.mediaDevices)) {
291
330
  throw new Error('Display media API not supported in this browser');
292
331
  }
@@ -299,12 +338,12 @@ class MediaDevicesService extends BrowserApiBaseService {
299
338
  return await navigator.mediaDevices.getDisplayMedia(finalConstraints);
300
339
  }
301
340
  catch (error) {
302
- console.error('[MediaDevicesService] Error getting display media:', error);
341
+ this.logError('Error getting display media:', error);
303
342
  throw this.createError('Failed to get display media', error);
304
343
  }
305
344
  }
306
345
  watchDeviceChanges() {
307
- this.ensureMediaDevicesSupport();
346
+ this.ensureSupported();
308
347
  return new Observable((observer) => {
309
348
  const handleDeviceChange = async () => {
310
349
  try {
@@ -312,7 +351,7 @@ class MediaDevicesService extends BrowserApiBaseService {
312
351
  observer.next(devices);
313
352
  }
314
353
  catch (error) {
315
- console.error('[MediaDevicesService] Error handling device change:', error);
354
+ this.logError('Error handling device change:', error);
316
355
  }
317
356
  };
318
357
  // Listen for device changes
@@ -367,7 +406,7 @@ class MediaDevicesService extends BrowserApiBaseService {
367
406
  }
368
407
  // Direct access to native media devices API
369
408
  getNativeMediaDevices() {
370
- this.ensureMediaDevicesSupport();
409
+ this.ensureSupported();
371
410
  return navigator.mediaDevices;
372
411
  }
373
412
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MediaDevicesService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
@@ -381,22 +420,24 @@ class NotificationService extends BrowserApiBaseService {
381
420
  getApiName() {
382
421
  return 'notifications';
383
422
  }
423
+ ensureSupported() {
424
+ super.ensureSupported();
425
+ if (!('Notification' in window)) {
426
+ throw new Error('Notifications API not supported in this browser');
427
+ }
428
+ }
384
429
  get permission() {
430
+ if (!this.isBrowserEnvironment() || !('Notification' in window)) {
431
+ return 'default';
432
+ }
385
433
  return Notification.permission;
386
434
  }
387
- isSupported() {
388
- return 'Notification' in window;
389
- }
390
435
  async requestNotificationPermission() {
391
- if (!this.isSupported()) {
392
- throw new Error('Notification API not supported in this browser');
393
- }
436
+ this.ensureSupported();
394
437
  return Notification.requestPermission();
395
438
  }
396
439
  async showNotification(title, options) {
397
- if (!this.isSupported()) {
398
- throw new Error('Notification API not supported in this browser');
399
- }
440
+ this.ensureSupported();
400
441
  if (Notification.permission !== 'granted') {
401
442
  throw new Error('Notification permission required. Please grant notification access and try again.');
402
443
  }
@@ -404,7 +445,7 @@ class NotificationService extends BrowserApiBaseService {
404
445
  return new Notification(title, options);
405
446
  }
406
447
  catch (error) {
407
- console.error('[NotificationService] Error showing notification:', error);
448
+ this.logError('Error showing notification:', error);
408
449
  throw error;
409
450
  }
410
451
  }
@@ -419,44 +460,29 @@ class ClipboardService extends BrowserApiBaseService {
419
460
  getApiName() {
420
461
  return 'clipboard';
421
462
  }
422
- async ensureClipboardPermission(action) {
423
- if (!('clipboard' in navigator)) {
424
- throw new Error('Clipboard API not supported in this browser');
425
- }
426
- const permissionStatus = await this.permissionsService.query({
427
- name: `clipboard-${action}`,
428
- });
429
- if (permissionStatus.state !== 'granted') {
430
- throw new Error(`Clipboard ${action} permission required. Please grant clipboard access and try again.`);
463
+ ensureSupported() {
464
+ super.ensureSupported();
465
+ if (!navigator.clipboard) {
466
+ throw new Error('Clipboard API not supported \u2014 a secure context (HTTPS) is required');
431
467
  }
432
468
  }
433
469
  async writeText(text) {
434
- await this.ensureClipboardPermission('write');
470
+ this.ensureSupported();
435
471
  try {
436
472
  await navigator.clipboard.writeText(text);
437
473
  }
438
474
  catch (error) {
439
- console.error('[ClipboardService] Error writing to clipboard:', error);
475
+ this.logError('Error writing to clipboard:', error);
440
476
  throw error;
441
477
  }
442
478
  }
443
479
  async readText() {
444
- await this.ensureClipboardPermission('read');
480
+ this.ensureSupported();
445
481
  try {
446
482
  return await navigator.clipboard.readText();
447
483
  }
448
484
  catch (error) {
449
- console.error('[ClipboardService] Error reading from clipboard:', error);
450
- throw error;
451
- }
452
- }
453
- async writeTextSecure(text) {
454
- await this.ensureClipboardPermission('write');
455
- try {
456
- await navigator.clipboard.writeText(text);
457
- }
458
- catch (error) {
459
- console.error('[ClipboardService] Error writing to clipboard:', error);
485
+ this.logError('Error reading from clipboard:', error);
460
486
  throw error;
461
487
  }
462
488
  }
@@ -628,23 +654,23 @@ class BatteryService extends BrowserApiBaseService {
628
654
  getApiName() {
629
655
  return 'battery';
630
656
  }
631
- ensureBatterySupport() {
657
+ ensureSupported() {
658
+ super.ensureSupported();
632
659
  const nav = navigator;
633
660
  if (!('getBattery' in nav)) {
634
- throw new Error('Battery API not supported in this browser');
661
+ throw new Error('Battery Status API not supported in this browser');
635
662
  }
636
663
  }
637
664
  async initialize() {
638
- this.ensureBatterySupport();
665
+ this.ensureSupported();
639
666
  try {
640
667
  const nav = navigator;
641
668
  this.batteryManager = await nav.getBattery();
642
669
  const batteryInfo = this.getBatteryInfo();
643
- this.setupEventListeners();
644
670
  return batteryInfo;
645
671
  }
646
672
  catch (error) {
647
- console.error('[BatteryService] Error initializing battery API:', error);
673
+ this.logError('Error initializing battery API:', error);
648
674
  throw this.createError('Failed to initialize battery API', error);
649
675
  }
650
676
  }
@@ -683,16 +709,6 @@ class BatteryService extends BrowserApiBaseService {
683
709
  };
684
710
  });
685
711
  }
686
- setupEventListeners() {
687
- if (!this.batteryManager)
688
- return;
689
- this.batteryManager.addEventListener('chargingchange', () => {
690
- console.log('[BatteryService] Charging status changed:', this.batteryManager.charging);
691
- });
692
- this.batteryManager.addEventListener('levelchange', () => {
693
- console.log('[BatteryService] Battery level changed:', this.batteryManager.level);
694
- });
695
- }
696
712
  // Direct access to native battery API
697
713
  getNativeBatteryManager() {
698
714
  if (!this.batteryManager) {
@@ -723,19 +739,20 @@ class WebShareService extends BrowserApiBaseService {
723
739
  getApiName() {
724
740
  return 'web-share';
725
741
  }
726
- ensureWebShareSupport() {
742
+ ensureSupported() {
743
+ super.ensureSupported();
727
744
  if (!('share' in navigator)) {
728
745
  throw new Error('Web Share API not supported in this browser');
729
746
  }
730
747
  }
731
748
  async share(data) {
732
- this.ensureWebShareSupport();
749
+ this.ensureSupported();
733
750
  try {
734
751
  await navigator.share(data);
735
752
  return { shared: true };
736
753
  }
737
754
  catch (error) {
738
- console.error('[WebShareService] Error sharing:', error);
755
+ this.logError('Error sharing:', error);
739
756
  const errorMessage = error instanceof Error ? error.message : 'Share failed';
740
757
  return { shared: false, error: errorMessage };
741
758
  }
@@ -752,7 +769,7 @@ class WebShareService extends BrowserApiBaseService {
752
769
  }
753
770
  // Direct access to native share API
754
771
  getNativeShare() {
755
- this.ensureWebShareSupport();
772
+ this.ensureSupported();
756
773
  return navigator.share;
757
774
  }
758
775
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebShareService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
@@ -764,7 +781,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
764
781
 
765
782
  class WebStorageService extends BrowserApiBaseService {
766
783
  storageEvents = signal(null, ...(ngDevMode ? [{ debugName: "storageEvents" }] : /* istanbul ignore next */ []));
767
- destroyRef = inject(DestroyRef);
768
784
  constructor() {
769
785
  super();
770
786
  this.setupEventListeners();
@@ -772,8 +788,9 @@ class WebStorageService extends BrowserApiBaseService {
772
788
  getApiName() {
773
789
  return 'storage';
774
790
  }
775
- ensureStorageSupport() {
776
- if (!this.isBrowserEnvironment() || typeof Storage === 'undefined') {
791
+ ensureSupported() {
792
+ super.ensureSupported();
793
+ if (typeof Storage === 'undefined') {
777
794
  throw new Error('Storage API not supported in this browser');
778
795
  }
779
796
  }
@@ -783,14 +800,13 @@ class WebStorageService extends BrowserApiBaseService {
783
800
  .pipe(takeUntilDestroyed(this.destroyRef))
784
801
  .subscribe((event) => {
785
802
  const storageEvent = event;
786
- if (storageEvent.key && storageEvent.newValue !== null) {
787
- this.storageEvents.set({
788
- key: storageEvent.key,
789
- newValue: this.deserializeValue(storageEvent.newValue),
790
- oldValue: storageEvent.oldValue ? this.deserializeValue(storageEvent.oldValue) : null,
791
- storageArea: storageEvent.storageArea === localStorage ? 'localStorage' : 'sessionStorage',
792
- });
793
- }
803
+ const area = storageEvent.storageArea === localStorage ? 'localStorage' : 'sessionStorage';
804
+ this.storageEvents.set({
805
+ key: storageEvent.key,
806
+ newValue: storageEvent.newValue ? this.deserializeValue(storageEvent.newValue) : null,
807
+ oldValue: storageEvent.oldValue ? this.deserializeValue(storageEvent.oldValue) : null,
808
+ storageArea: area,
809
+ });
794
810
  });
795
811
  }
796
812
  }
@@ -817,50 +833,58 @@ class WebStorageService extends BrowserApiBaseService {
817
833
  const prefix = options?.prefix || '';
818
834
  return prefix ? `${prefix}:${key}` : key;
819
835
  }
836
+ emitStorageChange(fullKey, newValue, oldValue, area) {
837
+ this.storageEvents.set({ key: fullKey, newValue, oldValue, storageArea: area });
838
+ }
820
839
  // Local Storage Methods
821
840
  setLocalStorage(key, value, options = {}) {
822
- this.ensureStorageSupport();
841
+ this.ensureSupported();
823
842
  try {
824
843
  const serializedValue = this.serializeValue(value, options);
825
844
  const fullKey = this.getKey(key, options);
845
+ const oldRaw = localStorage.getItem(fullKey);
846
+ const oldValue = oldRaw !== null ? this.deserializeValue(oldRaw, options) : null;
826
847
  localStorage.setItem(fullKey, serializedValue);
848
+ this.emitStorageChange(fullKey, value, oldValue, 'localStorage');
827
849
  return true;
828
850
  }
829
851
  catch (error) {
830
- console.error('[WebStorageService] Error setting localStorage:', error);
852
+ this.logError('Error setting localStorage:', error);
831
853
  return false;
832
854
  }
833
855
  }
834
856
  getLocalStorage(key, defaultValue = null, options = {}) {
835
- this.ensureStorageSupport();
857
+ this.ensureSupported();
836
858
  try {
837
859
  const fullKey = this.getKey(key, options);
838
860
  const value = localStorage.getItem(fullKey);
839
861
  return value !== null ? this.deserializeValue(value, options) : defaultValue;
840
862
  }
841
863
  catch (error) {
842
- console.error('[WebStorageService] Error getting localStorage:', error);
864
+ this.logError('Error getting localStorage:', error);
843
865
  return defaultValue;
844
866
  }
845
867
  }
846
868
  removeLocalStorage(key, options = {}) {
847
- this.ensureStorageSupport();
869
+ this.ensureSupported();
848
870
  try {
849
871
  const fullKey = this.getKey(key, options);
872
+ const oldRaw = localStorage.getItem(fullKey);
873
+ const oldValue = oldRaw !== null ? this.deserializeValue(oldRaw, options) : null;
850
874
  localStorage.removeItem(fullKey);
875
+ this.emitStorageChange(fullKey, null, oldValue, 'localStorage');
851
876
  return true;
852
877
  }
853
878
  catch (error) {
854
- console.error('[WebStorageService] Error removing localStorage:', error);
879
+ this.logError('Error removing localStorage:', error);
855
880
  return false;
856
881
  }
857
882
  }
858
883
  clearLocalStorage(options = {}) {
859
- this.ensureStorageSupport();
884
+ this.ensureSupported();
860
885
  try {
861
886
  const prefix = options?.prefix;
862
887
  if (prefix) {
863
- // Only remove keys with the specified prefix
864
888
  const keysToRemove = [];
865
889
  for (let i = 0; i < localStorage.length; i++) {
866
890
  const key = localStorage.key(i);
@@ -868,62 +892,72 @@ class WebStorageService extends BrowserApiBaseService {
868
892
  keysToRemove.push(key);
869
893
  }
870
894
  }
871
- keysToRemove.forEach((key) => localStorage.removeItem(key));
895
+ keysToRemove.forEach((key) => {
896
+ const oldRaw = localStorage.getItem(key);
897
+ localStorage.removeItem(key);
898
+ this.emitStorageChange(key, null, oldRaw, 'localStorage');
899
+ });
872
900
  }
873
901
  else {
874
902
  localStorage.clear();
903
+ this.emitStorageChange(null, null, null, 'localStorage');
875
904
  }
876
905
  return true;
877
906
  }
878
907
  catch (error) {
879
- console.error('[WebStorageService] Error clearing localStorage:', error);
908
+ this.logError('Error clearing localStorage:', error);
880
909
  return false;
881
910
  }
882
911
  }
883
912
  // Session Storage Methods
884
913
  setSessionStorage(key, value, options = {}) {
885
- this.ensureStorageSupport();
914
+ this.ensureSupported();
886
915
  try {
887
916
  const serializedValue = this.serializeValue(value, options);
888
917
  const fullKey = this.getKey(key, options);
918
+ const oldRaw = sessionStorage.getItem(fullKey);
919
+ const oldValue = oldRaw !== null ? this.deserializeValue(oldRaw, options) : null;
889
920
  sessionStorage.setItem(fullKey, serializedValue);
921
+ this.emitStorageChange(fullKey, value, oldValue, 'sessionStorage');
890
922
  return true;
891
923
  }
892
924
  catch (error) {
893
- console.error('[WebStorageService] Error setting sessionStorage:', error);
925
+ this.logError('Error setting sessionStorage:', error);
894
926
  return false;
895
927
  }
896
928
  }
897
929
  getSessionStorage(key, defaultValue = null, options = {}) {
898
- this.ensureStorageSupport();
930
+ this.ensureSupported();
899
931
  try {
900
932
  const fullKey = this.getKey(key, options);
901
933
  const value = sessionStorage.getItem(fullKey);
902
934
  return value !== null ? this.deserializeValue(value, options) : defaultValue;
903
935
  }
904
936
  catch (error) {
905
- console.error('[WebStorageService] Error getting sessionStorage:', error);
937
+ this.logError('Error getting sessionStorage:', error);
906
938
  return defaultValue;
907
939
  }
908
940
  }
909
941
  removeSessionStorage(key, options = {}) {
910
- this.ensureStorageSupport();
942
+ this.ensureSupported();
911
943
  try {
912
944
  const fullKey = this.getKey(key, options);
945
+ const oldRaw = sessionStorage.getItem(fullKey);
946
+ const oldValue = oldRaw !== null ? this.deserializeValue(oldRaw, options) : null;
913
947
  sessionStorage.removeItem(fullKey);
948
+ this.emitStorageChange(fullKey, null, oldValue, 'sessionStorage');
914
949
  return true;
915
950
  }
916
951
  catch (error) {
917
- console.error('[WebStorageService] Error removing sessionStorage:', error);
952
+ this.logError('Error removing sessionStorage:', error);
918
953
  return false;
919
954
  }
920
955
  }
921
956
  clearSessionStorage(options = {}) {
922
- this.ensureStorageSupport();
957
+ this.ensureSupported();
923
958
  try {
924
959
  const prefix = options?.prefix;
925
960
  if (prefix) {
926
- // Only remove keys with the specified prefix
927
961
  const keysToRemove = [];
928
962
  for (let i = 0; i < sessionStorage.length; i++) {
929
963
  const key = sessionStorage.key(i);
@@ -931,21 +965,26 @@ class WebStorageService extends BrowserApiBaseService {
931
965
  keysToRemove.push(key);
932
966
  }
933
967
  }
934
- keysToRemove.forEach((key) => sessionStorage.removeItem(key));
968
+ keysToRemove.forEach((key) => {
969
+ const oldRaw = sessionStorage.getItem(key);
970
+ sessionStorage.removeItem(key);
971
+ this.emitStorageChange(key, null, oldRaw, 'sessionStorage');
972
+ });
935
973
  }
936
974
  else {
937
975
  sessionStorage.clear();
976
+ this.emitStorageChange(null, null, null, 'sessionStorage');
938
977
  }
939
978
  return true;
940
979
  }
941
980
  catch (error) {
942
- console.error('[WebStorageService] Error clearing sessionStorage:', error);
981
+ this.logError('Error clearing sessionStorage:', error);
943
982
  return false;
944
983
  }
945
984
  }
946
985
  // Utility Methods
947
986
  getLocalStorageSize(options = {}) {
948
- this.ensureStorageSupport();
987
+ this.ensureSupported();
949
988
  let totalSize = 0;
950
989
  const prefix = options?.prefix;
951
990
  for (let i = 0; i < localStorage.length; i++) {
@@ -957,7 +996,7 @@ class WebStorageService extends BrowserApiBaseService {
957
996
  return totalSize;
958
997
  }
959
998
  getSessionStorageSize(options = {}) {
960
- this.ensureStorageSupport();
999
+ this.ensureSupported();
961
1000
  let totalSize = 0;
962
1001
  const prefix = options?.prefix;
963
1002
  for (let i = 0; i < sessionStorage.length; i++) {
@@ -974,30 +1013,20 @@ class WebStorageService extends BrowserApiBaseService {
974
1013
  prev.oldValue === curr.oldValue));
975
1014
  }
976
1015
  watchLocalStorage(key, options = {}) {
977
- return this.getStorageEvents().pipe(map((event) => {
978
- const fullKey = this.getKey(key, options);
979
- if (event.key === fullKey && event.storageArea === 'localStorage') {
980
- return event.newValue;
981
- }
982
- return this.getLocalStorage(key, null, options);
983
- }));
1016
+ const fullKey = this.getKey(key, options);
1017
+ return this.getStorageEvents().pipe(filter((event) => event.storageArea === 'localStorage' && (event.key === null || event.key === fullKey)), map((event) => event.newValue));
984
1018
  }
985
1019
  watchSessionStorage(key, options = {}) {
986
- return this.getStorageEvents().pipe(map((event) => {
987
- const fullKey = this.getKey(key, options);
988
- if (event.key === fullKey && event.storageArea === 'sessionStorage') {
989
- return event.newValue;
990
- }
991
- return this.getSessionStorage(key, null, options);
992
- }));
1020
+ const fullKey = this.getKey(key, options);
1021
+ return this.getStorageEvents().pipe(filter((event) => event.storageArea === 'sessionStorage' && (event.key === null || event.key === fullKey)), map((event) => event.newValue));
993
1022
  }
994
1023
  // Direct access to native storage APIs
995
1024
  getNativeLocalStorage() {
996
- this.ensureStorageSupport();
1025
+ this.ensureSupported();
997
1026
  return localStorage;
998
1027
  }
999
1028
  getNativeSessionStorage() {
1000
- this.ensureStorageSupport();
1029
+ this.ensureSupported();
1001
1030
  return sessionStorage;
1002
1031
  }
1003
1032
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -1009,21 +1038,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
1009
1038
 
1010
1039
  class WebSocketService extends BrowserApiBaseService {
1011
1040
  webSocket = null;
1012
- statusSubject = new Subject();
1041
+ statusSubject = new BehaviorSubject({
1042
+ connected: false,
1043
+ connecting: false,
1044
+ reconnecting: false,
1045
+ reconnectAttempts: 0,
1046
+ });
1013
1047
  messageSubject = new Subject();
1014
1048
  reconnectAttempts = 0;
1015
1049
  reconnectTimer = null;
1016
1050
  heartbeatTimer = null;
1051
+ _cleanup = this.destroyRef.onDestroy(() => this.disconnect());
1017
1052
  getApiName() {
1018
1053
  return 'websocket';
1019
1054
  }
1020
- ensureWebSocketSupport() {
1055
+ ensureSupported() {
1056
+ super.ensureSupported();
1021
1057
  if (typeof WebSocket === 'undefined') {
1022
1058
  throw new Error('WebSocket API not supported in this browser');
1023
1059
  }
1024
1060
  }
1025
1061
  connect(config) {
1026
- this.ensureWebSocketSupport();
1062
+ this.ensureSupported();
1027
1063
  return new Observable((observer) => {
1028
1064
  this.disconnect(); // Disconnect existing connection if any
1029
1065
  this.updateStatus({
@@ -1035,10 +1071,10 @@ class WebSocketService extends BrowserApiBaseService {
1035
1071
  try {
1036
1072
  this.webSocket = new WebSocket(config.url, config.protocols);
1037
1073
  this.setupWebSocketHandlers(config);
1038
- observer.next(this.getCurrentStatus());
1074
+ observer.next(this.statusSubject.getValue());
1039
1075
  }
1040
1076
  catch (error) {
1041
- console.error('[WebSocketService] Error creating WebSocket:', error);
1077
+ this.logError('Error creating WebSocket:', error);
1042
1078
  this.updateStatus({
1043
1079
  connected: false,
1044
1080
  connecting: false,
@@ -1046,7 +1082,7 @@ class WebSocketService extends BrowserApiBaseService {
1046
1082
  error: error instanceof Error ? error.message : 'Connection failed',
1047
1083
  reconnectAttempts: 0,
1048
1084
  });
1049
- observer.next(this.getCurrentStatus());
1085
+ observer.next(this.statusSubject.getValue());
1050
1086
  }
1051
1087
  return () => {
1052
1088
  this.disconnect();
@@ -1093,15 +1129,18 @@ class WebSocketService extends BrowserApiBaseService {
1093
1129
  return this.statusSubject.asObservable();
1094
1130
  }
1095
1131
  getMessages() {
1132
+ return this.messageSubject.asObservable();
1133
+ }
1134
+ getMessagesByType(type) {
1096
1135
  return this.messageSubject
1097
1136
  .asObservable()
1098
- .pipe(filter((msg) => true));
1137
+ .pipe(filter((msg) => msg.type === type));
1099
1138
  }
1100
1139
  setupWebSocketHandlers(config) {
1101
1140
  if (!this.webSocket)
1102
1141
  return;
1103
1142
  this.webSocket.onopen = () => {
1104
- console.log('[WebSocketService] Connected to:', config.url);
1143
+ this.logInfo(`Connected to: ${config.url}`);
1105
1144
  this.reconnectAttempts = 0;
1106
1145
  this.updateStatus({
1107
1146
  connected: true,
@@ -1115,7 +1154,7 @@ class WebSocketService extends BrowserApiBaseService {
1115
1154
  }
1116
1155
  };
1117
1156
  this.webSocket.onclose = (event) => {
1118
- console.log('[WebSocketService] Connection closed:', event.code, event.reason);
1157
+ this.logInfo(`Connection closed: ${event.code} ${event.reason}`);
1119
1158
  this.updateStatus({
1120
1159
  connected: false,
1121
1160
  connecting: false,
@@ -1128,7 +1167,7 @@ class WebSocketService extends BrowserApiBaseService {
1128
1167
  }
1129
1168
  };
1130
1169
  this.webSocket.onerror = (error) => {
1131
- console.error('[WebSocketService] WebSocket error:', error);
1170
+ this.logError('WebSocket error:', error);
1132
1171
  this.updateStatus({
1133
1172
  connected: false,
1134
1173
  connecting: false,
@@ -1143,7 +1182,7 @@ class WebSocketService extends BrowserApiBaseService {
1143
1182
  this.messageSubject.next(message);
1144
1183
  }
1145
1184
  catch (error) {
1146
- console.error('[WebSocketService] Error parsing message:', error);
1185
+ this.logError('Error parsing message:', error);
1147
1186
  }
1148
1187
  };
1149
1188
  }
@@ -1159,7 +1198,7 @@ class WebSocketService extends BrowserApiBaseService {
1159
1198
  }
1160
1199
  attemptReconnect(config) {
1161
1200
  if (this.reconnectAttempts >= (config.maxReconnectAttempts || 5)) {
1162
- console.log('[WebSocketService] Max reconnect attempts reached');
1201
+ this.logInfo('Max reconnect attempts reached');
1163
1202
  return;
1164
1203
  }
1165
1204
  this.reconnectAttempts++;
@@ -1170,23 +1209,14 @@ class WebSocketService extends BrowserApiBaseService {
1170
1209
  reconnectAttempts: this.reconnectAttempts,
1171
1210
  });
1172
1211
  this.reconnectTimer = setTimeout(() => {
1173
- console.log(`[WebSocketService] Reconnect attempt ${this.reconnectAttempts}`);
1212
+ this.logInfo(`Reconnect attempt ${this.reconnectAttempts}`);
1174
1213
  this.connect(config);
1175
1214
  }, config.reconnectInterval || 3000);
1176
1215
  }
1177
1216
  updateStatus(status) {
1178
- const currentStatus = this.getCurrentStatus();
1179
- const newStatus = { ...currentStatus, ...status };
1217
+ const newStatus = { ...this.statusSubject.getValue(), ...status };
1180
1218
  this.statusSubject.next(newStatus);
1181
1219
  }
1182
- getCurrentStatus() {
1183
- return {
1184
- connected: this.webSocket?.readyState === WebSocket.OPEN,
1185
- connecting: false,
1186
- reconnecting: false,
1187
- reconnectAttempts: this.reconnectAttempts,
1188
- };
1189
- }
1190
1220
  // Direct access to native WebSocket
1191
1221
  getNativeWebSocket() {
1192
1222
  return this.webSocket;
@@ -1205,21 +1235,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
1205
1235
  }] });
1206
1236
 
1207
1237
  class WebWorkerService extends BrowserApiBaseService {
1208
- destroyRef = inject(DestroyRef);
1209
1238
  workers = new Map();
1210
1239
  workerStatuses = new Map();
1211
1240
  workerMessages = new Map();
1212
1241
  currentWorkerStatuses = new Map();
1242
+ _cleanup = this.destroyRef.onDestroy(() => this.terminateAllWorkers());
1213
1243
  getApiName() {
1214
1244
  return 'webworker';
1215
1245
  }
1216
- ensureWorkerSupport() {
1246
+ ensureSupported() {
1247
+ super.ensureSupported();
1217
1248
  if (typeof Worker === 'undefined') {
1218
1249
  throw new Error('Web Workers not supported in this browser');
1219
1250
  }
1220
1251
  }
1221
1252
  createWorker(name, scriptUrl) {
1222
- this.ensureWorkerSupport();
1253
+ this.ensureSupported();
1223
1254
  return new Observable((observer) => {
1224
1255
  if (this.workers.has(name)) {
1225
1256
  observer.next(this.currentWorkerStatuses.get(name));
@@ -1241,7 +1272,7 @@ class WebWorkerService extends BrowserApiBaseService {
1241
1272
  observer.next(status);
1242
1273
  }
1243
1274
  catch (error) {
1244
- console.error(`[WebWorkerService] Failed to create worker ${name}:`, error);
1275
+ this.logError(`Failed to create worker ${name}:`, error);
1245
1276
  const status = {
1246
1277
  initialized: false,
1247
1278
  running: false,
@@ -1275,7 +1306,7 @@ class WebWorkerService extends BrowserApiBaseService {
1275
1306
  postMessage(workerName, task) {
1276
1307
  const worker = this.workers.get(workerName);
1277
1308
  if (!worker) {
1278
- console.error(`[WebWorkerService] Worker ${workerName} not found`);
1309
+ this.logError(`Worker ${workerName} not found`);
1279
1310
  return;
1280
1311
  }
1281
1312
  try {
@@ -1293,7 +1324,7 @@ class WebWorkerService extends BrowserApiBaseService {
1293
1324
  }
1294
1325
  }
1295
1326
  catch (error) {
1296
- console.error(`[WebWorkerService] Failed to post message to worker ${workerName}:`, error);
1327
+ this.logError(`Failed to post message to worker ${workerName}:`, error);
1297
1328
  }
1298
1329
  }
1299
1330
  getMessages(workerName) {
@@ -1332,7 +1363,7 @@ class WebWorkerService extends BrowserApiBaseService {
1332
1363
  this.workerMessages.get(name).next(message);
1333
1364
  };
1334
1365
  worker.onerror = (error) => {
1335
- console.error(`[WebWorkerService] Worker ${name} error:`, error);
1366
+ this.logError(`Worker ${name} error:`, error);
1336
1367
  const status = {
1337
1368
  initialized: true,
1338
1369
  running: false,
@@ -1394,10 +1425,12 @@ function intersectionObserverEntriesStream(element, options = {}) {
1394
1425
  });
1395
1426
  }
1396
1427
 
1397
- class IntersectionObserverService {
1398
- platformId = inject(PLATFORM_ID);
1428
+ class IntersectionObserverService extends BrowserApiBaseService {
1429
+ getApiName() {
1430
+ return 'intersection-observer';
1431
+ }
1399
1432
  isSupported() {
1400
- return isPlatformBrowser(this.platformId) && 'IntersectionObserver' in window;
1433
+ return this.isBrowserEnvironment() && 'IntersectionObserver' in window;
1401
1434
  }
1402
1435
  observe(element, options = {}) {
1403
1436
  if (!this.isSupported()) {
@@ -1411,7 +1444,7 @@ class IntersectionObserverService {
1411
1444
  }
1412
1445
  return intersectionObserverStream(element, options);
1413
1446
  }
1414
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IntersectionObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1447
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IntersectionObserverService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1415
1448
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IntersectionObserverService });
1416
1449
  }
1417
1450
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IntersectionObserverService, decorators: [{
@@ -1452,10 +1485,12 @@ function resizeObserverEntriesStream(element, options = {}) {
1452
1485
  });
1453
1486
  }
1454
1487
 
1455
- class ResizeObserverService {
1456
- platformId = inject(PLATFORM_ID);
1488
+ class ResizeObserverService extends BrowserApiBaseService {
1489
+ getApiName() {
1490
+ return 'resize-observer';
1491
+ }
1457
1492
  isSupported() {
1458
- return isPlatformBrowser(this.platformId) && 'ResizeObserver' in window;
1493
+ return this.isBrowserEnvironment() && 'ResizeObserver' in window;
1459
1494
  }
1460
1495
  observe(element, options = {}) {
1461
1496
  if (!this.isSupported()) {
@@ -1469,7 +1504,7 @@ class ResizeObserverService {
1469
1504
  }
1470
1505
  return resizeObserverStream(element, options);
1471
1506
  }
1472
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ResizeObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1507
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ResizeObserverService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1473
1508
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ResizeObserverService });
1474
1509
  }
1475
1510
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ResizeObserverService, decorators: [{
@@ -1491,10 +1526,12 @@ function pageVisibilityStream() {
1491
1526
  });
1492
1527
  }
1493
1528
 
1494
- class PageVisibilityService {
1495
- platformId = inject(PLATFORM_ID);
1529
+ class PageVisibilityService extends BrowserApiBaseService {
1530
+ getApiName() {
1531
+ return 'page-visibility';
1532
+ }
1496
1533
  isSupported() {
1497
- return isPlatformBrowser(this.platformId) && 'hidden' in document;
1534
+ return this.isBrowserEnvironment() && 'hidden' in document;
1498
1535
  }
1499
1536
  get isHidden() {
1500
1537
  if (!this.isSupported())
@@ -1512,32 +1549,79 @@ class PageVisibilityService {
1512
1549
  watchVisibility() {
1513
1550
  return pageVisibilityStream().pipe(map$1((s) => s === 'visible'));
1514
1551
  }
1515
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PageVisibilityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1552
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PageVisibilityService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1516
1553
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PageVisibilityService });
1517
1554
  }
1518
1555
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PageVisibilityService, decorators: [{
1519
1556
  type: Injectable
1520
1557
  }] });
1521
1558
 
1522
- class BroadcastChannelService {
1523
- destroyRef = inject(DestroyRef);
1524
- platformId = inject(PLATFORM_ID);
1525
- channels = new Map();
1559
+ /**
1560
+ * Base class for services that manage a named registry of persistent
1561
+ * connections (e.g. BroadcastChannel, EventSource, WebSocket pools).
1562
+ *
1563
+ * Implements the Template Method pattern: subclasses define how a single
1564
+ * native connection is closed via `closeNativeConnection()`, while this
1565
+ * class handles the Map lifecycle (remove, closeAll, getActiveKeys).
1566
+ *
1567
+ * Public-facing method names (`close`, `disconnect`, `getOpenChannels`, etc.)
1568
+ * remain the responsibility of the concrete service to preserve the public API.
1569
+ */
1570
+ class ConnectionRegistryBaseService extends BrowserApiBaseService {
1571
+ connections = new Map();
1572
+ /**
1573
+ * Remove and close the connection registered under `key`.
1574
+ * Safe to call even if the key does not exist.
1575
+ */
1576
+ removeConnection(key) {
1577
+ const connection = this.connections.get(key);
1578
+ if (connection) {
1579
+ this.closeNativeConnection(connection);
1580
+ this.connections.delete(key);
1581
+ }
1582
+ }
1583
+ /**
1584
+ * Close all registered connections and clear the registry.
1585
+ */
1586
+ closeAllConnections() {
1587
+ this.connections.forEach((connection) => this.closeNativeConnection(connection));
1588
+ this.connections.clear();
1589
+ }
1590
+ /**
1591
+ * Return the keys of all currently open connections.
1592
+ */
1593
+ getConnectionKeys() {
1594
+ return Array.from(this.connections.keys());
1595
+ }
1596
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ConnectionRegistryBaseService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1597
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ConnectionRegistryBaseService });
1598
+ }
1599
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ConnectionRegistryBaseService, decorators: [{
1600
+ type: Injectable
1601
+ }] });
1602
+
1603
+ class BroadcastChannelService extends ConnectionRegistryBaseService {
1604
+ getApiName() {
1605
+ return 'broadcast-channel';
1606
+ }
1607
+ closeNativeConnection(channel) {
1608
+ channel.close();
1609
+ }
1526
1610
  isSupported() {
1527
- return isPlatformBrowser(this.platformId) && 'BroadcastChannel' in window;
1611
+ return this.isBrowserEnvironment() && 'BroadcastChannel' in window;
1528
1612
  }
1529
- ensureSupport() {
1613
+ ensureBroadcastChannelSupported() {
1530
1614
  if (!this.isSupported()) {
1531
1615
  throw new Error('BroadcastChannel API not supported in this environment');
1532
1616
  }
1533
1617
  }
1534
1618
  open(name) {
1535
- this.ensureSupport();
1619
+ this.ensureBroadcastChannelSupported();
1536
1620
  return new Observable((observer) => {
1537
- let channel = this.channels.get(name);
1621
+ let channel = this.connections.get(name);
1538
1622
  if (!channel) {
1539
1623
  channel = new BroadcastChannel(name);
1540
- this.channels.set(name, channel);
1624
+ this.connections.set(name, channel);
1541
1625
  }
1542
1626
  const handler = (event) => observer.next(event.data);
1543
1627
  const errorHandler = () => observer.error(new Error(`BroadcastChannel "${name}" error`));
@@ -1552,30 +1636,25 @@ class BroadcastChannelService {
1552
1636
  });
1553
1637
  }
1554
1638
  post(name, data) {
1555
- this.ensureSupport();
1556
- let channel = this.channels.get(name);
1639
+ this.ensureBroadcastChannelSupported();
1640
+ let channel = this.connections.get(name);
1557
1641
  if (!channel) {
1558
1642
  channel = new BroadcastChannel(name);
1559
- this.channels.set(name, channel);
1643
+ this.connections.set(name, channel);
1560
1644
  this.destroyRef.onDestroy(() => this.close(name));
1561
1645
  }
1562
1646
  channel.postMessage(data);
1563
1647
  }
1564
1648
  close(name) {
1565
- const channel = this.channels.get(name);
1566
- if (channel) {
1567
- channel.close();
1568
- this.channels.delete(name);
1569
- }
1649
+ this.removeConnection(name);
1570
1650
  }
1571
1651
  closeAll() {
1572
- this.channels.forEach((channel) => channel.close());
1573
- this.channels.clear();
1652
+ this.closeAllConnections();
1574
1653
  }
1575
1654
  getOpenChannels() {
1576
- return Array.from(this.channels.keys());
1655
+ return this.getConnectionKeys();
1577
1656
  }
1578
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BroadcastChannelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1657
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BroadcastChannelService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1579
1658
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BroadcastChannelService });
1580
1659
  }
1581
1660
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BroadcastChannelService, decorators: [{
@@ -1627,21 +1706,23 @@ function networkInformationStream() {
1627
1706
  });
1628
1707
  }
1629
1708
 
1630
- class NetworkInformationService {
1631
- platformId = inject(PLATFORM_ID);
1709
+ class NetworkInformationService extends BrowserApiBaseService {
1710
+ getApiName() {
1711
+ return 'network-information';
1712
+ }
1632
1713
  isSupported() {
1633
- return isPlatformBrowser(this.platformId) && isNetworkInformationSupported();
1714
+ return this.isBrowserEnvironment() && isNetworkInformationSupported();
1634
1715
  }
1635
1716
  getSnapshot() {
1636
- return isPlatformBrowser(this.platformId) ? getNetworkSnapshot() : { online: true };
1717
+ return this.isBrowserEnvironment() ? getNetworkSnapshot() : { online: true };
1637
1718
  }
1638
1719
  watch() {
1639
1720
  return networkInformationStream();
1640
1721
  }
1641
1722
  get isOnline() {
1642
- return isPlatformBrowser(this.platformId) ? navigator.onLine : true;
1723
+ return this.isBrowserEnvironment() ? navigator.onLine : true;
1643
1724
  }
1644
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NetworkInformationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1725
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NetworkInformationService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1645
1726
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NetworkInformationService });
1646
1727
  }
1647
1728
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NetworkInformationService, decorators: [{
@@ -1654,7 +1735,7 @@ class ScreenWakeLockService extends BrowserApiBaseService {
1654
1735
  return 'screen-wake-lock';
1655
1736
  }
1656
1737
  isSupported() {
1657
- return isPlatformBrowser(this.platformId) && 'wakeLock' in navigator;
1738
+ return this.isBrowserEnvironment() && 'wakeLock' in navigator;
1658
1739
  }
1659
1740
  get isActive() {
1660
1741
  return this.sentinel !== null && !this.sentinel.released;
@@ -1675,7 +1756,7 @@ class ScreenWakeLockService extends BrowserApiBaseService {
1675
1756
  return { active: true, type, released: false };
1676
1757
  }
1677
1758
  catch (error) {
1678
- console.error('[ScreenWakeLockService] Failed to acquire wake lock:', error);
1759
+ this.logError('Failed to acquire wake lock:', error);
1679
1760
  throw this.createError('Failed to acquire wake lock', error);
1680
1761
  }
1681
1762
  }
@@ -1744,13 +1825,15 @@ function screenOrientationStream() {
1744
1825
  });
1745
1826
  }
1746
1827
 
1747
- class ScreenOrientationService {
1748
- platformId = inject(PLATFORM_ID);
1828
+ class ScreenOrientationService extends BrowserApiBaseService {
1829
+ getApiName() {
1830
+ return 'screen-orientation';
1831
+ }
1749
1832
  isSupported() {
1750
- return isPlatformBrowser(this.platformId) && 'screen' in window && 'orientation' in screen;
1833
+ return this.isBrowserEnvironment() && 'screen' in window && 'orientation' in screen;
1751
1834
  }
1752
1835
  getSnapshot() {
1753
- return isPlatformBrowser(this.platformId)
1836
+ return this.isBrowserEnvironment()
1754
1837
  ? getOrientationSnapshot()
1755
1838
  : { type: 'portrait-primary', angle: 0 };
1756
1839
  }
@@ -1771,7 +1854,7 @@ class ScreenOrientationService {
1771
1854
  await screen.orientation.lock(orientation);
1772
1855
  }
1773
1856
  catch (error) {
1774
- console.error('[ScreenOrientationService] Failed to lock orientation:', error);
1857
+ this.logError('Failed to lock orientation:', error);
1775
1858
  throw error;
1776
1859
  }
1777
1860
  }
@@ -1780,30 +1863,31 @@ class ScreenOrientationService {
1780
1863
  screen.orientation.unlock();
1781
1864
  }
1782
1865
  }
1783
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenOrientationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1866
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenOrientationService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1784
1867
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenOrientationService });
1785
1868
  }
1786
1869
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenOrientationService, decorators: [{
1787
1870
  type: Injectable
1788
1871
  }] });
1789
1872
 
1790
- class FullscreenService {
1791
- destroyRef = inject(DestroyRef);
1792
- platformId = inject(PLATFORM_ID);
1873
+ class FullscreenService extends BrowserApiBaseService {
1874
+ getApiName() {
1875
+ return 'fullscreen';
1876
+ }
1793
1877
  isSupported() {
1794
- if (!isPlatformBrowser(this.platformId))
1878
+ if (!this.isBrowserEnvironment())
1795
1879
  return false;
1796
1880
  return !!(document.fullscreenEnabled ??
1797
1881
  document.webkitFullscreenEnabled);
1798
1882
  }
1799
1883
  get isFullscreen() {
1800
- if (!isPlatformBrowser(this.platformId))
1884
+ if (!this.isBrowserEnvironment())
1801
1885
  return false;
1802
1886
  return !!(document.fullscreenElement ??
1803
1887
  document.webkitFullscreenElement);
1804
1888
  }
1805
1889
  get fullscreenElement() {
1806
- if (!isPlatformBrowser(this.platformId))
1890
+ if (!this.isBrowserEnvironment())
1807
1891
  return null;
1808
1892
  return (document.fullscreenElement ??
1809
1893
  document.webkitFullscreenElement ??
@@ -1823,7 +1907,7 @@ class FullscreenService {
1823
1907
  }
1824
1908
  }
1825
1909
  catch (error) {
1826
- console.error('[FullscreenService] Failed to enter fullscreen:', error);
1910
+ this.logError('Failed to enter fullscreen:', error);
1827
1911
  throw error;
1828
1912
  }
1829
1913
  }
@@ -1840,7 +1924,7 @@ class FullscreenService {
1840
1924
  }
1841
1925
  }
1842
1926
  catch (error) {
1843
- console.error('[FullscreenService] Failed to exit fullscreen:', error);
1927
+ this.logError('Failed to exit fullscreen:', error);
1844
1928
  throw error;
1845
1929
  }
1846
1930
  }
@@ -1854,7 +1938,7 @@ class FullscreenService {
1854
1938
  }
1855
1939
  watch() {
1856
1940
  return new Observable((observer) => {
1857
- if (!isPlatformBrowser(this.platformId)) {
1941
+ if (!this.isBrowserEnvironment()) {
1858
1942
  observer.next(false);
1859
1943
  observer.complete();
1860
1944
  return undefined;
@@ -1871,7 +1955,7 @@ class FullscreenService {
1871
1955
  return cleanup;
1872
1956
  });
1873
1957
  }
1874
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FullscreenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1958
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FullscreenService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1875
1959
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FullscreenService });
1876
1960
  }
1877
1961
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FullscreenService, decorators: [{
@@ -1888,10 +1972,8 @@ class FileSystemAccessService extends BrowserApiBaseService {
1888
1972
  get win() {
1889
1973
  return window;
1890
1974
  }
1891
- ensureSupport() {
1892
- if (this.isServerEnvironment()) {
1893
- throw new Error('File System Access API not available in server environment');
1894
- }
1975
+ ensureSupported() {
1976
+ super.ensureSupported();
1895
1977
  if (!('showOpenFilePicker' in window)) {
1896
1978
  throw new Error('File System Access API not supported in this browser');
1897
1979
  }
@@ -1900,7 +1982,7 @@ class FileSystemAccessService extends BrowserApiBaseService {
1900
1982
  }
1901
1983
  }
1902
1984
  async openFile(options = {}) {
1903
- this.ensureSupport();
1985
+ this.ensureSupported();
1904
1986
  try {
1905
1987
  const handles = await this.win.showOpenFilePicker(options);
1906
1988
  return Promise.all(handles.map((h) => h.getFile()));
@@ -1909,12 +1991,12 @@ class FileSystemAccessService extends BrowserApiBaseService {
1909
1991
  if (error instanceof DOMException && error.name === 'AbortError') {
1910
1992
  return [];
1911
1993
  }
1912
- console.error('[FileSystemAccessService] Error opening file:', error);
1994
+ this.logError('Error opening file:', error);
1913
1995
  throw error;
1914
1996
  }
1915
1997
  }
1916
1998
  async saveFile(content, options = {}) {
1917
- this.ensureSupport();
1999
+ this.ensureSupported();
1918
2000
  if (!this.win.showSaveFilePicker) {
1919
2001
  throw new Error('showSaveFilePicker not supported');
1920
2002
  }
@@ -1928,12 +2010,12 @@ class FileSystemAccessService extends BrowserApiBaseService {
1928
2010
  if (error instanceof DOMException && error.name === 'AbortError') {
1929
2011
  return;
1930
2012
  }
1931
- console.error('[FileSystemAccessService] Error saving file:', error);
2013
+ this.logError('Error saving file:', error);
1932
2014
  throw error;
1933
2015
  }
1934
2016
  }
1935
2017
  async openDirectory(options = {}) {
1936
- this.ensureSupport();
2018
+ this.ensureSupported();
1937
2019
  if (!this.win.showDirectoryPicker) {
1938
2020
  throw new Error('showDirectoryPicker not supported');
1939
2021
  }
@@ -1944,7 +2026,7 @@ class FileSystemAccessService extends BrowserApiBaseService {
1944
2026
  if (error instanceof DOMException && error.name === 'AbortError') {
1945
2027
  return null;
1946
2028
  }
1947
- console.error('[FileSystemAccessService] Error opening directory:', error);
2029
+ this.logError('Error opening directory:', error);
1948
2030
  throw error;
1949
2031
  }
1950
2032
  }
@@ -2011,7 +2093,7 @@ class MediaRecorderService extends BrowserApiBaseService {
2011
2093
  this.recorder.start(timeslice);
2012
2094
  }
2013
2095
  catch (error) {
2014
- console.error('[MediaRecorderService] Failed to start recording:', error);
2096
+ this.logError('Failed to start recording:', error);
2015
2097
  throw this.createError('Failed to start recording', error);
2016
2098
  }
2017
2099
  }
@@ -2054,23 +2136,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2054
2136
  type: Injectable
2055
2137
  }] });
2056
2138
 
2057
- class ServerSentEventsService {
2058
- destroyRef = inject(DestroyRef);
2059
- platformId = inject(PLATFORM_ID);
2060
- sources = new Map();
2139
+ class ServerSentEventsService extends ConnectionRegistryBaseService {
2140
+ getApiName() {
2141
+ return 'server-sent-events';
2142
+ }
2143
+ closeNativeConnection(source) {
2144
+ source.close();
2145
+ }
2061
2146
  isSupported() {
2062
- return isPlatformBrowser(this.platformId) && 'EventSource' in window;
2147
+ return this.isBrowserEnvironment() && 'EventSource' in window;
2063
2148
  }
2064
- ensureSupport() {
2149
+ ensureSSESupported() {
2065
2150
  if (!this.isSupported()) {
2066
2151
  throw new Error('Server-Sent Events (EventSource) not supported in this environment');
2067
2152
  }
2068
2153
  }
2069
2154
  connect(url, config = {}) {
2070
- this.ensureSupport();
2155
+ this.ensureSSESupported();
2071
2156
  return new Observable((observer) => {
2072
2157
  const source = new EventSource(url, { withCredentials: config.withCredentials ?? false });
2073
- this.sources.set(url, source);
2158
+ this.connections.set(url, source);
2074
2159
  const messageHandler = (event) => {
2075
2160
  try {
2076
2161
  observer.next({
@@ -2094,7 +2179,7 @@ class ServerSentEventsService {
2094
2179
  observer.error(new Error('SSE connection closed unexpectedly'));
2095
2180
  }
2096
2181
  else {
2097
- console.warn('[ServerSentEventsService] SSE connection error, reconnecting...', event);
2182
+ this.logWarn('SSE connection error, reconnecting...');
2098
2183
  }
2099
2184
  };
2100
2185
  source.addEventListener('message', messageHandler);
@@ -2112,35 +2197,32 @@ class ServerSentEventsService {
2112
2197
  });
2113
2198
  }
2114
2199
  disconnect(url) {
2115
- const source = this.sources.get(url);
2116
- if (source) {
2117
- source.close();
2118
- this.sources.delete(url);
2119
- }
2200
+ this.removeConnection(url);
2120
2201
  }
2121
2202
  disconnectAll() {
2122
- this.sources.forEach((source) => source.close());
2123
- this.sources.clear();
2203
+ this.closeAllConnections();
2124
2204
  }
2125
2205
  getState(url) {
2126
- const source = this.sources.get(url);
2206
+ const source = this.connections.get(url);
2127
2207
  if (!source)
2128
2208
  return 'closed';
2129
2209
  const states = ['connecting', 'open', 'closed'];
2130
2210
  return states[source.readyState] ?? 'closed';
2131
2211
  }
2132
2212
  getActiveConnections() {
2133
- return Array.from(this.sources.keys());
2213
+ return this.getConnectionKeys();
2134
2214
  }
2135
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ServerSentEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2215
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ServerSentEventsService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2136
2216
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ServerSentEventsService });
2137
2217
  }
2138
2218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ServerSentEventsService, decorators: [{
2139
2219
  type: Injectable
2140
2220
  }] });
2141
2221
 
2142
- class VibrationService {
2143
- platformId = inject(PLATFORM_ID);
2222
+ class VibrationService extends BrowserApiBaseService {
2223
+ getApiName() {
2224
+ return 'vibration';
2225
+ }
2144
2226
  presets = {
2145
2227
  success: [50, 30, 50],
2146
2228
  error: [100, 50, 100, 50, 100],
@@ -2148,7 +2230,7 @@ class VibrationService {
2148
2230
  doubleTap: [50, 100, 50],
2149
2231
  };
2150
2232
  isSupported() {
2151
- return isPlatformBrowser(this.platformId) && 'vibrate' in navigator;
2233
+ return this.isBrowserEnvironment() && 'vibrate' in navigator;
2152
2234
  }
2153
2235
  vibrate(pattern = 200) {
2154
2236
  if (!this.isSupported())
@@ -2170,20 +2252,21 @@ class VibrationService {
2170
2252
  stop() {
2171
2253
  return this.vibrate(0);
2172
2254
  }
2173
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: VibrationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2255
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: VibrationService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2174
2256
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: VibrationService });
2175
2257
  }
2176
2258
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: VibrationService, decorators: [{
2177
2259
  type: Injectable
2178
2260
  }] });
2179
2261
 
2180
- class SpeechSynthesisService {
2181
- destroyRef = inject(DestroyRef);
2182
- platformId = inject(PLATFORM_ID);
2262
+ class SpeechSynthesisService extends BrowserApiBaseService {
2263
+ getApiName() {
2264
+ return 'speech-synthesis';
2265
+ }
2183
2266
  isSupported() {
2184
- return isPlatformBrowser(this.platformId) && 'speechSynthesis' in window;
2267
+ return this.isBrowserEnvironment() && 'speechSynthesis' in window;
2185
2268
  }
2186
- ensureSupport() {
2269
+ ensureSpeechSynthesisSupported() {
2187
2270
  if (!this.isSupported()) {
2188
2271
  throw new Error('Speech Synthesis API not supported in this browser');
2189
2272
  }
@@ -2222,7 +2305,7 @@ class SpeechSynthesisService {
2222
2305
  }
2223
2306
  speak(text, options = {}) {
2224
2307
  return new Observable((observer) => {
2225
- this.ensureSupport();
2308
+ this.ensureSpeechSynthesisSupported();
2226
2309
  const utterance = new SpeechSynthesisUtterance(text);
2227
2310
  if (options.lang)
2228
2311
  utterance.lang = options.lang;
@@ -2266,7 +2349,7 @@ class SpeechSynthesisService {
2266
2349
  if (this.isSupported())
2267
2350
  speechSynthesis.cancel();
2268
2351
  }
2269
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SpeechSynthesisService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2352
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SpeechSynthesisService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2270
2353
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SpeechSynthesisService });
2271
2354
  }
2272
2355
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SpeechSynthesisService, decorators: [{
@@ -2292,10 +2375,12 @@ function mutationObserverStream(element, options = DEFAULT_OPTIONS) {
2292
2375
  });
2293
2376
  }
2294
2377
 
2295
- class MutationObserverService {
2296
- platformId = inject(PLATFORM_ID);
2378
+ class MutationObserverService extends BrowserApiBaseService {
2379
+ getApiName() {
2380
+ return 'mutation-observer';
2381
+ }
2297
2382
  isSupported() {
2298
- return isPlatformBrowser(this.platformId) && isMutationObserverSupported();
2383
+ return this.isBrowserEnvironment() && isMutationObserverSupported();
2299
2384
  }
2300
2385
  observe(target, options) {
2301
2386
  if (!this.isSupported()) {
@@ -2303,7 +2388,7 @@ class MutationObserverService {
2303
2388
  }
2304
2389
  return mutationObserverStream(target, options);
2305
2390
  }
2306
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2391
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2307
2392
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService });
2308
2393
  }
2309
2394
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService, decorators: [{
@@ -2328,10 +2413,12 @@ function performanceObserverStream(config) {
2328
2413
  });
2329
2414
  }
2330
2415
 
2331
- class PerformanceObserverService {
2332
- platformId = inject(PLATFORM_ID);
2416
+ class PerformanceObserverService extends BrowserApiBaseService {
2417
+ getApiName() {
2418
+ return 'performance-observer';
2419
+ }
2333
2420
  isSupported() {
2334
- return isPlatformBrowser(this.platformId) && isPerformanceObserverSupported();
2421
+ return this.isBrowserEnvironment() && isPerformanceObserverSupported();
2335
2422
  }
2336
2423
  observe(config) {
2337
2424
  if (!this.isSupported()) {
@@ -2347,7 +2434,7 @@ class PerformanceObserverService {
2347
2434
  return [];
2348
2435
  return (PerformanceObserver.supportedEntryTypes ?? []);
2349
2436
  }
2350
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2437
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2351
2438
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService });
2352
2439
  }
2353
2440
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService, decorators: [{
@@ -2357,10 +2444,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2357
2444
  function getIdleDetectorClass$1() {
2358
2445
  return window.IdleDetector;
2359
2446
  }
2360
- class IdleDetectorService {
2361
- platformId = inject(PLATFORM_ID);
2447
+ class IdleDetectorService extends BrowserApiBaseService {
2448
+ getApiName() {
2449
+ return 'idle-detector';
2450
+ }
2362
2451
  isSupported() {
2363
- return isPlatformBrowser(this.platformId) && 'IdleDetector' in window;
2452
+ return this.isBrowserEnvironment() && 'IdleDetector' in window;
2364
2453
  }
2365
2454
  async requestPermission() {
2366
2455
  if (!this.isSupported()) {
@@ -2390,7 +2479,7 @@ class IdleDetectorService {
2390
2479
  return () => abortController.abort();
2391
2480
  });
2392
2481
  }
2393
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2482
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2394
2483
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService });
2395
2484
  }
2396
2485
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, decorators: [{
@@ -2400,10 +2489,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2400
2489
  function getEyeDropperClass() {
2401
2490
  return window.EyeDropper;
2402
2491
  }
2403
- class EyeDropperService {
2404
- platformId = inject(PLATFORM_ID);
2492
+ class EyeDropperService extends BrowserApiBaseService {
2493
+ getApiName() {
2494
+ return 'eye-dropper';
2495
+ }
2405
2496
  isSupported() {
2406
- return isPlatformBrowser(this.platformId) && 'EyeDropper' in window;
2497
+ return this.isBrowserEnvironment() && 'EyeDropper' in window;
2407
2498
  }
2408
2499
  async open(signal) {
2409
2500
  if (!this.isSupported()) {
@@ -2412,7 +2503,7 @@ class EyeDropperService {
2412
2503
  const dropper = new (getEyeDropperClass())();
2413
2504
  return dropper.open(signal ? { signal } : undefined);
2414
2505
  }
2415
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2506
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2416
2507
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService });
2417
2508
  }
2418
2509
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, decorators: [{
@@ -2422,10 +2513,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2422
2513
  function getBarcodeDetectorClass() {
2423
2514
  return window.BarcodeDetector;
2424
2515
  }
2425
- class BarcodeDetectorService {
2426
- platformId = inject(PLATFORM_ID);
2516
+ class BarcodeDetectorService extends BrowserApiBaseService {
2517
+ getApiName() {
2518
+ return 'barcode-detector';
2519
+ }
2427
2520
  isSupported() {
2428
- return isPlatformBrowser(this.platformId) && 'BarcodeDetector' in window;
2521
+ return this.isBrowserEnvironment() && 'BarcodeDetector' in window;
2429
2522
  }
2430
2523
  async getSupportedFormats() {
2431
2524
  if (!this.isSupported())
@@ -2441,19 +2534,20 @@ class BarcodeDetectorService {
2441
2534
  : new (getBarcodeDetectorClass())();
2442
2535
  return detector.detect(image);
2443
2536
  }
2444
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2537
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2445
2538
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService });
2446
2539
  }
2447
2540
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, decorators: [{
2448
2541
  type: Injectable
2449
2542
  }] });
2450
2543
 
2451
- class WebAudioService {
2452
- platformId = inject(PLATFORM_ID);
2453
- destroyRef = inject(DestroyRef);
2544
+ class WebAudioService extends BrowserApiBaseService {
2545
+ getApiName() {
2546
+ return 'web-audio';
2547
+ }
2454
2548
  context = null;
2455
2549
  isSupported() {
2456
- return isPlatformBrowser(this.platformId) && 'AudioContext' in window;
2550
+ return this.isBrowserEnvironment() && 'AudioContext' in window;
2457
2551
  }
2458
2552
  getContext() {
2459
2553
  if (!this.isSupported()) {
@@ -2527,7 +2621,7 @@ class WebAudioService {
2527
2621
  source.start(0);
2528
2622
  return source;
2529
2623
  }
2530
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2624
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2531
2625
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService });
2532
2626
  }
2533
2627
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService, decorators: [{
@@ -2610,10 +2704,12 @@ function gamepadPollStream(index, intervalMs = 16) {
2610
2704
  });
2611
2705
  }
2612
2706
 
2613
- class GamepadService {
2614
- platformId = inject(PLATFORM_ID);
2707
+ class GamepadService extends BrowserApiBaseService {
2708
+ getApiName() {
2709
+ return 'gamepad';
2710
+ }
2615
2711
  isSupported() {
2616
- return isPlatformBrowser(this.platformId) && isGamepadSupported();
2712
+ return this.isBrowserEnvironment() && isGamepadSupported();
2617
2713
  }
2618
2714
  getSnapshot(index) {
2619
2715
  if (!this.isSupported())
@@ -2647,7 +2743,7 @@ class GamepadService {
2647
2743
  }
2648
2744
  return gamepadPollStream(index, intervalMs);
2649
2745
  }
2650
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2746
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2651
2747
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService });
2652
2748
  }
2653
2749
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService, decorators: [{
@@ -2657,10 +2753,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2657
2753
  function getBluetooth() {
2658
2754
  return navigator.bluetooth;
2659
2755
  }
2660
- class WebBluetoothService {
2661
- platformId = inject(PLATFORM_ID);
2756
+ class WebBluetoothService extends BrowserApiBaseService {
2757
+ getApiName() {
2758
+ return 'web-bluetooth';
2759
+ }
2662
2760
  isSupported() {
2663
- return isPlatformBrowser(this.platformId) && !!getBluetooth();
2761
+ return this.isBrowserEnvironment() && !!getBluetooth();
2664
2762
  }
2665
2763
  async requestDevice(options = { acceptAllDevices: true }) {
2666
2764
  if (!this.isSupported()) {
@@ -2716,7 +2814,7 @@ class WebBluetoothService {
2716
2814
  };
2717
2815
  });
2718
2816
  }
2719
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2817
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2720
2818
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService });
2721
2819
  }
2722
2820
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, decorators: [{
@@ -2726,10 +2824,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2726
2824
  function getUsb() {
2727
2825
  return navigator.usb;
2728
2826
  }
2729
- class WebUsbService {
2730
- platformId = inject(PLATFORM_ID);
2827
+ class WebUsbService extends BrowserApiBaseService {
2828
+ getApiName() {
2829
+ return 'web-usb';
2830
+ }
2731
2831
  isSupported() {
2732
- return isPlatformBrowser(this.platformId) && !!getUsb();
2832
+ return this.isBrowserEnvironment() && !!getUsb();
2733
2833
  }
2734
2834
  async requestDevice(filters = []) {
2735
2835
  if (!this.isSupported()) {
@@ -2789,7 +2889,7 @@ class WebUsbService {
2789
2889
  opened: device.opened,
2790
2890
  };
2791
2891
  }
2792
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2892
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2793
2893
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService });
2794
2894
  }
2795
2895
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, decorators: [{
@@ -2799,10 +2899,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2799
2899
  function getNdefReaderClass() {
2800
2900
  return window.NDEFReader;
2801
2901
  }
2802
- class WebNfcService {
2803
- platformId = inject(PLATFORM_ID);
2902
+ class WebNfcService extends BrowserApiBaseService {
2903
+ getApiName() {
2904
+ return 'web-nfc';
2905
+ }
2804
2906
  isSupported() {
2805
- return isPlatformBrowser(this.platformId) && 'NDEFReader' in window;
2907
+ return this.isBrowserEnvironment() && 'NDEFReader' in window;
2806
2908
  }
2807
2909
  scan() {
2808
2910
  if (!this.isSupported()) {
@@ -2836,17 +2938,19 @@ class WebNfcService {
2836
2938
  const reader = new (getNdefReaderClass())();
2837
2939
  await reader.write(message, options);
2838
2940
  }
2839
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2941
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2840
2942
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService });
2841
2943
  }
2842
2944
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, decorators: [{
2843
2945
  type: Injectable
2844
2946
  }] });
2845
2947
 
2846
- class PaymentRequestService {
2847
- platformId = inject(PLATFORM_ID);
2948
+ class PaymentRequestService extends BrowserApiBaseService {
2949
+ getApiName() {
2950
+ return 'payment-request';
2951
+ }
2848
2952
  isSupported() {
2849
- return isPlatformBrowser(this.platformId) && 'PaymentRequest' in window;
2953
+ return this.isBrowserEnvironment() && 'PaymentRequest' in window;
2850
2954
  }
2851
2955
  async canMakePayment(methods, details) {
2852
2956
  if (!this.isSupported())
@@ -2876,17 +2980,19 @@ class PaymentRequestService {
2876
2980
  const request = new PaymentRequest(methods, details);
2877
2981
  await request.abort();
2878
2982
  }
2879
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2983
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2880
2984
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService });
2881
2985
  }
2882
2986
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, decorators: [{
2883
2987
  type: Injectable
2884
2988
  }] });
2885
2989
 
2886
- class CredentialManagementService {
2887
- platformId = inject(PLATFORM_ID);
2990
+ class CredentialManagementService extends BrowserApiBaseService {
2991
+ getApiName() {
2992
+ return 'credential-management';
2993
+ }
2888
2994
  isSupported() {
2889
- return isPlatformBrowser(this.platformId) && 'credentials' in navigator;
2995
+ return this.isBrowserEnvironment() && 'credentials' in navigator;
2890
2996
  }
2891
2997
  isPublicKeySupported() {
2892
2998
  return this.isSupported() && 'PublicKeyCredential' in window;
@@ -2932,7 +3038,7 @@ class CredentialManagementService {
2932
3038
  }
2933
3039
  return false;
2934
3040
  }
2935
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3041
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2936
3042
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService });
2937
3043
  }
2938
3044
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, decorators: [{
@@ -3268,218 +3374,253 @@ const permissionGuard = (permission) => {
3268
3374
  };
3269
3375
  };
3270
3376
 
3271
- const defaultBrowserWebApisConfig = {
3272
- enableCamera: true,
3273
- enableGeolocation: true,
3274
- enableNotifications: true,
3275
- enableClipboard: true,
3276
- enableBattery: false,
3277
- enableMediaDevices: true,
3278
- enableWebShare: false,
3279
- enableWebStorage: false,
3280
- enableWebSocket: false,
3281
- enableWebWorker: false,
3282
- enableIntersectionObserver: false,
3283
- enableResizeObserver: false,
3284
- enablePageVisibility: false,
3285
- enableBroadcastChannel: false,
3286
- enableNetworkInformation: false,
3287
- enableScreenWakeLock: false,
3288
- enableScreenOrientation: false,
3289
- enableFullscreen: false,
3290
- enableFileSystemAccess: false,
3291
- enableMediaRecorder: false,
3292
- enableServerSentEvents: false,
3293
- enableVibration: false,
3294
- enableSpeechSynthesis: false,
3295
- enableMutationObserver: false,
3296
- enablePerformanceObserver: false,
3297
- enableIdleDetector: false,
3298
- enableEyeDropper: false,
3299
- enableBarcodeDetector: false,
3300
- enableWebAudio: false,
3301
- enableGamepad: false,
3302
- enableWebBluetooth: false,
3303
- enableWebUsb: false,
3304
- enableWebNfc: false,
3305
- enablePaymentRequest: false,
3306
- enableCredentialManagement: false,
3307
- };
3308
- function provideBrowserWebApis(config = {}) {
3309
- const mergedConfig = { ...defaultBrowserWebApisConfig, ...config };
3310
- const providers = [PermissionsService];
3311
- const conditionalProviders = [
3312
- [mergedConfig.enableCamera, CameraService],
3313
- [mergedConfig.enableGeolocation, GeolocationService],
3314
- [mergedConfig.enableNotifications, NotificationService],
3315
- [mergedConfig.enableClipboard, ClipboardService],
3316
- [mergedConfig.enableMediaDevices, MediaDevicesService],
3317
- [mergedConfig.enableBattery, BatteryService],
3318
- [mergedConfig.enableWebShare, WebShareService],
3319
- [mergedConfig.enableWebStorage, WebStorageService],
3320
- [mergedConfig.enableWebSocket, WebSocketService],
3321
- [mergedConfig.enableWebWorker, WebWorkerService],
3322
- [mergedConfig.enableIntersectionObserver, IntersectionObserverService],
3323
- [mergedConfig.enableResizeObserver, ResizeObserverService],
3324
- [mergedConfig.enablePageVisibility, PageVisibilityService],
3325
- [mergedConfig.enableBroadcastChannel, BroadcastChannelService],
3326
- [mergedConfig.enableNetworkInformation, NetworkInformationService],
3327
- [mergedConfig.enableScreenWakeLock, ScreenWakeLockService],
3328
- [mergedConfig.enableScreenOrientation, ScreenOrientationService],
3329
- [mergedConfig.enableFullscreen, FullscreenService],
3330
- [mergedConfig.enableFileSystemAccess, FileSystemAccessService],
3331
- [mergedConfig.enableMediaRecorder, MediaRecorderService],
3332
- [mergedConfig.enableServerSentEvents, ServerSentEventsService],
3333
- [mergedConfig.enableVibration, VibrationService],
3334
- [mergedConfig.enableSpeechSynthesis, SpeechSynthesisService],
3335
- [mergedConfig.enableMutationObserver, MutationObserverService],
3336
- [mergedConfig.enablePerformanceObserver, PerformanceObserverService],
3337
- [mergedConfig.enableIdleDetector, IdleDetectorService],
3338
- [mergedConfig.enableEyeDropper, EyeDropperService],
3339
- [mergedConfig.enableBarcodeDetector, BarcodeDetectorService],
3340
- [mergedConfig.enableWebAudio, WebAudioService],
3341
- [mergedConfig.enableGamepad, GamepadService],
3342
- [mergedConfig.enableWebBluetooth, WebBluetoothService],
3343
- [mergedConfig.enableWebUsb, WebUsbService],
3344
- [mergedConfig.enableWebNfc, WebNfcService],
3345
- [mergedConfig.enablePaymentRequest, PaymentRequestService],
3346
- [mergedConfig.enableCredentialManagement, CredentialManagementService],
3347
- ];
3348
- for (const [enabled, provider] of conditionalProviders) {
3349
- if (enabled) {
3350
- providers.push(provider);
3351
- }
3352
- }
3353
- return makeEnvironmentProviders(providers);
3377
+ function providePermissions() {
3378
+ return makeEnvironmentProviders([PermissionsService]);
3354
3379
  }
3355
- // Feature-specific providers for tree-shaking
3380
+
3356
3381
  function provideCamera() {
3357
- return makeEnvironmentProviders([PermissionsService, CameraService]);
3382
+ return makeEnvironmentProviders([CameraService]);
3358
3383
  }
3384
+
3359
3385
  function provideGeolocation() {
3360
3386
  return makeEnvironmentProviders([PermissionsService, GeolocationService]);
3361
3387
  }
3388
+
3362
3389
  function provideNotifications() {
3363
3390
  return makeEnvironmentProviders([PermissionsService, NotificationService]);
3364
3391
  }
3392
+
3365
3393
  function provideClipboard() {
3366
- return makeEnvironmentProviders([PermissionsService, ClipboardService]);
3394
+ return makeEnvironmentProviders([ClipboardService]);
3367
3395
  }
3396
+
3368
3397
  function provideMediaDevices() {
3369
3398
  return makeEnvironmentProviders([PermissionsService, MediaDevicesService]);
3370
3399
  }
3400
+
3401
+ function provideScreenWakeLock() {
3402
+ return makeEnvironmentProviders([PermissionsService, ScreenWakeLockService]);
3403
+ }
3404
+
3405
+ function provideFileSystemAccess() {
3406
+ return makeEnvironmentProviders([PermissionsService, FileSystemAccessService]);
3407
+ }
3408
+
3409
+ function provideMediaRecorder() {
3410
+ return makeEnvironmentProviders([PermissionsService, MediaRecorderService]);
3411
+ }
3412
+
3413
+ function provideIdleDetector() {
3414
+ return makeEnvironmentProviders([PermissionsService, IdleDetectorService]);
3415
+ }
3416
+
3371
3417
  function provideBattery() {
3372
3418
  return makeEnvironmentProviders([BatteryService]);
3373
3419
  }
3420
+
3374
3421
  function provideWebShare() {
3375
3422
  return makeEnvironmentProviders([WebShareService]);
3376
3423
  }
3424
+
3377
3425
  function provideWebStorage() {
3378
3426
  return makeEnvironmentProviders([WebStorageService]);
3379
3427
  }
3428
+
3380
3429
  function provideWebSocket() {
3381
3430
  return makeEnvironmentProviders([WebSocketService]);
3382
3431
  }
3432
+
3383
3433
  function provideWebWorker() {
3384
3434
  return makeEnvironmentProviders([WebWorkerService]);
3385
3435
  }
3386
- function providePermissions() {
3387
- return makeEnvironmentProviders([PermissionsService]);
3388
- }
3389
- // Combined providers for common use cases
3390
- function provideMediaApis() {
3391
- return makeEnvironmentProviders([PermissionsService, CameraService, MediaDevicesService]);
3392
- }
3393
- function provideLocationApis() {
3394
- return makeEnvironmentProviders([PermissionsService, GeolocationService]);
3395
- }
3396
- function provideStorageApis() {
3397
- return makeEnvironmentProviders([PermissionsService, ClipboardService, WebStorageService]);
3398
- }
3399
- function provideCommunicationApis() {
3400
- return makeEnvironmentProviders([
3401
- PermissionsService,
3402
- NotificationService,
3403
- WebShareService,
3404
- WebSocketService,
3405
- ]);
3406
- }
3436
+
3407
3437
  function provideIntersectionObserver() {
3408
3438
  return makeEnvironmentProviders([IntersectionObserverService]);
3409
3439
  }
3440
+
3410
3441
  function provideResizeObserver() {
3411
3442
  return makeEnvironmentProviders([ResizeObserverService]);
3412
3443
  }
3444
+
3413
3445
  function providePageVisibility() {
3414
3446
  return makeEnvironmentProviders([PageVisibilityService]);
3415
3447
  }
3448
+
3416
3449
  function provideBroadcastChannel() {
3417
3450
  return makeEnvironmentProviders([BroadcastChannelService]);
3418
3451
  }
3452
+
3419
3453
  function provideNetworkInformation() {
3420
3454
  return makeEnvironmentProviders([NetworkInformationService]);
3421
3455
  }
3422
- function provideScreenWakeLock() {
3423
- return makeEnvironmentProviders([PermissionsService, ScreenWakeLockService]);
3424
- }
3456
+
3425
3457
  function provideScreenOrientation() {
3426
3458
  return makeEnvironmentProviders([ScreenOrientationService]);
3427
3459
  }
3460
+
3428
3461
  function provideFullscreen() {
3429
3462
  return makeEnvironmentProviders([FullscreenService]);
3430
3463
  }
3431
- function provideFileSystemAccess() {
3432
- return makeEnvironmentProviders([PermissionsService, FileSystemAccessService]);
3433
- }
3434
- function provideMediaRecorder() {
3435
- return makeEnvironmentProviders([PermissionsService, MediaRecorderService]);
3436
- }
3464
+
3437
3465
  function provideServerSentEvents() {
3438
3466
  return makeEnvironmentProviders([ServerSentEventsService]);
3439
3467
  }
3468
+
3440
3469
  function provideVibration() {
3441
3470
  return makeEnvironmentProviders([VibrationService]);
3442
3471
  }
3472
+
3443
3473
  function provideSpeechSynthesis() {
3444
3474
  return makeEnvironmentProviders([SpeechSynthesisService]);
3445
3475
  }
3476
+
3446
3477
  function provideMutationObserver() {
3447
3478
  return makeEnvironmentProviders([MutationObserverService]);
3448
3479
  }
3480
+
3449
3481
  function providePerformanceObserver() {
3450
3482
  return makeEnvironmentProviders([PerformanceObserverService]);
3451
3483
  }
3452
- function provideIdleDetector() {
3453
- return makeEnvironmentProviders([PermissionsService, IdleDetectorService]);
3454
- }
3484
+
3455
3485
  function provideEyeDropper() {
3456
3486
  return makeEnvironmentProviders([EyeDropperService]);
3457
3487
  }
3488
+
3458
3489
  function provideBarcodeDetector() {
3459
3490
  return makeEnvironmentProviders([BarcodeDetectorService]);
3460
3491
  }
3492
+
3461
3493
  function provideWebAudio() {
3462
3494
  return makeEnvironmentProviders([WebAudioService]);
3463
3495
  }
3496
+
3464
3497
  function provideGamepad() {
3465
3498
  return makeEnvironmentProviders([GamepadService]);
3466
3499
  }
3500
+
3467
3501
  function provideWebBluetooth() {
3468
3502
  return makeEnvironmentProviders([WebBluetoothService]);
3469
3503
  }
3504
+
3470
3505
  function provideWebUsb() {
3471
3506
  return makeEnvironmentProviders([WebUsbService]);
3472
3507
  }
3508
+
3473
3509
  function provideWebNfc() {
3474
3510
  return makeEnvironmentProviders([WebNfcService]);
3475
3511
  }
3512
+
3476
3513
  function providePaymentRequest() {
3477
3514
  return makeEnvironmentProviders([PaymentRequestService]);
3478
3515
  }
3516
+
3479
3517
  function provideCredentialManagement() {
3480
3518
  return makeEnvironmentProviders([CredentialManagementService]);
3481
3519
  }
3482
3520
 
3521
+ function provideMediaApis() {
3522
+ return makeEnvironmentProviders([PermissionsService, CameraService, MediaDevicesService]);
3523
+ }
3524
+ function provideLocationApis() {
3525
+ return makeEnvironmentProviders([PermissionsService, GeolocationService]);
3526
+ }
3527
+ function provideStorageApis() {
3528
+ return makeEnvironmentProviders([PermissionsService, ClipboardService, WebStorageService]);
3529
+ }
3530
+ function provideCommunicationApis() {
3531
+ return makeEnvironmentProviders([
3532
+ PermissionsService,
3533
+ NotificationService,
3534
+ WebShareService,
3535
+ WebSocketService,
3536
+ ]);
3537
+ }
3538
+
3539
+ const defaultBrowserWebApisConfig = {
3540
+ enableCamera: true,
3541
+ enableGeolocation: true,
3542
+ enableNotifications: true,
3543
+ enableClipboard: true,
3544
+ enableBattery: false,
3545
+ enableMediaDevices: true,
3546
+ enableWebShare: false,
3547
+ enableWebStorage: false,
3548
+ enableWebSocket: false,
3549
+ enableWebWorker: false,
3550
+ enableIntersectionObserver: false,
3551
+ enableResizeObserver: false,
3552
+ enablePageVisibility: false,
3553
+ enableBroadcastChannel: false,
3554
+ enableNetworkInformation: false,
3555
+ enableScreenWakeLock: false,
3556
+ enableScreenOrientation: false,
3557
+ enableFullscreen: false,
3558
+ enableFileSystemAccess: false,
3559
+ enableMediaRecorder: false,
3560
+ enableServerSentEvents: false,
3561
+ enableVibration: false,
3562
+ enableSpeechSynthesis: false,
3563
+ enableMutationObserver: false,
3564
+ enablePerformanceObserver: false,
3565
+ enableIdleDetector: false,
3566
+ enableEyeDropper: false,
3567
+ enableBarcodeDetector: false,
3568
+ enableWebAudio: false,
3569
+ enableGamepad: false,
3570
+ enableWebBluetooth: false,
3571
+ enableWebUsb: false,
3572
+ enableWebNfc: false,
3573
+ enablePaymentRequest: false,
3574
+ enableCredentialManagement: false,
3575
+ };
3576
+ function provideBrowserWebApis(config = {}) {
3577
+ const mergedConfig = { ...defaultBrowserWebApisConfig, ...config };
3578
+ const providers = [PermissionsService];
3579
+ const conditionalProviders = [
3580
+ [mergedConfig.enableCamera, CameraService],
3581
+ [mergedConfig.enableGeolocation, GeolocationService],
3582
+ [mergedConfig.enableNotifications, NotificationService],
3583
+ [mergedConfig.enableClipboard, ClipboardService],
3584
+ [mergedConfig.enableMediaDevices, MediaDevicesService],
3585
+ [mergedConfig.enableBattery, BatteryService],
3586
+ [mergedConfig.enableWebShare, WebShareService],
3587
+ [mergedConfig.enableWebStorage, WebStorageService],
3588
+ [mergedConfig.enableWebSocket, WebSocketService],
3589
+ [mergedConfig.enableWebWorker, WebWorkerService],
3590
+ [mergedConfig.enableIntersectionObserver, IntersectionObserverService],
3591
+ [mergedConfig.enableResizeObserver, ResizeObserverService],
3592
+ [mergedConfig.enablePageVisibility, PageVisibilityService],
3593
+ [mergedConfig.enableBroadcastChannel, BroadcastChannelService],
3594
+ [mergedConfig.enableNetworkInformation, NetworkInformationService],
3595
+ [mergedConfig.enableScreenWakeLock, ScreenWakeLockService],
3596
+ [mergedConfig.enableScreenOrientation, ScreenOrientationService],
3597
+ [mergedConfig.enableFullscreen, FullscreenService],
3598
+ [mergedConfig.enableFileSystemAccess, FileSystemAccessService],
3599
+ [mergedConfig.enableMediaRecorder, MediaRecorderService],
3600
+ [mergedConfig.enableServerSentEvents, ServerSentEventsService],
3601
+ [mergedConfig.enableVibration, VibrationService],
3602
+ [mergedConfig.enableSpeechSynthesis, SpeechSynthesisService],
3603
+ [mergedConfig.enableMutationObserver, MutationObserverService],
3604
+ [mergedConfig.enablePerformanceObserver, PerformanceObserverService],
3605
+ [mergedConfig.enableIdleDetector, IdleDetectorService],
3606
+ [mergedConfig.enableEyeDropper, EyeDropperService],
3607
+ [mergedConfig.enableBarcodeDetector, BarcodeDetectorService],
3608
+ [mergedConfig.enableWebAudio, WebAudioService],
3609
+ [mergedConfig.enableGamepad, GamepadService],
3610
+ [mergedConfig.enableWebBluetooth, WebBluetoothService],
3611
+ [mergedConfig.enableWebUsb, WebUsbService],
3612
+ [mergedConfig.enableWebNfc, WebNfcService],
3613
+ [mergedConfig.enablePaymentRequest, PaymentRequestService],
3614
+ [mergedConfig.enableCredentialManagement, CredentialManagementService],
3615
+ ];
3616
+ for (const [enabled, provider] of conditionalProviders) {
3617
+ if (enabled) {
3618
+ providers.push(provider);
3619
+ }
3620
+ }
3621
+ return makeEnvironmentProviders(providers);
3622
+ }
3623
+
3483
3624
  // Browser Web APIs Services
3484
3625
  // Version
3485
3626
  const version = '0.1.0';
@@ -3488,4 +3629,4 @@ const version = '0.1.0';
3488
3629
  * Generated bundle index. Do not edit.
3489
3630
  */
3490
3631
 
3491
- export { BarcodeDetectorService, BatteryService, BroadcastChannelService, BrowserApiBaseService, BrowserCapabilityService, BrowserSupportUtil, CameraService, ClipboardService, CredentialManagementService, EyeDropperService, FileSystemAccessService, FullscreenService, GamepadService, GeolocationService, IdleDetectorService, IntersectionObserverService, MediaDevicesService, MediaRecorderService, MutationObserverService, NetworkInformationService, NotificationService, PageVisibilityService, PaymentRequestService, PerformanceObserverService, PermissionsService, ResizeObserverService, ScreenOrientationService, ScreenWakeLockService, ServerSentEventsService, SpeechSynthesisService, VibrationService, WebAudioService, WebBluetoothService, WebNfcService, WebShareService, WebSocketService, WebStorageService, WebUsbService, WebWorkerService, permissionGuard as createPermissionGuard, defaultBrowserWebApisConfig, injectGamepad, injectIdleDetector, injectIntersectionObserver, injectMutationObserver, injectNetworkInformation, injectPageVisibility, injectPerformanceObserver, injectResizeObserver, injectScreenOrientation, permissionGuard, provideBarcodeDetector, provideBattery, provideBroadcastChannel, provideBrowserWebApis, provideCamera, provideClipboard, provideCommunicationApis, provideCredentialManagement, provideEyeDropper, provideFileSystemAccess, provideFullscreen, provideGamepad, provideGeolocation, provideIdleDetector, provideIntersectionObserver, provideLocationApis, provideMediaApis, provideMediaDevices, provideMediaRecorder, provideMutationObserver, provideNetworkInformation, provideNotifications, providePageVisibility, providePaymentRequest, providePerformanceObserver, providePermissions, provideResizeObserver, provideScreenOrientation, provideScreenWakeLock, provideServerSentEvents, provideSpeechSynthesis, provideStorageApis, provideVibration, provideWebAudio, provideWebBluetooth, provideWebNfc, provideWebShare, provideWebSocket, provideWebStorage, provideWebUsb, provideWebWorker, version };
3632
+ export { BROWSER_API_LOGGER, BarcodeDetectorService, BatteryService, BroadcastChannelService, BrowserApiBaseService, BrowserCapabilityService, BrowserSupportUtil, CameraService, ClipboardService, ConnectionRegistryBaseService, CredentialManagementService, EyeDropperService, FileSystemAccessService, FullscreenService, GamepadService, GeolocationService, IdleDetectorService, IntersectionObserverService, MediaDevicesService, MediaRecorderService, MutationObserverService, NetworkInformationService, NotificationService, PageVisibilityService, PaymentRequestService, PerformanceObserverService, PermissionsService, ResizeObserverService, ScreenOrientationService, ScreenWakeLockService, ServerSentEventsService, SpeechSynthesisService, VibrationService, WebAudioService, WebBluetoothService, WebNfcService, WebShareService, WebSocketService, WebStorageService, WebUsbService, WebWorkerService, permissionGuard as createPermissionGuard, defaultBrowserWebApisConfig, injectGamepad, injectIdleDetector, injectIntersectionObserver, injectMutationObserver, injectNetworkInformation, injectPageVisibility, injectPerformanceObserver, injectResizeObserver, injectScreenOrientation, permissionGuard, provideBarcodeDetector, provideBattery, provideBroadcastChannel, provideBrowserWebApis, provideCamera, provideClipboard, provideCommunicationApis, provideCredentialManagement, provideEyeDropper, provideFileSystemAccess, provideFullscreen, provideGamepad, provideGeolocation, provideIdleDetector, provideIntersectionObserver, provideLocationApis, provideMediaApis, provideMediaDevices, provideMediaRecorder, provideMutationObserver, provideNetworkInformation, provideNotifications, providePageVisibility, providePaymentRequest, providePerformanceObserver, providePermissions, provideResizeObserver, provideScreenOrientation, provideScreenWakeLock, provideServerSentEvents, provideSpeechSynthesis, provideStorageApis, provideVibration, provideWebAudio, provideWebBluetooth, provideWebNfc, provideWebShare, provideWebSocket, provideWebStorage, provideWebUsb, provideWebWorker, version };