@angular-helpers/browser-web-apis 21.4.0 → 21.6.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.
package/README.es.md CHANGED
@@ -8,12 +8,13 @@ Paquete de servicios Angular para acceder de forma estructurada y segura a Brows
8
8
 
9
9
  ## Caracteristicas
10
10
 
11
- - Seguridad integrada con prevencion de ReDoS usando Web Workers
12
11
  - Acceso unificado a APIs del navegador mediante servicios tipados
13
- - Arquitectura tree-shakable
14
- - Configuracion modular para habilitar solo lo necesario
12
+ - **Tree-shaking real** — cada `provideX()` vive en su propio modulo e importa solo lo que necesita
13
+ - `provideBrowserWebApis()` para configuracion rapida cuando el tamano del bundle no es critico
15
14
  - APIs reactivas con signals y observables
16
- - Integracion segura con el ciclo de vida usando `destroyRef`
15
+ - Integracion segura con el ciclo de vida via `DestroyRef` (cleanup automatico)
16
+ - Logging y manejo de errores centralizado en `BrowserApiBaseService`
17
+ - Validacion de contexto seguro y deteccion de soporte del navegador incorporados
17
18
 
18
19
  ## Servicios disponibles
19
20
 
@@ -29,6 +30,8 @@ Paquete de servicios Angular para acceder de forma estructurada y segura a Brows
29
30
 
30
31
  - `IntersectionObserverService` - Detectar cuando elementos entran/salen del viewport
31
32
  - `ResizeObserverService` - Observar cambios de tamano de elementos
33
+ - `MutationObserverService` - Observar mutaciones en el DOM
34
+ - `PerformanceObserverService` - Monitorear entradas de rendimiento (LCP, CLS, etc.)
32
35
 
33
36
  ### APIs de sistema
34
37
 
@@ -39,6 +42,9 @@ Paquete de servicios Angular para acceder de forma estructurada y segura a Brows
39
42
  - `FullscreenService` - Alternar modo pantalla completa para elementos
40
43
  - `VibrationService` - Activar patrones de retroalimentacion tactil
41
44
  - `SpeechSynthesisService` - Texto a voz con seleccion de voz
45
+ - `IdleDetectorService` - Detectar estado idle del usuario y bloqueo de pantalla
46
+ - `GamepadService` - Polling de entrada de controladores de juego
47
+ - `WebAudioService` - Contexto de audio, osciladores y analizadores
42
48
 
43
49
  ### APIs de red
44
50
 
@@ -75,6 +81,8 @@ npm install @angular-helpers/browser-web-apis
75
81
 
76
82
  ## Configuracion rapida
77
83
 
84
+ ### Todo en uno (sin preocupacion por el bundle)
85
+
78
86
  ```typescript
79
87
  import { provideBrowserWebApis } from '@angular-helpers/browser-web-apis';
80
88
 
@@ -89,6 +97,62 @@ bootstrapApplication(AppComponent, {
89
97
  });
90
98
  ```
91
99
 
100
+ ### Configuracion granular (recomendada para produccion)
101
+
102
+ Cada `provideX()` vive en su propio modulo e importa solo su servicio. Los bundlers (webpack, Rollup, Vite) eliminan todo lo que no uses.
103
+
104
+ ```typescript
105
+ import {
106
+ provideCamera,
107
+ provideGeolocation,
108
+ provideWebStorage,
109
+ } from '@angular-helpers/browser-web-apis';
110
+
111
+ bootstrapApplication(AppComponent, {
112
+ providers: [
113
+ provideCamera(), // → solo CameraService + PermissionsService
114
+ provideGeolocation(), // → solo GeolocationService + PermissionsService
115
+ provideWebStorage(), // → solo WebStorageService
116
+ ],
117
+ });
118
+ ```
119
+
120
+ Cada servicio tiene su propio `provideX()`:
121
+
122
+ | Funcion | Servicios incluidos |
123
+ | ------------------------------- | ------------------------------------------- |
124
+ | `provideCamera()` | `PermissionsService`, `CameraService` |
125
+ | `provideGeolocation()` | `PermissionsService`, `GeolocationService` |
126
+ | `provideNotifications()` | `PermissionsService`, `NotificationService` |
127
+ | `provideClipboard()` | `PermissionsService`, `ClipboardService` |
128
+ | `provideMediaDevices()` | `PermissionsService`, `MediaDevicesService` |
129
+ | `provideWebStorage()` | `WebStorageService` |
130
+ | `provideWebSocket()` | `WebSocketService` |
131
+ | `provideWebWorker()` | `WebWorkerService` |
132
+ | `provideBattery()` | `BatteryService` |
133
+ | `provideIntersectionObserver()` | `IntersectionObserverService` |
134
+ | `provideResizeObserver()` | `ResizeObserverService` |
135
+ | `provideMutationObserver()` | `MutationObserverService` |
136
+ | `providePerformanceObserver()` | `PerformanceObserverService` |
137
+ | `providePageVisibility()` | `PageVisibilityService` |
138
+ | `provideNetworkInformation()` | `NetworkInformationService` |
139
+ | …y 22 mas | Ver `src/providers/` |
140
+
141
+ ### Providers combinados
142
+
143
+ Funciones de conveniencia que agrupan servicios relacionados:
144
+
145
+ ```typescript
146
+ import { provideMediaApis, provideStorageApis } from '@angular-helpers/browser-web-apis';
147
+
148
+ bootstrapApplication(AppComponent, {
149
+ providers: [
150
+ provideMediaApis(), // Camera + MediaDevices + Permissions
151
+ provideStorageApis(), // Clipboard + WebStorage + Permissions
152
+ ],
153
+ });
154
+ ```
155
+
92
156
  ## Uso por servicio
93
157
 
94
158
  ### CameraService
package/README.md CHANGED
@@ -8,12 +8,13 @@ Angular services package for a structured and secure access layer over browser W
8
8
 
9
9
  ## Features
10
10
 
11
- - Integrated security with ReDoS prevention using Web Workers
12
11
  - Unified browser API access through strongly typed services
13
- - Tree-shakable architecture
14
- - Modular provider setup to enable only what you need
15
- - Reactive APIs with signals and observables
16
- - Lifecycle-safe integration with `destroyRef`
12
+ - **True tree-shaking** — individual `provideX()` functions import only their own service
13
+ - All-in-one `provideBrowserWebApis()` for quick setup when bundle size is not a concern
14
+ - Reactive APIs using signals and observables
15
+ - Lifecycle-safe integration with `DestroyRef` (automatic cleanup)
16
+ - Centralized logging and error handling via `BrowserApiBaseService`
17
+ - Secure context validation and browser support detection built in
17
18
 
18
19
  ## Available Services
19
20
 
@@ -96,6 +97,8 @@ npm install @angular-helpers/browser-web-apis
96
97
 
97
98
  ## Quick Setup
98
99
 
100
+ ### All-in-one (zero bundle budget concern)
101
+
99
102
  ```typescript
100
103
  import { provideBrowserWebApis } from '@angular-helpers/browser-web-apis';
101
104
 
@@ -110,6 +113,62 @@ bootstrapApplication(AppComponent, {
110
113
  });
111
114
  ```
112
115
 
116
+ ### Granular setup (recommended for production)
117
+
118
+ Each `provideX()` lives in its own module and imports only the service it needs. Bundlers (webpack, Rollup, Vite) will tree-shake anything you don't include.
119
+
120
+ ```typescript
121
+ import {
122
+ provideCamera,
123
+ provideGeolocation,
124
+ provideWebStorage,
125
+ } from '@angular-helpers/browser-web-apis';
126
+
127
+ bootstrapApplication(AppComponent, {
128
+ providers: [
129
+ provideCamera(), // → only CameraService + PermissionsService
130
+ provideGeolocation(), // → only GeolocationService + PermissionsService
131
+ provideWebStorage(), // → only WebStorageService
132
+ ],
133
+ });
134
+ ```
135
+
136
+ Every service has a matching `provideX()` function:
137
+
138
+ | Function | Services included |
139
+ | ------------------------------- | ------------------------------------------- |
140
+ | `provideCamera()` | `PermissionsService`, `CameraService` |
141
+ | `provideGeolocation()` | `PermissionsService`, `GeolocationService` |
142
+ | `provideNotifications()` | `PermissionsService`, `NotificationService` |
143
+ | `provideClipboard()` | `PermissionsService`, `ClipboardService` |
144
+ | `provideMediaDevices()` | `PermissionsService`, `MediaDevicesService` |
145
+ | `provideWebStorage()` | `WebStorageService` |
146
+ | `provideWebSocket()` | `WebSocketService` |
147
+ | `provideWebWorker()` | `WebWorkerService` |
148
+ | `provideBattery()` | `BatteryService` |
149
+ | `provideIntersectionObserver()` | `IntersectionObserverService` |
150
+ | `provideResizeObserver()` | `ResizeObserverService` |
151
+ | `provideMutationObserver()` | `MutationObserverService` |
152
+ | `providePerformanceObserver()` | `PerformanceObserverService` |
153
+ | `providePageVisibility()` | `PageVisibilityService` |
154
+ | `provideNetworkInformation()` | `NetworkInformationService` |
155
+ | …and 22 more | See `src/providers/` |
156
+
157
+ ### Combo providers
158
+
159
+ Convenience functions that bundle related services:
160
+
161
+ ```typescript
162
+ import { provideMediaApis, provideStorageApis } from '@angular-helpers/browser-web-apis';
163
+
164
+ bootstrapApplication(AppComponent, {
165
+ providers: [
166
+ provideMediaApis(), // Camera + MediaDevices + Permissions
167
+ provideStorageApis(), // Clipboard + WebStorage + Permissions
168
+ ],
169
+ });
170
+ ```
171
+
113
172
  ## Usage by Service
114
173
 
115
174
  ### CameraService
@@ -0,0 +1,478 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, DestroyRef, PLATFORM_ID, signal, computed, makeEnvironmentProviders } from '@angular/core';
3
+ import { Observable } from 'rxjs';
4
+ import { BrowserApiBaseService, PermissionsService } from '@angular-helpers/browser-web-apis';
5
+ import { isPlatformBrowser } from '@angular/common';
6
+
7
+ function getIdleDetectorClass$1() {
8
+ return window.IdleDetector;
9
+ }
10
+ class IdleDetectorService extends BrowserApiBaseService {
11
+ getApiName() {
12
+ return 'idle-detector';
13
+ }
14
+ isSupported() {
15
+ return this.isBrowserEnvironment() && 'IdleDetector' in window;
16
+ }
17
+ async requestPermission() {
18
+ if (!this.isSupported()) {
19
+ throw new Error('IdleDetector API not supported');
20
+ }
21
+ return getIdleDetectorClass$1().requestPermission();
22
+ }
23
+ watch(options = {}) {
24
+ if (!this.isSupported()) {
25
+ return new Observable((o) => o.error(new Error('IdleDetector API not supported')));
26
+ }
27
+ return new Observable((subscriber) => {
28
+ const abortController = new AbortController();
29
+ const detector = new (getIdleDetectorClass$1())();
30
+ detector.addEventListener('change', () => {
31
+ subscriber.next({
32
+ user: detector.userState,
33
+ screen: detector.screenState,
34
+ });
35
+ });
36
+ detector
37
+ .start({
38
+ threshold: options.threshold ?? 60_000,
39
+ signal: abortController.signal,
40
+ })
41
+ .catch((err) => subscriber.error(err));
42
+ return () => abortController.abort();
43
+ });
44
+ }
45
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
46
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService });
47
+ }
48
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, decorators: [{
49
+ type: Injectable
50
+ }] });
51
+
52
+ function getEyeDropperClass() {
53
+ return window.EyeDropper;
54
+ }
55
+ class EyeDropperService extends BrowserApiBaseService {
56
+ getApiName() {
57
+ return 'eye-dropper';
58
+ }
59
+ isSupported() {
60
+ return this.isBrowserEnvironment() && 'EyeDropper' in window;
61
+ }
62
+ async open() {
63
+ if (!this.isSupported()) {
64
+ throw new Error('EyeDropper API not supported');
65
+ }
66
+ const eyeDropper = new (getEyeDropperClass())();
67
+ return eyeDropper.open();
68
+ }
69
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
70
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService });
71
+ }
72
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, decorators: [{
73
+ type: Injectable
74
+ }] });
75
+
76
+ function getBarcodeDetectorClass() {
77
+ return window.BarcodeDetector;
78
+ }
79
+ class BarcodeDetectorService extends BrowserApiBaseService {
80
+ getApiName() {
81
+ return 'barcode-detector';
82
+ }
83
+ isSupported() {
84
+ return this.isBrowserEnvironment() && 'BarcodeDetector' in window;
85
+ }
86
+ async getSupportedFormats() {
87
+ if (!this.isSupported()) {
88
+ return [];
89
+ }
90
+ return getBarcodeDetectorClass().getSupportedFormats();
91
+ }
92
+ async detect(source, formats) {
93
+ if (!this.isSupported()) {
94
+ throw new Error('BarcodeDetector API not supported');
95
+ }
96
+ const detector = new (getBarcodeDetectorClass())(formats ? { formats } : undefined);
97
+ return detector.detect(source);
98
+ }
99
+ detectStream(video, options = {}) {
100
+ return new Observable((subscriber) => {
101
+ if (!this.isSupported()) {
102
+ subscriber.error(new Error('BarcodeDetector API not supported'));
103
+ return () => { };
104
+ }
105
+ const detector = new (getBarcodeDetectorClass())(options.formats ? { formats: options.formats } : undefined);
106
+ let rafId = null;
107
+ let isActive = true;
108
+ const detect = async () => {
109
+ if (!isActive)
110
+ return;
111
+ try {
112
+ const barcodes = await detector.detect(video);
113
+ if (barcodes.length > 0) {
114
+ subscriber.next(barcodes);
115
+ }
116
+ rafId = requestAnimationFrame(detect);
117
+ }
118
+ catch (error) {
119
+ subscriber.error(error);
120
+ }
121
+ };
122
+ rafId = requestAnimationFrame(detect);
123
+ return () => {
124
+ isActive = false;
125
+ if (rafId !== null) {
126
+ cancelAnimationFrame(rafId);
127
+ }
128
+ };
129
+ });
130
+ }
131
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
132
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService });
133
+ }
134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, decorators: [{
135
+ type: Injectable
136
+ }] });
137
+
138
+ function getBluetoothApi() {
139
+ return navigator.bluetooth;
140
+ }
141
+ class WebBluetoothService extends BrowserApiBaseService {
142
+ getApiName() {
143
+ return 'web-bluetooth';
144
+ }
145
+ isSupported() {
146
+ return this.isBrowserEnvironment() && 'bluetooth' in navigator;
147
+ }
148
+ async requestDevice(options) {
149
+ if (!this.isSupported()) {
150
+ throw new Error('Web Bluetooth API not supported');
151
+ }
152
+ const device = await getBluetoothApi().requestDevice(options ?? {});
153
+ return device;
154
+ }
155
+ async getConnectedDevices() {
156
+ // Note: Web Bluetooth does not expose an API to list all connected devices
157
+ // Devices must be paired/connected per session
158
+ return [];
159
+ }
160
+ watchConnectionChanges() {
161
+ return new Observable((subscriber) => {
162
+ // Web Bluetooth doesn't have a global connection event
163
+ // This would need to be implemented per-device via gattserverdisconnected
164
+ subscriber.complete();
165
+ });
166
+ }
167
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
168
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService });
169
+ }
170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, decorators: [{
171
+ type: Injectable
172
+ }] });
173
+
174
+ function getUsb() {
175
+ return navigator.usb;
176
+ }
177
+ class WebUsbService extends BrowserApiBaseService {
178
+ getApiName() {
179
+ return 'web-usb';
180
+ }
181
+ isSupported() {
182
+ return this.isBrowserEnvironment() && 'usb' in navigator;
183
+ }
184
+ async requestDevice(filters) {
185
+ if (!this.isSupported()) {
186
+ throw new Error('WebUSB API not supported');
187
+ }
188
+ const device = await getUsb().requestDevice({ filters });
189
+ return device;
190
+ }
191
+ async getDevices() {
192
+ if (!this.isSupported()) {
193
+ return [];
194
+ }
195
+ return getUsb().getDevices();
196
+ }
197
+ watchDeviceChanges() {
198
+ if (!this.isSupported()) {
199
+ return new Observable((o) => o.error(new Error('WebUSB API not supported')));
200
+ }
201
+ return new Observable((subscriber) => {
202
+ const usb = getUsb();
203
+ const onConnect = (e) => subscriber.next({ device: e.device, type: 'connect' });
204
+ const onDisconnect = (e) => subscriber.next({ device: e.device, type: 'disconnect' });
205
+ usb.addEventListener('connect', onConnect);
206
+ usb.addEventListener('disconnect', onDisconnect);
207
+ return () => {
208
+ usb.removeEventListener('connect', onConnect);
209
+ usb.removeEventListener('disconnect', onDisconnect);
210
+ };
211
+ });
212
+ }
213
+ getDeviceInfo(device) {
214
+ return {
215
+ vendorId: device.vendorId,
216
+ productId: device.productId,
217
+ productName: device.productName,
218
+ manufacturerName: device.manufacturerName,
219
+ serialNumber: device.serialNumber,
220
+ opened: device.opened,
221
+ };
222
+ }
223
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
224
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService });
225
+ }
226
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, decorators: [{
227
+ type: Injectable
228
+ }] });
229
+
230
+ function getNdefReaderClass() {
231
+ return window.NDEFReader;
232
+ }
233
+ class WebNfcService extends BrowserApiBaseService {
234
+ getApiName() {
235
+ return 'web-nfc';
236
+ }
237
+ isSupported() {
238
+ return this.isBrowserEnvironment() && 'NDEFReader' in window;
239
+ }
240
+ scan() {
241
+ if (!this.isSupported()) {
242
+ return new Observable((o) => o.error(new Error('Web NFC API not supported')));
243
+ }
244
+ return new Observable((subscriber) => {
245
+ const abortController = new AbortController();
246
+ const reader = new (getNdefReaderClass())();
247
+ const onReading = (event) => {
248
+ const e = event;
249
+ subscriber.next({
250
+ serialNumber: e.serialNumber,
251
+ message: e.message,
252
+ });
253
+ };
254
+ const onError = (event) => {
255
+ subscriber.error(event.error ?? new Error('NFC read error'));
256
+ };
257
+ reader.addEventListener('reading', onReading);
258
+ reader.addEventListener('readingerror', onError);
259
+ reader
260
+ .scan({ signal: abortController.signal })
261
+ .catch((err) => subscriber.error(err));
262
+ return () => abortController.abort();
263
+ });
264
+ }
265
+ async write(message, options) {
266
+ if (!this.isSupported()) {
267
+ throw new Error('Web NFC API not supported');
268
+ }
269
+ const reader = new (getNdefReaderClass())();
270
+ await reader.write(message, options);
271
+ }
272
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
273
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService });
274
+ }
275
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, decorators: [{
276
+ type: Injectable
277
+ }] });
278
+
279
+ class PaymentRequestService extends BrowserApiBaseService {
280
+ getApiName() {
281
+ return 'payment-request';
282
+ }
283
+ isSupported() {
284
+ return this.isBrowserEnvironment() && 'PaymentRequest' in window;
285
+ }
286
+ async canMakePayment(methods, details) {
287
+ if (!this.isSupported())
288
+ return false;
289
+ const request = new PaymentRequest(methods, details);
290
+ return request.canMakePayment();
291
+ }
292
+ async show(methods, details, options) {
293
+ if (!this.isSupported()) {
294
+ throw new Error('Payment Request API not supported');
295
+ }
296
+ const request = new PaymentRequest(methods, details, options);
297
+ const response = await request.show();
298
+ const result = {
299
+ methodName: response.methodName,
300
+ details: response.details,
301
+ payerName: response.payerName ?? null,
302
+ payerEmail: response.payerEmail ?? null,
303
+ payerPhone: response.payerPhone ?? null,
304
+ };
305
+ await response.complete('success');
306
+ return result;
307
+ }
308
+ async abort(methods, details) {
309
+ if (!this.isSupported())
310
+ return;
311
+ const request = new PaymentRequest(methods, details);
312
+ await request.abort();
313
+ }
314
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
315
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService });
316
+ }
317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, decorators: [{
318
+ type: Injectable
319
+ }] });
320
+
321
+ class CredentialManagementService extends BrowserApiBaseService {
322
+ getApiName() {
323
+ return 'credential-management';
324
+ }
325
+ isSupported() {
326
+ return this.isBrowserEnvironment() && 'credentials' in navigator;
327
+ }
328
+ isPublicKeySupported() {
329
+ return this.isSupported() && 'PublicKeyCredential' in window;
330
+ }
331
+ async get(options) {
332
+ if (!this.isSupported()) {
333
+ throw new Error('Credential Management API not supported');
334
+ }
335
+ return navigator.credentials.get(options);
336
+ }
337
+ async store(credential) {
338
+ if (!this.isSupported()) {
339
+ throw new Error('Credential Management API not supported');
340
+ }
341
+ await navigator.credentials.store(credential);
342
+ }
343
+ async createPasswordCredential(data) {
344
+ if (!this.isSupported()) {
345
+ throw new Error('Credential Management API not supported');
346
+ }
347
+ return navigator.credentials.create({
348
+ password: data,
349
+ });
350
+ }
351
+ async createPublicKeyCredential(options) {
352
+ if (!this.isPublicKeySupported()) {
353
+ throw new Error('PublicKeyCredential API not supported');
354
+ }
355
+ return navigator.credentials.create({
356
+ publicKey: options,
357
+ });
358
+ }
359
+ async preventSilentAccess() {
360
+ if (!this.isSupported())
361
+ return;
362
+ await navigator.credentials.preventSilentAccess();
363
+ }
364
+ async isConditionalMediationAvailable() {
365
+ if (!this.isPublicKeySupported())
366
+ return false;
367
+ if ('isConditionalMediationAvailable' in PublicKeyCredential) {
368
+ return PublicKeyCredential.isConditionalMediationAvailable();
369
+ }
370
+ return false;
371
+ }
372
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
373
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService });
374
+ }
375
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, decorators: [{
376
+ type: Injectable
377
+ }] });
378
+
379
+ function getIdleDetectorClass() {
380
+ return window.IdleDetector;
381
+ }
382
+ function injectIdleDetector(options = {}) {
383
+ const destroyRef = inject(DestroyRef);
384
+ const platformId = inject(PLATFORM_ID);
385
+ const defaultState = { user: 'active', screen: 'unlocked' };
386
+ const state = signal(defaultState, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
387
+ if (isPlatformBrowser(platformId) && 'IdleDetector' in window) {
388
+ const abortController = new AbortController();
389
+ const detector = new (getIdleDetectorClass())();
390
+ detector.addEventListener('change', () => {
391
+ state.set({
392
+ user: detector.userState,
393
+ screen: detector.screenState,
394
+ });
395
+ });
396
+ detector
397
+ .start({
398
+ threshold: options.threshold ?? 60_000,
399
+ signal: abortController.signal,
400
+ })
401
+ .catch(() => {
402
+ /* permission denied or unsupported — keep defaults */
403
+ });
404
+ destroyRef.onDestroy(() => abortController.abort());
405
+ }
406
+ return {
407
+ state: state.asReadonly(),
408
+ userState: computed(() => state().user),
409
+ screenState: computed(() => state().screen),
410
+ isUserIdle: computed(() => state().user === 'idle'),
411
+ isScreenLocked: computed(() => state().screen === 'locked'),
412
+ };
413
+ }
414
+
415
+ function provideIdleDetector() {
416
+ return makeEnvironmentProviders([PermissionsService, IdleDetectorService]);
417
+ }
418
+ function provideEyeDropper() {
419
+ return makeEnvironmentProviders([EyeDropperService]);
420
+ }
421
+ function provideBarcodeDetector() {
422
+ return makeEnvironmentProviders([BarcodeDetectorService]);
423
+ }
424
+ function provideWebBluetooth() {
425
+ return makeEnvironmentProviders([WebBluetoothService]);
426
+ }
427
+ function provideWebUsb() {
428
+ return makeEnvironmentProviders([WebUsbService]);
429
+ }
430
+ function provideWebNfc() {
431
+ return makeEnvironmentProviders([WebNfcService]);
432
+ }
433
+ function providePaymentRequest() {
434
+ return makeEnvironmentProviders([PaymentRequestService]);
435
+ }
436
+ function provideCredentialManagement() {
437
+ return makeEnvironmentProviders([CredentialManagementService]);
438
+ }
439
+ const defaultExperimentalWebApisConfig = {
440
+ enableIdleDetector: false,
441
+ enableEyeDropper: false,
442
+ enableBarcodeDetector: false,
443
+ enableWebBluetooth: false,
444
+ enableWebUsb: false,
445
+ enableWebNfc: false,
446
+ enablePaymentRequest: false,
447
+ enableCredentialManagement: false,
448
+ };
449
+ function provideExperimentalWebApis(config = {}) {
450
+ const mergedConfig = { ...defaultExperimentalWebApisConfig, ...config };
451
+ const providers = [];
452
+ const conditionalProviders = [
453
+ [mergedConfig.enableIdleDetector, IdleDetectorService],
454
+ [mergedConfig.enableEyeDropper, EyeDropperService],
455
+ [mergedConfig.enableBarcodeDetector, BarcodeDetectorService],
456
+ [mergedConfig.enableWebBluetooth, WebBluetoothService],
457
+ [mergedConfig.enableWebUsb, WebUsbService],
458
+ [mergedConfig.enableWebNfc, WebNfcService],
459
+ [mergedConfig.enablePaymentRequest, PaymentRequestService],
460
+ [mergedConfig.enableCredentialManagement, CredentialManagementService],
461
+ ];
462
+ for (const [enabled, provider] of conditionalProviders) {
463
+ if (enabled) {
464
+ providers.push(provider);
465
+ }
466
+ }
467
+ return makeEnvironmentProviders(providers);
468
+ }
469
+
470
+ // Secondary entry point: @angular-helpers/browser-web-apis/experimental
471
+ // Experimental Chromium-only APIs that require specific browser support
472
+ // --- Services ---
473
+
474
+ /**
475
+ * Generated bundle index. Do not edit.
476
+ */
477
+
478
+ export { BarcodeDetectorService, CredentialManagementService, EyeDropperService, IdleDetectorService, PaymentRequestService, WebBluetoothService, WebNfcService, WebUsbService, defaultExperimentalWebApisConfig, injectIdleDetector, provideBarcodeDetector, provideCredentialManagement, provideExperimentalWebApis, provideEyeDropper, provideIdleDetector, providePaymentRequest, provideWebBluetooth, provideWebNfc, provideWebUsb };