@angular-helpers/browser-web-apis 21.1.0 → 21.3.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 +523 -2
- package/README.md +579 -2
- package/fesm2022/angular-helpers-browser-web-apis.mjs +1990 -3
- package/package.json +1 -1
- package/types/angular-helpers-browser-web-apis.d.ts +864 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, inject, DestroyRef, PLATFORM_ID, signal, makeEnvironmentProviders } from '@angular/core';
|
|
2
|
+
import { Injectable, inject, DestroyRef, PLATFORM_ID, signal, computed, isSignal, effect, ElementRef, makeEnvironmentProviders } from '@angular/core';
|
|
3
3
|
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
|
|
4
|
-
import { Observable, fromEvent, Subject } from 'rxjs';
|
|
4
|
+
import { Observable, fromEvent, 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';
|
|
@@ -480,6 +480,31 @@ const BROWSER_CAPABILITIES = [
|
|
|
480
480
|
{ id: 'webShare', label: 'Web Share', requiresSecureContext: true },
|
|
481
481
|
{ id: 'battery', label: 'Battery API', requiresSecureContext: false },
|
|
482
482
|
{ id: 'webSocket', label: 'WebSocket API', requiresSecureContext: false },
|
|
483
|
+
{ id: 'intersectionObserver', label: 'Intersection Observer', requiresSecureContext: false },
|
|
484
|
+
{ id: 'resizeObserver', label: 'Resize Observer', requiresSecureContext: false },
|
|
485
|
+
{ id: 'pageVisibility', label: 'Page Visibility API', requiresSecureContext: false },
|
|
486
|
+
{ id: 'broadcastChannel', label: 'Broadcast Channel API', requiresSecureContext: false },
|
|
487
|
+
{ id: 'networkInformation', label: 'Network Information API', requiresSecureContext: false },
|
|
488
|
+
{ id: 'screenWakeLock', label: 'Screen Wake Lock API', requiresSecureContext: true },
|
|
489
|
+
{ id: 'screenOrientation', label: 'Screen Orientation API', requiresSecureContext: false },
|
|
490
|
+
{ id: 'fullscreen', label: 'Fullscreen API', requiresSecureContext: false },
|
|
491
|
+
{ id: 'fileSystemAccess', label: 'File System Access API', requiresSecureContext: true },
|
|
492
|
+
{ id: 'mediaRecorder', label: 'MediaRecorder API', requiresSecureContext: true },
|
|
493
|
+
{ id: 'serverSentEvents', label: 'Server-Sent Events', requiresSecureContext: false },
|
|
494
|
+
{ id: 'vibration', label: 'Vibration API', requiresSecureContext: false },
|
|
495
|
+
{ id: 'speechSynthesis', label: 'Speech Synthesis API', requiresSecureContext: false },
|
|
496
|
+
{ id: 'mutationObserver', label: 'Mutation Observer', requiresSecureContext: false },
|
|
497
|
+
{ id: 'performanceObserver', label: 'Performance Observer', requiresSecureContext: false },
|
|
498
|
+
{ id: 'idleDetector', label: 'Idle Detection API', requiresSecureContext: true },
|
|
499
|
+
{ id: 'eyeDropper', label: 'EyeDropper API', requiresSecureContext: true },
|
|
500
|
+
{ id: 'barcodeDetector', label: 'Barcode Detection API', requiresSecureContext: true },
|
|
501
|
+
{ id: 'webAudio', label: 'Web Audio API', requiresSecureContext: false },
|
|
502
|
+
{ id: 'gamepad', label: 'Gamepad API', requiresSecureContext: true },
|
|
503
|
+
{ id: 'webBluetooth', label: 'Web Bluetooth API', requiresSecureContext: true },
|
|
504
|
+
{ id: 'webUsb', label: 'WebUSB API', requiresSecureContext: true },
|
|
505
|
+
{ id: 'webNfc', label: 'Web NFC API', requiresSecureContext: true },
|
|
506
|
+
{ id: 'paymentRequest', label: 'Payment Request API', requiresSecureContext: true },
|
|
507
|
+
{ id: 'credentialManagement', label: 'Credential Management API', requiresSecureContext: true },
|
|
483
508
|
];
|
|
484
509
|
class BrowserCapabilityService {
|
|
485
510
|
getCapabilities() {
|
|
@@ -512,6 +537,58 @@ class BrowserCapabilityService {
|
|
|
512
537
|
return typeof navigator !== 'undefined' && 'getBattery' in navigator;
|
|
513
538
|
case 'webSocket':
|
|
514
539
|
return typeof WebSocket !== 'undefined';
|
|
540
|
+
case 'intersectionObserver':
|
|
541
|
+
return typeof IntersectionObserver !== 'undefined';
|
|
542
|
+
case 'resizeObserver':
|
|
543
|
+
return typeof ResizeObserver !== 'undefined';
|
|
544
|
+
case 'pageVisibility':
|
|
545
|
+
return typeof document !== 'undefined' && 'hidden' in document;
|
|
546
|
+
case 'broadcastChannel':
|
|
547
|
+
return typeof BroadcastChannel !== 'undefined';
|
|
548
|
+
case 'networkInformation':
|
|
549
|
+
return (typeof navigator !== 'undefined' &&
|
|
550
|
+
('connection' in navigator || 'mozConnection' in navigator));
|
|
551
|
+
case 'screenWakeLock':
|
|
552
|
+
return typeof navigator !== 'undefined' && 'wakeLock' in navigator;
|
|
553
|
+
case 'screenOrientation':
|
|
554
|
+
return typeof screen !== 'undefined' && 'orientation' in screen;
|
|
555
|
+
case 'fullscreen':
|
|
556
|
+
return (typeof document !== 'undefined' &&
|
|
557
|
+
('fullscreenEnabled' in document || 'webkitFullscreenEnabled' in document));
|
|
558
|
+
case 'fileSystemAccess':
|
|
559
|
+
return typeof window !== 'undefined' && 'showOpenFilePicker' in window;
|
|
560
|
+
case 'mediaRecorder':
|
|
561
|
+
return typeof MediaRecorder !== 'undefined';
|
|
562
|
+
case 'serverSentEvents':
|
|
563
|
+
return typeof EventSource !== 'undefined';
|
|
564
|
+
case 'vibration':
|
|
565
|
+
return typeof navigator !== 'undefined' && 'vibrate' in navigator;
|
|
566
|
+
case 'speechSynthesis':
|
|
567
|
+
return typeof window !== 'undefined' && 'speechSynthesis' in window;
|
|
568
|
+
case 'mutationObserver':
|
|
569
|
+
return typeof MutationObserver !== 'undefined';
|
|
570
|
+
case 'performanceObserver':
|
|
571
|
+
return typeof PerformanceObserver !== 'undefined';
|
|
572
|
+
case 'idleDetector':
|
|
573
|
+
return typeof window !== 'undefined' && 'IdleDetector' in window;
|
|
574
|
+
case 'eyeDropper':
|
|
575
|
+
return typeof window !== 'undefined' && 'EyeDropper' in window;
|
|
576
|
+
case 'barcodeDetector':
|
|
577
|
+
return typeof window !== 'undefined' && 'BarcodeDetector' in window;
|
|
578
|
+
case 'webAudio':
|
|
579
|
+
return typeof window !== 'undefined' && 'AudioContext' in window;
|
|
580
|
+
case 'gamepad':
|
|
581
|
+
return typeof navigator !== 'undefined' && 'getGamepads' in navigator;
|
|
582
|
+
case 'webBluetooth':
|
|
583
|
+
return typeof navigator !== 'undefined' && 'bluetooth' in navigator;
|
|
584
|
+
case 'webUsb':
|
|
585
|
+
return typeof navigator !== 'undefined' && 'usb' in navigator;
|
|
586
|
+
case 'webNfc':
|
|
587
|
+
return typeof window !== 'undefined' && 'NDEFReader' in window;
|
|
588
|
+
case 'paymentRequest':
|
|
589
|
+
return typeof window !== 'undefined' && 'PaymentRequest' in window;
|
|
590
|
+
case 'credentialManagement':
|
|
591
|
+
return typeof navigator !== 'undefined' && 'credentials' in navigator;
|
|
515
592
|
default:
|
|
516
593
|
return false;
|
|
517
594
|
}
|
|
@@ -1290,8 +1367,1793 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
1290
1367
|
type: Injectable
|
|
1291
1368
|
}] });
|
|
1292
1369
|
|
|
1370
|
+
function isIntersectionObserverSupported() {
|
|
1371
|
+
return typeof window !== 'undefined' && 'IntersectionObserver' in window;
|
|
1372
|
+
}
|
|
1373
|
+
function intersectionObserverStream(element, options = {}) {
|
|
1374
|
+
return new Observable((observer) => {
|
|
1375
|
+
const io = new IntersectionObserver((entries) => {
|
|
1376
|
+
const entry = entries[entries.length - 1];
|
|
1377
|
+
observer.next(entry.isIntersecting);
|
|
1378
|
+
}, options);
|
|
1379
|
+
io.observe(element);
|
|
1380
|
+
return () => {
|
|
1381
|
+
io.unobserve(element);
|
|
1382
|
+
io.disconnect();
|
|
1383
|
+
};
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
function intersectionObserverEntriesStream(element, options = {}) {
|
|
1387
|
+
return new Observable((observer) => {
|
|
1388
|
+
const io = new IntersectionObserver((entries) => observer.next(entries), options);
|
|
1389
|
+
io.observe(element);
|
|
1390
|
+
return () => {
|
|
1391
|
+
io.unobserve(element);
|
|
1392
|
+
io.disconnect();
|
|
1393
|
+
};
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
class IntersectionObserverService {
|
|
1398
|
+
platformId = inject(PLATFORM_ID);
|
|
1399
|
+
isSupported() {
|
|
1400
|
+
return isPlatformBrowser(this.platformId) && 'IntersectionObserver' in window;
|
|
1401
|
+
}
|
|
1402
|
+
observe(element, options = {}) {
|
|
1403
|
+
if (!this.isSupported()) {
|
|
1404
|
+
return new Observable((o) => o.error(new Error('IntersectionObserver API not supported')));
|
|
1405
|
+
}
|
|
1406
|
+
return intersectionObserverEntriesStream(element, options);
|
|
1407
|
+
}
|
|
1408
|
+
observeVisibility(element, options = {}) {
|
|
1409
|
+
if (!this.isSupported()) {
|
|
1410
|
+
return new Observable((o) => o.error(new Error('IntersectionObserver API not supported')));
|
|
1411
|
+
}
|
|
1412
|
+
return intersectionObserverStream(element, options);
|
|
1413
|
+
}
|
|
1414
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IntersectionObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1415
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IntersectionObserverService });
|
|
1416
|
+
}
|
|
1417
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IntersectionObserverService, decorators: [{
|
|
1418
|
+
type: Injectable
|
|
1419
|
+
}] });
|
|
1420
|
+
|
|
1421
|
+
function isResizeObserverSupported() {
|
|
1422
|
+
return typeof window !== 'undefined' && 'ResizeObserver' in window;
|
|
1423
|
+
}
|
|
1424
|
+
function resizeObserverStream(element, options = {}) {
|
|
1425
|
+
return new Observable((observer) => {
|
|
1426
|
+
const ro = new ResizeObserver((entries) => {
|
|
1427
|
+
const entry = entries[entries.length - 1];
|
|
1428
|
+
const contentRect = entry.contentRect;
|
|
1429
|
+
const borderBoxSize = entry.borderBoxSize?.[0];
|
|
1430
|
+
observer.next({
|
|
1431
|
+
width: contentRect.width,
|
|
1432
|
+
height: contentRect.height,
|
|
1433
|
+
inlineSize: borderBoxSize?.inlineSize ?? contentRect.width,
|
|
1434
|
+
blockSize: borderBoxSize?.blockSize ?? contentRect.height,
|
|
1435
|
+
});
|
|
1436
|
+
});
|
|
1437
|
+
ro.observe(element, options);
|
|
1438
|
+
return () => {
|
|
1439
|
+
ro.unobserve(element);
|
|
1440
|
+
ro.disconnect();
|
|
1441
|
+
};
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
function resizeObserverEntriesStream(element, options = {}) {
|
|
1445
|
+
return new Observable((observer) => {
|
|
1446
|
+
const ro = new ResizeObserver((entries) => observer.next(entries));
|
|
1447
|
+
ro.observe(element, options);
|
|
1448
|
+
return () => {
|
|
1449
|
+
ro.unobserve(element);
|
|
1450
|
+
ro.disconnect();
|
|
1451
|
+
};
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
class ResizeObserverService {
|
|
1456
|
+
platformId = inject(PLATFORM_ID);
|
|
1457
|
+
isSupported() {
|
|
1458
|
+
return isPlatformBrowser(this.platformId) && 'ResizeObserver' in window;
|
|
1459
|
+
}
|
|
1460
|
+
observe(element, options = {}) {
|
|
1461
|
+
if (!this.isSupported()) {
|
|
1462
|
+
return new Observable((o) => o.error(new Error('ResizeObserver API not supported')));
|
|
1463
|
+
}
|
|
1464
|
+
return resizeObserverEntriesStream(element, options);
|
|
1465
|
+
}
|
|
1466
|
+
observeSize(element, options = {}) {
|
|
1467
|
+
if (!this.isSupported()) {
|
|
1468
|
+
return new Observable((o) => o.error(new Error('ResizeObserver API not supported')));
|
|
1469
|
+
}
|
|
1470
|
+
return resizeObserverStream(element, options);
|
|
1471
|
+
}
|
|
1472
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ResizeObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1473
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ResizeObserverService });
|
|
1474
|
+
}
|
|
1475
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ResizeObserverService, decorators: [{
|
|
1476
|
+
type: Injectable
|
|
1477
|
+
}] });
|
|
1478
|
+
|
|
1479
|
+
function isPageVisibilitySupported() {
|
|
1480
|
+
return typeof document !== 'undefined' && 'hidden' in document;
|
|
1481
|
+
}
|
|
1482
|
+
function pageVisibilityStream() {
|
|
1483
|
+
if (!isPageVisibilitySupported()) {
|
|
1484
|
+
return of('visible');
|
|
1485
|
+
}
|
|
1486
|
+
return new Observable((observer) => {
|
|
1487
|
+
const handler = () => observer.next(document.visibilityState);
|
|
1488
|
+
document.addEventListener('visibilitychange', handler);
|
|
1489
|
+
observer.next(document.visibilityState);
|
|
1490
|
+
return () => document.removeEventListener('visibilitychange', handler);
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
class PageVisibilityService {
|
|
1495
|
+
platformId = inject(PLATFORM_ID);
|
|
1496
|
+
isSupported() {
|
|
1497
|
+
return isPlatformBrowser(this.platformId) && 'hidden' in document;
|
|
1498
|
+
}
|
|
1499
|
+
get isHidden() {
|
|
1500
|
+
if (!this.isSupported())
|
|
1501
|
+
return false;
|
|
1502
|
+
return document.hidden;
|
|
1503
|
+
}
|
|
1504
|
+
get visibilityState() {
|
|
1505
|
+
if (!this.isSupported())
|
|
1506
|
+
return 'visible';
|
|
1507
|
+
return document.visibilityState;
|
|
1508
|
+
}
|
|
1509
|
+
watch() {
|
|
1510
|
+
return pageVisibilityStream();
|
|
1511
|
+
}
|
|
1512
|
+
watchVisibility() {
|
|
1513
|
+
return pageVisibilityStream().pipe(map$1((s) => s === 'visible'));
|
|
1514
|
+
}
|
|
1515
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PageVisibilityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1516
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PageVisibilityService });
|
|
1517
|
+
}
|
|
1518
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PageVisibilityService, decorators: [{
|
|
1519
|
+
type: Injectable
|
|
1520
|
+
}] });
|
|
1521
|
+
|
|
1522
|
+
class BroadcastChannelService {
|
|
1523
|
+
destroyRef = inject(DestroyRef);
|
|
1524
|
+
platformId = inject(PLATFORM_ID);
|
|
1525
|
+
channels = new Map();
|
|
1526
|
+
isSupported() {
|
|
1527
|
+
return isPlatformBrowser(this.platformId) && 'BroadcastChannel' in window;
|
|
1528
|
+
}
|
|
1529
|
+
ensureSupport() {
|
|
1530
|
+
if (!this.isSupported()) {
|
|
1531
|
+
throw new Error('BroadcastChannel API not supported in this environment');
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
open(name) {
|
|
1535
|
+
this.ensureSupport();
|
|
1536
|
+
return new Observable((observer) => {
|
|
1537
|
+
let channel = this.channels.get(name);
|
|
1538
|
+
if (!channel) {
|
|
1539
|
+
channel = new BroadcastChannel(name);
|
|
1540
|
+
this.channels.set(name, channel);
|
|
1541
|
+
}
|
|
1542
|
+
const handler = (event) => observer.next(event.data);
|
|
1543
|
+
const errorHandler = () => observer.error(new Error(`BroadcastChannel "${name}" error`));
|
|
1544
|
+
channel.addEventListener('message', handler);
|
|
1545
|
+
channel.addEventListener('messageerror', errorHandler);
|
|
1546
|
+
const cleanup = () => {
|
|
1547
|
+
channel.removeEventListener('message', handler);
|
|
1548
|
+
channel.removeEventListener('messageerror', errorHandler);
|
|
1549
|
+
};
|
|
1550
|
+
this.destroyRef.onDestroy(() => this.close(name));
|
|
1551
|
+
return cleanup;
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
post(name, data) {
|
|
1555
|
+
this.ensureSupport();
|
|
1556
|
+
let channel = this.channels.get(name);
|
|
1557
|
+
if (!channel) {
|
|
1558
|
+
channel = new BroadcastChannel(name);
|
|
1559
|
+
this.channels.set(name, channel);
|
|
1560
|
+
this.destroyRef.onDestroy(() => this.close(name));
|
|
1561
|
+
}
|
|
1562
|
+
channel.postMessage(data);
|
|
1563
|
+
}
|
|
1564
|
+
close(name) {
|
|
1565
|
+
const channel = this.channels.get(name);
|
|
1566
|
+
if (channel) {
|
|
1567
|
+
channel.close();
|
|
1568
|
+
this.channels.delete(name);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
closeAll() {
|
|
1572
|
+
this.channels.forEach((channel) => channel.close());
|
|
1573
|
+
this.channels.clear();
|
|
1574
|
+
}
|
|
1575
|
+
getOpenChannels() {
|
|
1576
|
+
return Array.from(this.channels.keys());
|
|
1577
|
+
}
|
|
1578
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BroadcastChannelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1579
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BroadcastChannelService });
|
|
1580
|
+
}
|
|
1581
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BroadcastChannelService, decorators: [{
|
|
1582
|
+
type: Injectable
|
|
1583
|
+
}] });
|
|
1584
|
+
|
|
1585
|
+
function isNetworkInformationSupported() {
|
|
1586
|
+
if (typeof navigator === 'undefined')
|
|
1587
|
+
return false;
|
|
1588
|
+
const nav = navigator;
|
|
1589
|
+
return 'connection' in nav || 'mozConnection' in nav || 'webkitConnection' in nav;
|
|
1590
|
+
}
|
|
1591
|
+
function getNetworkConnection() {
|
|
1592
|
+
if (typeof navigator === 'undefined')
|
|
1593
|
+
return undefined;
|
|
1594
|
+
const nav = navigator;
|
|
1595
|
+
return nav.connection ?? nav.mozConnection ?? nav.webkitConnection;
|
|
1596
|
+
}
|
|
1597
|
+
function getNetworkSnapshot() {
|
|
1598
|
+
const online = typeof navigator !== 'undefined' ? navigator.onLine : true;
|
|
1599
|
+
const conn = getNetworkConnection();
|
|
1600
|
+
return {
|
|
1601
|
+
online,
|
|
1602
|
+
type: conn?.type,
|
|
1603
|
+
effectiveType: conn?.effectiveType,
|
|
1604
|
+
downlink: conn?.downlink,
|
|
1605
|
+
downlinkMax: conn?.downlinkMax,
|
|
1606
|
+
rtt: conn?.rtt,
|
|
1607
|
+
saveData: conn?.saveData,
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
function networkInformationStream() {
|
|
1611
|
+
if (typeof window === 'undefined') {
|
|
1612
|
+
return of({ online: true });
|
|
1613
|
+
}
|
|
1614
|
+
return new Observable((observer) => {
|
|
1615
|
+
const emit = () => observer.next(getNetworkSnapshot());
|
|
1616
|
+
const conn = getNetworkConnection();
|
|
1617
|
+
if (conn)
|
|
1618
|
+
conn.addEventListener('change', emit);
|
|
1619
|
+
window.addEventListener('online', emit);
|
|
1620
|
+
window.addEventListener('offline', emit);
|
|
1621
|
+
emit();
|
|
1622
|
+
return () => {
|
|
1623
|
+
conn?.removeEventListener('change', emit);
|
|
1624
|
+
window.removeEventListener('online', emit);
|
|
1625
|
+
window.removeEventListener('offline', emit);
|
|
1626
|
+
};
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
class NetworkInformationService {
|
|
1631
|
+
platformId = inject(PLATFORM_ID);
|
|
1632
|
+
isSupported() {
|
|
1633
|
+
return isPlatformBrowser(this.platformId) && isNetworkInformationSupported();
|
|
1634
|
+
}
|
|
1635
|
+
getSnapshot() {
|
|
1636
|
+
return isPlatformBrowser(this.platformId) ? getNetworkSnapshot() : { online: true };
|
|
1637
|
+
}
|
|
1638
|
+
watch() {
|
|
1639
|
+
return networkInformationStream();
|
|
1640
|
+
}
|
|
1641
|
+
get isOnline() {
|
|
1642
|
+
return isPlatformBrowser(this.platformId) ? navigator.onLine : true;
|
|
1643
|
+
}
|
|
1644
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NetworkInformationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1645
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NetworkInformationService });
|
|
1646
|
+
}
|
|
1647
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NetworkInformationService, decorators: [{
|
|
1648
|
+
type: Injectable
|
|
1649
|
+
}] });
|
|
1650
|
+
|
|
1651
|
+
class ScreenWakeLockService extends BrowserApiBaseService {
|
|
1652
|
+
sentinel = null;
|
|
1653
|
+
getApiName() {
|
|
1654
|
+
return 'screen-wake-lock';
|
|
1655
|
+
}
|
|
1656
|
+
isSupported() {
|
|
1657
|
+
return isPlatformBrowser(this.platformId) && 'wakeLock' in navigator;
|
|
1658
|
+
}
|
|
1659
|
+
get isActive() {
|
|
1660
|
+
return this.sentinel !== null && !this.sentinel.released;
|
|
1661
|
+
}
|
|
1662
|
+
async request(type = 'screen') {
|
|
1663
|
+
if (!this.isSupported()) {
|
|
1664
|
+
throw new Error('Screen Wake Lock API not supported in this browser');
|
|
1665
|
+
}
|
|
1666
|
+
if (!window.isSecureContext) {
|
|
1667
|
+
throw new Error('Screen Wake Lock API requires a secure context (HTTPS)');
|
|
1668
|
+
}
|
|
1669
|
+
try {
|
|
1670
|
+
this.sentinel = await navigator.wakeLock.request(type);
|
|
1671
|
+
this.sentinel.addEventListener('release', () => {
|
|
1672
|
+
this.sentinel = null;
|
|
1673
|
+
});
|
|
1674
|
+
this.destroyRef.onDestroy(() => this.release());
|
|
1675
|
+
return { active: true, type, released: false };
|
|
1676
|
+
}
|
|
1677
|
+
catch (error) {
|
|
1678
|
+
console.error('[ScreenWakeLockService] Failed to acquire wake lock:', error);
|
|
1679
|
+
throw this.createError('Failed to acquire wake lock', error);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
async release() {
|
|
1683
|
+
if (this.sentinel && !this.sentinel.released) {
|
|
1684
|
+
try {
|
|
1685
|
+
await this.sentinel.release();
|
|
1686
|
+
}
|
|
1687
|
+
catch {
|
|
1688
|
+
// Sentinel may already be released
|
|
1689
|
+
}
|
|
1690
|
+
finally {
|
|
1691
|
+
this.sentinel = null;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
watchStatus() {
|
|
1696
|
+
return new Observable((observer) => {
|
|
1697
|
+
const emit = () => observer.next({ active: this.isActive, released: !this.isActive });
|
|
1698
|
+
const handleVisibilityChange = async () => {
|
|
1699
|
+
if (document.visibilityState === 'visible' && !this.isActive) {
|
|
1700
|
+
try {
|
|
1701
|
+
await this.request();
|
|
1702
|
+
}
|
|
1703
|
+
catch {
|
|
1704
|
+
// Could not re-acquire
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
emit();
|
|
1708
|
+
};
|
|
1709
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
1710
|
+
emit();
|
|
1711
|
+
const cleanup = () => document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
1712
|
+
this.destroyRef.onDestroy(cleanup);
|
|
1713
|
+
return cleanup;
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenWakeLockService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
1717
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenWakeLockService });
|
|
1718
|
+
}
|
|
1719
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenWakeLockService, decorators: [{
|
|
1720
|
+
type: Injectable
|
|
1721
|
+
}] });
|
|
1722
|
+
|
|
1723
|
+
function isScreenOrientationSupported() {
|
|
1724
|
+
return typeof window !== 'undefined' && 'screen' in window && 'orientation' in screen;
|
|
1725
|
+
}
|
|
1726
|
+
function getOrientationSnapshot() {
|
|
1727
|
+
if (!isScreenOrientationSupported()) {
|
|
1728
|
+
return { type: 'portrait-primary', angle: 0 };
|
|
1729
|
+
}
|
|
1730
|
+
return {
|
|
1731
|
+
type: screen.orientation.type,
|
|
1732
|
+
angle: screen.orientation.angle,
|
|
1733
|
+
};
|
|
1734
|
+
}
|
|
1735
|
+
function screenOrientationStream() {
|
|
1736
|
+
if (!isScreenOrientationSupported()) {
|
|
1737
|
+
return of({ type: 'portrait-primary', angle: 0 });
|
|
1738
|
+
}
|
|
1739
|
+
return new Observable((observer) => {
|
|
1740
|
+
const handler = () => observer.next(getOrientationSnapshot());
|
|
1741
|
+
screen.orientation.addEventListener('change', handler);
|
|
1742
|
+
observer.next(getOrientationSnapshot());
|
|
1743
|
+
return () => screen.orientation.removeEventListener('change', handler);
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
class ScreenOrientationService {
|
|
1748
|
+
platformId = inject(PLATFORM_ID);
|
|
1749
|
+
isSupported() {
|
|
1750
|
+
return isPlatformBrowser(this.platformId) && 'screen' in window && 'orientation' in screen;
|
|
1751
|
+
}
|
|
1752
|
+
getSnapshot() {
|
|
1753
|
+
return isPlatformBrowser(this.platformId)
|
|
1754
|
+
? getOrientationSnapshot()
|
|
1755
|
+
: { type: 'portrait-primary', angle: 0 };
|
|
1756
|
+
}
|
|
1757
|
+
get isPortrait() {
|
|
1758
|
+
return this.getSnapshot().type.startsWith('portrait');
|
|
1759
|
+
}
|
|
1760
|
+
get isLandscape() {
|
|
1761
|
+
return this.getSnapshot().type.startsWith('landscape');
|
|
1762
|
+
}
|
|
1763
|
+
watch() {
|
|
1764
|
+
return screenOrientationStream();
|
|
1765
|
+
}
|
|
1766
|
+
async lock(orientation) {
|
|
1767
|
+
if (!this.isSupported()) {
|
|
1768
|
+
throw new Error('Screen Orientation API not supported');
|
|
1769
|
+
}
|
|
1770
|
+
try {
|
|
1771
|
+
await screen.orientation.lock(orientation);
|
|
1772
|
+
}
|
|
1773
|
+
catch (error) {
|
|
1774
|
+
console.error('[ScreenOrientationService] Failed to lock orientation:', error);
|
|
1775
|
+
throw error;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
unlock() {
|
|
1779
|
+
if (this.isSupported()) {
|
|
1780
|
+
screen.orientation.unlock();
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenOrientationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1784
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenOrientationService });
|
|
1785
|
+
}
|
|
1786
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScreenOrientationService, decorators: [{
|
|
1787
|
+
type: Injectable
|
|
1788
|
+
}] });
|
|
1789
|
+
|
|
1790
|
+
class FullscreenService {
|
|
1791
|
+
destroyRef = inject(DestroyRef);
|
|
1792
|
+
platformId = inject(PLATFORM_ID);
|
|
1793
|
+
isSupported() {
|
|
1794
|
+
if (!isPlatformBrowser(this.platformId))
|
|
1795
|
+
return false;
|
|
1796
|
+
return !!(document.fullscreenEnabled ??
|
|
1797
|
+
document.webkitFullscreenEnabled);
|
|
1798
|
+
}
|
|
1799
|
+
get isFullscreen() {
|
|
1800
|
+
if (!isPlatformBrowser(this.platformId))
|
|
1801
|
+
return false;
|
|
1802
|
+
return !!(document.fullscreenElement ??
|
|
1803
|
+
document.webkitFullscreenElement);
|
|
1804
|
+
}
|
|
1805
|
+
get fullscreenElement() {
|
|
1806
|
+
if (!isPlatformBrowser(this.platformId))
|
|
1807
|
+
return null;
|
|
1808
|
+
return (document.fullscreenElement ??
|
|
1809
|
+
document.webkitFullscreenElement ??
|
|
1810
|
+
null);
|
|
1811
|
+
}
|
|
1812
|
+
async request(element = document.documentElement) {
|
|
1813
|
+
if (!this.isSupported()) {
|
|
1814
|
+
throw new Error('Fullscreen API not supported in this browser');
|
|
1815
|
+
}
|
|
1816
|
+
try {
|
|
1817
|
+
const el = element;
|
|
1818
|
+
if (el.requestFullscreen) {
|
|
1819
|
+
await el.requestFullscreen();
|
|
1820
|
+
}
|
|
1821
|
+
else if (el.webkitRequestFullscreen) {
|
|
1822
|
+
await el.webkitRequestFullscreen();
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
catch (error) {
|
|
1826
|
+
console.error('[FullscreenService] Failed to enter fullscreen:', error);
|
|
1827
|
+
throw error;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
async exit() {
|
|
1831
|
+
if (!this.isFullscreen)
|
|
1832
|
+
return;
|
|
1833
|
+
try {
|
|
1834
|
+
const doc = document;
|
|
1835
|
+
if (doc.exitFullscreen) {
|
|
1836
|
+
await doc.exitFullscreen();
|
|
1837
|
+
}
|
|
1838
|
+
else if (doc.webkitExitFullscreen) {
|
|
1839
|
+
await doc.webkitExitFullscreen();
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
catch (error) {
|
|
1843
|
+
console.error('[FullscreenService] Failed to exit fullscreen:', error);
|
|
1844
|
+
throw error;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
async toggle(element = document.documentElement) {
|
|
1848
|
+
if (this.isFullscreen) {
|
|
1849
|
+
await this.exit();
|
|
1850
|
+
}
|
|
1851
|
+
else {
|
|
1852
|
+
await this.request(element);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
watch() {
|
|
1856
|
+
return new Observable((observer) => {
|
|
1857
|
+
if (!isPlatformBrowser(this.platformId)) {
|
|
1858
|
+
observer.next(false);
|
|
1859
|
+
observer.complete();
|
|
1860
|
+
return undefined;
|
|
1861
|
+
}
|
|
1862
|
+
const handler = () => observer.next(this.isFullscreen);
|
|
1863
|
+
document.addEventListener('fullscreenchange', handler);
|
|
1864
|
+
document.addEventListener('webkitfullscreenchange', handler);
|
|
1865
|
+
observer.next(this.isFullscreen);
|
|
1866
|
+
const cleanup = () => {
|
|
1867
|
+
document.removeEventListener('fullscreenchange', handler);
|
|
1868
|
+
document.removeEventListener('webkitfullscreenchange', handler);
|
|
1869
|
+
};
|
|
1870
|
+
this.destroyRef.onDestroy(cleanup);
|
|
1871
|
+
return cleanup;
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FullscreenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1875
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FullscreenService });
|
|
1876
|
+
}
|
|
1877
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FullscreenService, decorators: [{
|
|
1878
|
+
type: Injectable
|
|
1879
|
+
}] });
|
|
1880
|
+
|
|
1881
|
+
class FileSystemAccessService extends BrowserApiBaseService {
|
|
1882
|
+
getApiName() {
|
|
1883
|
+
return 'file-system-access';
|
|
1884
|
+
}
|
|
1885
|
+
isSupported() {
|
|
1886
|
+
return this.isBrowserEnvironment() && 'showOpenFilePicker' in window && window.isSecureContext;
|
|
1887
|
+
}
|
|
1888
|
+
get win() {
|
|
1889
|
+
return window;
|
|
1890
|
+
}
|
|
1891
|
+
ensureSupport() {
|
|
1892
|
+
if (this.isServerEnvironment()) {
|
|
1893
|
+
throw new Error('File System Access API not available in server environment');
|
|
1894
|
+
}
|
|
1895
|
+
if (!('showOpenFilePicker' in window)) {
|
|
1896
|
+
throw new Error('File System Access API not supported in this browser');
|
|
1897
|
+
}
|
|
1898
|
+
if (!window.isSecureContext) {
|
|
1899
|
+
throw new Error('File System Access API requires a secure context (HTTPS)');
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
async openFile(options = {}) {
|
|
1903
|
+
this.ensureSupport();
|
|
1904
|
+
try {
|
|
1905
|
+
const handles = await this.win.showOpenFilePicker(options);
|
|
1906
|
+
return Promise.all(handles.map((h) => h.getFile()));
|
|
1907
|
+
}
|
|
1908
|
+
catch (error) {
|
|
1909
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
1910
|
+
return [];
|
|
1911
|
+
}
|
|
1912
|
+
console.error('[FileSystemAccessService] Error opening file:', error);
|
|
1913
|
+
throw error;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
async saveFile(content, options = {}) {
|
|
1917
|
+
this.ensureSupport();
|
|
1918
|
+
if (!this.win.showSaveFilePicker) {
|
|
1919
|
+
throw new Error('showSaveFilePicker not supported');
|
|
1920
|
+
}
|
|
1921
|
+
try {
|
|
1922
|
+
const handle = await this.win.showSaveFilePicker(options);
|
|
1923
|
+
const writable = await handle.createWritable();
|
|
1924
|
+
await writable.write(content);
|
|
1925
|
+
await writable.close();
|
|
1926
|
+
}
|
|
1927
|
+
catch (error) {
|
|
1928
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
console.error('[FileSystemAccessService] Error saving file:', error);
|
|
1932
|
+
throw error;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
async openDirectory(options = {}) {
|
|
1936
|
+
this.ensureSupport();
|
|
1937
|
+
if (!this.win.showDirectoryPicker) {
|
|
1938
|
+
throw new Error('showDirectoryPicker not supported');
|
|
1939
|
+
}
|
|
1940
|
+
try {
|
|
1941
|
+
return await this.win.showDirectoryPicker(options);
|
|
1942
|
+
}
|
|
1943
|
+
catch (error) {
|
|
1944
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
1945
|
+
return null;
|
|
1946
|
+
}
|
|
1947
|
+
console.error('[FileSystemAccessService] Error opening directory:', error);
|
|
1948
|
+
throw error;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
async readFileAsText(file) {
|
|
1952
|
+
return file.text();
|
|
1953
|
+
}
|
|
1954
|
+
async readFileAsArrayBuffer(file) {
|
|
1955
|
+
return file.arrayBuffer();
|
|
1956
|
+
}
|
|
1957
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FileSystemAccessService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
1958
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FileSystemAccessService });
|
|
1959
|
+
}
|
|
1960
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: FileSystemAccessService, decorators: [{
|
|
1961
|
+
type: Injectable
|
|
1962
|
+
}] });
|
|
1963
|
+
|
|
1964
|
+
class MediaRecorderService extends BrowserApiBaseService {
|
|
1965
|
+
recorder = null;
|
|
1966
|
+
chunks = [];
|
|
1967
|
+
startTime = 0;
|
|
1968
|
+
dataSubject = new Subject();
|
|
1969
|
+
stateSubject = new Subject();
|
|
1970
|
+
getApiName() {
|
|
1971
|
+
return 'media-recorder';
|
|
1972
|
+
}
|
|
1973
|
+
isSupported() {
|
|
1974
|
+
return this.isBrowserEnvironment() && 'MediaRecorder' in window;
|
|
1975
|
+
}
|
|
1976
|
+
get state() {
|
|
1977
|
+
return this.recorder?.state ?? 'inactive';
|
|
1978
|
+
}
|
|
1979
|
+
static isTypeSupported(mimeType) {
|
|
1980
|
+
return typeof MediaRecorder !== 'undefined' && MediaRecorder.isTypeSupported(mimeType);
|
|
1981
|
+
}
|
|
1982
|
+
watchState() {
|
|
1983
|
+
return this.stateSubject.asObservable();
|
|
1984
|
+
}
|
|
1985
|
+
watchData() {
|
|
1986
|
+
return this.dataSubject.asObservable();
|
|
1987
|
+
}
|
|
1988
|
+
async start(stream, options = {}) {
|
|
1989
|
+
if (!this.isSupported()) {
|
|
1990
|
+
throw new Error('MediaRecorder API not supported in this browser');
|
|
1991
|
+
}
|
|
1992
|
+
if (!window.isSecureContext) {
|
|
1993
|
+
throw new Error('MediaRecorder requires a secure context (HTTPS)');
|
|
1994
|
+
}
|
|
1995
|
+
this.stop();
|
|
1996
|
+
this.chunks = [];
|
|
1997
|
+
this.startTime = Date.now();
|
|
1998
|
+
const { timeslice, ...recorderOptions } = options;
|
|
1999
|
+
try {
|
|
2000
|
+
this.recorder = new MediaRecorder(stream, recorderOptions);
|
|
2001
|
+
this.recorder.ondataavailable = (event) => {
|
|
2002
|
+
if (event.data.size > 0) {
|
|
2003
|
+
this.chunks.push(event.data);
|
|
2004
|
+
this.dataSubject.next(event.data);
|
|
2005
|
+
}
|
|
2006
|
+
};
|
|
2007
|
+
this.recorder.onstart = () => this.stateSubject.next('recording');
|
|
2008
|
+
this.recorder.onpause = () => this.stateSubject.next('paused');
|
|
2009
|
+
this.recorder.onresume = () => this.stateSubject.next('recording');
|
|
2010
|
+
this.recorder.onstop = () => this.stateSubject.next('inactive');
|
|
2011
|
+
this.recorder.start(timeslice);
|
|
2012
|
+
}
|
|
2013
|
+
catch (error) {
|
|
2014
|
+
console.error('[MediaRecorderService] Failed to start recording:', error);
|
|
2015
|
+
throw this.createError('Failed to start recording', error);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
pause() {
|
|
2019
|
+
if (this.recorder?.state === 'recording') {
|
|
2020
|
+
this.recorder.pause();
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
resume() {
|
|
2024
|
+
if (this.recorder?.state === 'paused') {
|
|
2025
|
+
this.recorder.resume();
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
stop() {
|
|
2029
|
+
if (!this.recorder || this.recorder.state === 'inactive') {
|
|
2030
|
+
return null;
|
|
2031
|
+
}
|
|
2032
|
+
this.recorder.stop();
|
|
2033
|
+
const mimeType = this.recorder.mimeType;
|
|
2034
|
+
const duration = Date.now() - this.startTime;
|
|
2035
|
+
const blob = new Blob(this.chunks, { type: mimeType });
|
|
2036
|
+
const url = URL.createObjectURL(blob);
|
|
2037
|
+
this.recorder = null;
|
|
2038
|
+
this.chunks = [];
|
|
2039
|
+
return { blob, url, mimeType, duration };
|
|
2040
|
+
}
|
|
2041
|
+
getResult() {
|
|
2042
|
+
if (this.chunks.length === 0)
|
|
2043
|
+
return null;
|
|
2044
|
+
const mimeType = this.recorder?.mimeType ?? 'video/webm';
|
|
2045
|
+
const blob = new Blob(this.chunks, { type: mimeType });
|
|
2046
|
+
const url = URL.createObjectURL(blob);
|
|
2047
|
+
const duration = Date.now() - this.startTime;
|
|
2048
|
+
return { blob, url, mimeType, duration };
|
|
2049
|
+
}
|
|
2050
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MediaRecorderService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
2051
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MediaRecorderService });
|
|
2052
|
+
}
|
|
2053
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MediaRecorderService, decorators: [{
|
|
2054
|
+
type: Injectable
|
|
2055
|
+
}] });
|
|
2056
|
+
|
|
2057
|
+
class ServerSentEventsService {
|
|
2058
|
+
destroyRef = inject(DestroyRef);
|
|
2059
|
+
platformId = inject(PLATFORM_ID);
|
|
2060
|
+
sources = new Map();
|
|
2061
|
+
isSupported() {
|
|
2062
|
+
return isPlatformBrowser(this.platformId) && 'EventSource' in window;
|
|
2063
|
+
}
|
|
2064
|
+
ensureSupport() {
|
|
2065
|
+
if (!this.isSupported()) {
|
|
2066
|
+
throw new Error('Server-Sent Events (EventSource) not supported in this environment');
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
connect(url, config = {}) {
|
|
2070
|
+
this.ensureSupport();
|
|
2071
|
+
return new Observable((observer) => {
|
|
2072
|
+
const source = new EventSource(url, { withCredentials: config.withCredentials ?? false });
|
|
2073
|
+
this.sources.set(url, source);
|
|
2074
|
+
const messageHandler = (event) => {
|
|
2075
|
+
try {
|
|
2076
|
+
observer.next({
|
|
2077
|
+
data: JSON.parse(event.data),
|
|
2078
|
+
type: event.type,
|
|
2079
|
+
lastEventId: event.lastEventId,
|
|
2080
|
+
origin: event.origin,
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
catch {
|
|
2084
|
+
observer.next({
|
|
2085
|
+
data: event.data,
|
|
2086
|
+
type: event.type,
|
|
2087
|
+
lastEventId: event.lastEventId,
|
|
2088
|
+
origin: event.origin,
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
};
|
|
2092
|
+
const errorHandler = (event) => {
|
|
2093
|
+
if (source.readyState === EventSource.CLOSED) {
|
|
2094
|
+
observer.error(new Error('SSE connection closed unexpectedly'));
|
|
2095
|
+
}
|
|
2096
|
+
else {
|
|
2097
|
+
console.warn('[ServerSentEventsService] SSE connection error, reconnecting...', event);
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
source.addEventListener('message', messageHandler);
|
|
2101
|
+
source.addEventListener('error', errorHandler);
|
|
2102
|
+
if (config.eventTypes) {
|
|
2103
|
+
for (const type of config.eventTypes) {
|
|
2104
|
+
source.addEventListener(type, messageHandler);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
const cleanup = () => {
|
|
2108
|
+
this.disconnect(url);
|
|
2109
|
+
};
|
|
2110
|
+
this.destroyRef.onDestroy(cleanup);
|
|
2111
|
+
return cleanup;
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
disconnect(url) {
|
|
2115
|
+
const source = this.sources.get(url);
|
|
2116
|
+
if (source) {
|
|
2117
|
+
source.close();
|
|
2118
|
+
this.sources.delete(url);
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
disconnectAll() {
|
|
2122
|
+
this.sources.forEach((source) => source.close());
|
|
2123
|
+
this.sources.clear();
|
|
2124
|
+
}
|
|
2125
|
+
getState(url) {
|
|
2126
|
+
const source = this.sources.get(url);
|
|
2127
|
+
if (!source)
|
|
2128
|
+
return 'closed';
|
|
2129
|
+
const states = ['connecting', 'open', 'closed'];
|
|
2130
|
+
return states[source.readyState] ?? 'closed';
|
|
2131
|
+
}
|
|
2132
|
+
getActiveConnections() {
|
|
2133
|
+
return Array.from(this.sources.keys());
|
|
2134
|
+
}
|
|
2135
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ServerSentEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2136
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ServerSentEventsService });
|
|
2137
|
+
}
|
|
2138
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ServerSentEventsService, decorators: [{
|
|
2139
|
+
type: Injectable
|
|
2140
|
+
}] });
|
|
2141
|
+
|
|
2142
|
+
class VibrationService {
|
|
2143
|
+
platformId = inject(PLATFORM_ID);
|
|
2144
|
+
presets = {
|
|
2145
|
+
success: [50, 30, 50],
|
|
2146
|
+
error: [100, 50, 100, 50, 100],
|
|
2147
|
+
notification: [200],
|
|
2148
|
+
doubleTap: [50, 100, 50],
|
|
2149
|
+
};
|
|
2150
|
+
isSupported() {
|
|
2151
|
+
return isPlatformBrowser(this.platformId) && 'vibrate' in navigator;
|
|
2152
|
+
}
|
|
2153
|
+
vibrate(pattern = 200) {
|
|
2154
|
+
if (!this.isSupported())
|
|
2155
|
+
return false;
|
|
2156
|
+
return navigator.vibrate(pattern);
|
|
2157
|
+
}
|
|
2158
|
+
success() {
|
|
2159
|
+
return this.vibrate(this.presets.success);
|
|
2160
|
+
}
|
|
2161
|
+
error() {
|
|
2162
|
+
return this.vibrate(this.presets.error);
|
|
2163
|
+
}
|
|
2164
|
+
notification() {
|
|
2165
|
+
return this.vibrate(this.presets.notification);
|
|
2166
|
+
}
|
|
2167
|
+
doubleTap() {
|
|
2168
|
+
return this.vibrate(this.presets.doubleTap);
|
|
2169
|
+
}
|
|
2170
|
+
stop() {
|
|
2171
|
+
return this.vibrate(0);
|
|
2172
|
+
}
|
|
2173
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: VibrationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2174
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: VibrationService });
|
|
2175
|
+
}
|
|
2176
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: VibrationService, decorators: [{
|
|
2177
|
+
type: Injectable
|
|
2178
|
+
}] });
|
|
2179
|
+
|
|
2180
|
+
class SpeechSynthesisService {
|
|
2181
|
+
destroyRef = inject(DestroyRef);
|
|
2182
|
+
platformId = inject(PLATFORM_ID);
|
|
2183
|
+
isSupported() {
|
|
2184
|
+
return isPlatformBrowser(this.platformId) && 'speechSynthesis' in window;
|
|
2185
|
+
}
|
|
2186
|
+
ensureSupport() {
|
|
2187
|
+
if (!this.isSupported()) {
|
|
2188
|
+
throw new Error('Speech Synthesis API not supported in this browser');
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
get state() {
|
|
2192
|
+
if (!this.isSupported())
|
|
2193
|
+
return 'idle';
|
|
2194
|
+
if (speechSynthesis.speaking && !speechSynthesis.paused)
|
|
2195
|
+
return 'speaking';
|
|
2196
|
+
if (speechSynthesis.paused)
|
|
2197
|
+
return 'paused';
|
|
2198
|
+
return 'idle';
|
|
2199
|
+
}
|
|
2200
|
+
get isPending() {
|
|
2201
|
+
return this.isSupported() && speechSynthesis.pending;
|
|
2202
|
+
}
|
|
2203
|
+
getVoices() {
|
|
2204
|
+
if (!this.isSupported())
|
|
2205
|
+
return [];
|
|
2206
|
+
return speechSynthesis.getVoices();
|
|
2207
|
+
}
|
|
2208
|
+
watchVoices() {
|
|
2209
|
+
return new Observable((observer) => {
|
|
2210
|
+
if (!this.isSupported()) {
|
|
2211
|
+
observer.next([]);
|
|
2212
|
+
observer.complete();
|
|
2213
|
+
return undefined;
|
|
2214
|
+
}
|
|
2215
|
+
const emit = () => observer.next(speechSynthesis.getVoices());
|
|
2216
|
+
speechSynthesis.addEventListener('voiceschanged', emit);
|
|
2217
|
+
emit();
|
|
2218
|
+
const cleanup = () => speechSynthesis.removeEventListener('voiceschanged', emit);
|
|
2219
|
+
this.destroyRef.onDestroy(cleanup);
|
|
2220
|
+
return cleanup;
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2223
|
+
speak(text, options = {}) {
|
|
2224
|
+
return new Observable((observer) => {
|
|
2225
|
+
this.ensureSupport();
|
|
2226
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
2227
|
+
if (options.lang)
|
|
2228
|
+
utterance.lang = options.lang;
|
|
2229
|
+
if (options.voice)
|
|
2230
|
+
utterance.voice = options.voice;
|
|
2231
|
+
if (options.volume !== undefined)
|
|
2232
|
+
utterance.volume = options.volume;
|
|
2233
|
+
if (options.rate !== undefined)
|
|
2234
|
+
utterance.rate = options.rate;
|
|
2235
|
+
if (options.pitch !== undefined)
|
|
2236
|
+
utterance.pitch = options.pitch;
|
|
2237
|
+
utterance.onstart = () => observer.next('speaking');
|
|
2238
|
+
utterance.onpause = () => observer.next('paused');
|
|
2239
|
+
utterance.onresume = () => observer.next('speaking');
|
|
2240
|
+
utterance.onend = () => {
|
|
2241
|
+
observer.next('idle');
|
|
2242
|
+
observer.complete();
|
|
2243
|
+
};
|
|
2244
|
+
utterance.onerror = (event) => {
|
|
2245
|
+
observer.error(new Error(`Speech synthesis error: ${event.error}`));
|
|
2246
|
+
};
|
|
2247
|
+
observer.next('speaking');
|
|
2248
|
+
speechSynthesis.speak(utterance);
|
|
2249
|
+
const cleanup = () => {
|
|
2250
|
+
speechSynthesis.cancel();
|
|
2251
|
+
observer.next('idle');
|
|
2252
|
+
};
|
|
2253
|
+
this.destroyRef.onDestroy(cleanup);
|
|
2254
|
+
return cleanup;
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
pause() {
|
|
2258
|
+
if (this.isSupported())
|
|
2259
|
+
speechSynthesis.pause();
|
|
2260
|
+
}
|
|
2261
|
+
resume() {
|
|
2262
|
+
if (this.isSupported())
|
|
2263
|
+
speechSynthesis.resume();
|
|
2264
|
+
}
|
|
2265
|
+
cancel() {
|
|
2266
|
+
if (this.isSupported())
|
|
2267
|
+
speechSynthesis.cancel();
|
|
2268
|
+
}
|
|
2269
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SpeechSynthesisService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2270
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SpeechSynthesisService });
|
|
2271
|
+
}
|
|
2272
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SpeechSynthesisService, decorators: [{
|
|
2273
|
+
type: Injectable
|
|
2274
|
+
}] });
|
|
2275
|
+
|
|
2276
|
+
const DEFAULT_OPTIONS = {
|
|
2277
|
+
childList: true,
|
|
2278
|
+
attributes: true,
|
|
2279
|
+
characterData: false,
|
|
2280
|
+
subtree: true,
|
|
2281
|
+
};
|
|
2282
|
+
function isMutationObserverSupported() {
|
|
2283
|
+
return typeof MutationObserver !== 'undefined';
|
|
2284
|
+
}
|
|
2285
|
+
function mutationObserverStream(element, options = DEFAULT_OPTIONS) {
|
|
2286
|
+
return new Observable((subscriber) => {
|
|
2287
|
+
const observer = new MutationObserver((mutations) => {
|
|
2288
|
+
subscriber.next(mutations);
|
|
2289
|
+
});
|
|
2290
|
+
observer.observe(element, options);
|
|
2291
|
+
return () => observer.disconnect();
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
class MutationObserverService {
|
|
2296
|
+
platformId = inject(PLATFORM_ID);
|
|
2297
|
+
isSupported() {
|
|
2298
|
+
return isPlatformBrowser(this.platformId) && isMutationObserverSupported();
|
|
2299
|
+
}
|
|
2300
|
+
observe(target, options) {
|
|
2301
|
+
if (!this.isSupported()) {
|
|
2302
|
+
return new Observable((o) => o.error(new Error('MutationObserver API not supported')));
|
|
2303
|
+
}
|
|
2304
|
+
return mutationObserverStream(target, options);
|
|
2305
|
+
}
|
|
2306
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2307
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService });
|
|
2308
|
+
}
|
|
2309
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService, decorators: [{
|
|
2310
|
+
type: Injectable
|
|
2311
|
+
}] });
|
|
2312
|
+
|
|
2313
|
+
function isPerformanceObserverSupported() {
|
|
2314
|
+
return typeof PerformanceObserver !== 'undefined';
|
|
2315
|
+
}
|
|
2316
|
+
function performanceObserverStream(config) {
|
|
2317
|
+
return new Observable((subscriber) => {
|
|
2318
|
+
const observer = new PerformanceObserver((list) => {
|
|
2319
|
+
subscriber.next(list.getEntries());
|
|
2320
|
+
});
|
|
2321
|
+
if (config.type) {
|
|
2322
|
+
observer.observe({ type: config.type, buffered: config.buffered ?? true });
|
|
2323
|
+
}
|
|
2324
|
+
else if (config.entryTypes) {
|
|
2325
|
+
observer.observe({ entryTypes: config.entryTypes });
|
|
2326
|
+
}
|
|
2327
|
+
return () => observer.disconnect();
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
class PerformanceObserverService {
|
|
2332
|
+
platformId = inject(PLATFORM_ID);
|
|
2333
|
+
isSupported() {
|
|
2334
|
+
return isPlatformBrowser(this.platformId) && isPerformanceObserverSupported();
|
|
2335
|
+
}
|
|
2336
|
+
observe(config) {
|
|
2337
|
+
if (!this.isSupported()) {
|
|
2338
|
+
return new Observable((o) => o.error(new Error('PerformanceObserver API not supported')));
|
|
2339
|
+
}
|
|
2340
|
+
return performanceObserverStream(config);
|
|
2341
|
+
}
|
|
2342
|
+
observeByType(type, buffered = true) {
|
|
2343
|
+
return this.observe({ type, buffered });
|
|
2344
|
+
}
|
|
2345
|
+
getSupportedEntryTypes() {
|
|
2346
|
+
if (!this.isSupported())
|
|
2347
|
+
return [];
|
|
2348
|
+
return (PerformanceObserver.supportedEntryTypes ?? []);
|
|
2349
|
+
}
|
|
2350
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2351
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService });
|
|
2352
|
+
}
|
|
2353
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService, decorators: [{
|
|
2354
|
+
type: Injectable
|
|
2355
|
+
}] });
|
|
2356
|
+
|
|
2357
|
+
function getIdleDetectorClass$1() {
|
|
2358
|
+
return window.IdleDetector;
|
|
2359
|
+
}
|
|
2360
|
+
class IdleDetectorService {
|
|
2361
|
+
platformId = inject(PLATFORM_ID);
|
|
2362
|
+
isSupported() {
|
|
2363
|
+
return isPlatformBrowser(this.platformId) && 'IdleDetector' in window;
|
|
2364
|
+
}
|
|
2365
|
+
async requestPermission() {
|
|
2366
|
+
if (!this.isSupported()) {
|
|
2367
|
+
throw new Error('IdleDetector API not supported');
|
|
2368
|
+
}
|
|
2369
|
+
return getIdleDetectorClass$1().requestPermission();
|
|
2370
|
+
}
|
|
2371
|
+
watch(options = {}) {
|
|
2372
|
+
if (!this.isSupported()) {
|
|
2373
|
+
return new Observable((o) => o.error(new Error('IdleDetector API not supported')));
|
|
2374
|
+
}
|
|
2375
|
+
return new Observable((subscriber) => {
|
|
2376
|
+
const abortController = new AbortController();
|
|
2377
|
+
const detector = new (getIdleDetectorClass$1())();
|
|
2378
|
+
detector.addEventListener('change', () => {
|
|
2379
|
+
subscriber.next({
|
|
2380
|
+
user: detector.userState,
|
|
2381
|
+
screen: detector.screenState,
|
|
2382
|
+
});
|
|
2383
|
+
});
|
|
2384
|
+
detector
|
|
2385
|
+
.start({
|
|
2386
|
+
threshold: options.threshold ?? 60_000,
|
|
2387
|
+
signal: abortController.signal,
|
|
2388
|
+
})
|
|
2389
|
+
.catch((err) => subscriber.error(err));
|
|
2390
|
+
return () => abortController.abort();
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2393
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2394
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService });
|
|
2395
|
+
}
|
|
2396
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, decorators: [{
|
|
2397
|
+
type: Injectable
|
|
2398
|
+
}] });
|
|
2399
|
+
|
|
2400
|
+
function getEyeDropperClass() {
|
|
2401
|
+
return window.EyeDropper;
|
|
2402
|
+
}
|
|
2403
|
+
class EyeDropperService {
|
|
2404
|
+
platformId = inject(PLATFORM_ID);
|
|
2405
|
+
isSupported() {
|
|
2406
|
+
return isPlatformBrowser(this.platformId) && 'EyeDropper' in window;
|
|
2407
|
+
}
|
|
2408
|
+
async open(signal) {
|
|
2409
|
+
if (!this.isSupported()) {
|
|
2410
|
+
throw new Error('EyeDropper API not supported');
|
|
2411
|
+
}
|
|
2412
|
+
const dropper = new (getEyeDropperClass())();
|
|
2413
|
+
return dropper.open(signal ? { signal } : undefined);
|
|
2414
|
+
}
|
|
2415
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2416
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService });
|
|
2417
|
+
}
|
|
2418
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, decorators: [{
|
|
2419
|
+
type: Injectable
|
|
2420
|
+
}] });
|
|
2421
|
+
|
|
2422
|
+
function getBarcodeDetectorClass() {
|
|
2423
|
+
return window.BarcodeDetector;
|
|
2424
|
+
}
|
|
2425
|
+
class BarcodeDetectorService {
|
|
2426
|
+
platformId = inject(PLATFORM_ID);
|
|
2427
|
+
isSupported() {
|
|
2428
|
+
return isPlatformBrowser(this.platformId) && 'BarcodeDetector' in window;
|
|
2429
|
+
}
|
|
2430
|
+
async getSupportedFormats() {
|
|
2431
|
+
if (!this.isSupported())
|
|
2432
|
+
return [];
|
|
2433
|
+
return getBarcodeDetectorClass().getSupportedFormats();
|
|
2434
|
+
}
|
|
2435
|
+
async detect(image, formats) {
|
|
2436
|
+
if (!this.isSupported()) {
|
|
2437
|
+
throw new Error('BarcodeDetector API not supported');
|
|
2438
|
+
}
|
|
2439
|
+
const detector = formats
|
|
2440
|
+
? new (getBarcodeDetectorClass())({ formats })
|
|
2441
|
+
: new (getBarcodeDetectorClass())();
|
|
2442
|
+
return detector.detect(image);
|
|
2443
|
+
}
|
|
2444
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2445
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService });
|
|
2446
|
+
}
|
|
2447
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, decorators: [{
|
|
2448
|
+
type: Injectable
|
|
2449
|
+
}] });
|
|
2450
|
+
|
|
2451
|
+
class WebAudioService {
|
|
2452
|
+
platformId = inject(PLATFORM_ID);
|
|
2453
|
+
destroyRef = inject(DestroyRef);
|
|
2454
|
+
context = null;
|
|
2455
|
+
isSupported() {
|
|
2456
|
+
return isPlatformBrowser(this.platformId) && 'AudioContext' in window;
|
|
2457
|
+
}
|
|
2458
|
+
getContext() {
|
|
2459
|
+
if (!this.isSupported()) {
|
|
2460
|
+
throw new Error('Web Audio API not supported');
|
|
2461
|
+
}
|
|
2462
|
+
if (!this.context || this.context.state === 'closed') {
|
|
2463
|
+
this.context = new AudioContext();
|
|
2464
|
+
this.destroyRef.onDestroy(() => this.close());
|
|
2465
|
+
}
|
|
2466
|
+
return this.context;
|
|
2467
|
+
}
|
|
2468
|
+
async resume() {
|
|
2469
|
+
const ctx = this.getContext();
|
|
2470
|
+
if (ctx.state === 'suspended') {
|
|
2471
|
+
await ctx.resume();
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
async close() {
|
|
2475
|
+
if (this.context && this.context.state !== 'closed') {
|
|
2476
|
+
await this.context.close();
|
|
2477
|
+
this.context = null;
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
getState() {
|
|
2481
|
+
return (this.context?.state ?? 'closed');
|
|
2482
|
+
}
|
|
2483
|
+
createOscillator(type = 'sine', frequency = 440) {
|
|
2484
|
+
const ctx = this.getContext();
|
|
2485
|
+
const oscillator = ctx.createOscillator();
|
|
2486
|
+
oscillator.type = type;
|
|
2487
|
+
oscillator.frequency.value = frequency;
|
|
2488
|
+
return oscillator;
|
|
2489
|
+
}
|
|
2490
|
+
createGain(value = 1) {
|
|
2491
|
+
const ctx = this.getContext();
|
|
2492
|
+
const gain = ctx.createGain();
|
|
2493
|
+
gain.gain.value = value;
|
|
2494
|
+
return gain;
|
|
2495
|
+
}
|
|
2496
|
+
createAnalyser(fftSize = 2048) {
|
|
2497
|
+
const ctx = this.getContext();
|
|
2498
|
+
const analyser = ctx.createAnalyser();
|
|
2499
|
+
analyser.fftSize = fftSize;
|
|
2500
|
+
return analyser;
|
|
2501
|
+
}
|
|
2502
|
+
watchAnalyser(analyser, intervalMs = 50) {
|
|
2503
|
+
return new Observable((subscriber) => {
|
|
2504
|
+
const frequencyData = new Uint8Array(analyser.frequencyBinCount);
|
|
2505
|
+
const timeDomainData = new Uint8Array(analyser.frequencyBinCount);
|
|
2506
|
+
const interval = setInterval(() => {
|
|
2507
|
+
analyser.getByteFrequencyData(frequencyData);
|
|
2508
|
+
analyser.getByteTimeDomainData(timeDomainData);
|
|
2509
|
+
subscriber.next({
|
|
2510
|
+
frequencyData: new Uint8Array(frequencyData),
|
|
2511
|
+
timeDomainData: new Uint8Array(timeDomainData),
|
|
2512
|
+
});
|
|
2513
|
+
}, intervalMs);
|
|
2514
|
+
return () => clearInterval(interval);
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
async decodeAudioData(arrayBuffer) {
|
|
2518
|
+
const ctx = this.getContext();
|
|
2519
|
+
return ctx.decodeAudioData(arrayBuffer);
|
|
2520
|
+
}
|
|
2521
|
+
playBuffer(buffer, loop = false) {
|
|
2522
|
+
const ctx = this.getContext();
|
|
2523
|
+
const source = ctx.createBufferSource();
|
|
2524
|
+
source.buffer = buffer;
|
|
2525
|
+
source.loop = loop;
|
|
2526
|
+
source.connect(ctx.destination);
|
|
2527
|
+
source.start(0);
|
|
2528
|
+
return source;
|
|
2529
|
+
}
|
|
2530
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2531
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService });
|
|
2532
|
+
}
|
|
2533
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService, decorators: [{
|
|
2534
|
+
type: Injectable
|
|
2535
|
+
}] });
|
|
2536
|
+
|
|
2537
|
+
function isGamepadSupported() {
|
|
2538
|
+
return typeof navigator !== 'undefined' && 'getGamepads' in navigator;
|
|
2539
|
+
}
|
|
2540
|
+
function gamepadSnapshot(index) {
|
|
2541
|
+
const gp = navigator.getGamepads()[index];
|
|
2542
|
+
if (!gp)
|
|
2543
|
+
return null;
|
|
2544
|
+
return {
|
|
2545
|
+
id: gp.id,
|
|
2546
|
+
index: gp.index,
|
|
2547
|
+
connected: gp.connected,
|
|
2548
|
+
buttons: gp.buttons.map((b) => ({ pressed: b.pressed, value: b.value })),
|
|
2549
|
+
axes: Array.from(gp.axes),
|
|
2550
|
+
timestamp: gp.timestamp,
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
function gamepadConnectionStream() {
|
|
2554
|
+
return new Observable((subscriber) => {
|
|
2555
|
+
const onConnect = (e) => {
|
|
2556
|
+
const gp = e.gamepad;
|
|
2557
|
+
subscriber.next({
|
|
2558
|
+
type: 'connected',
|
|
2559
|
+
gamepad: {
|
|
2560
|
+
id: gp.id,
|
|
2561
|
+
index: gp.index,
|
|
2562
|
+
connected: true,
|
|
2563
|
+
buttons: gp.buttons.map((b) => ({ pressed: b.pressed, value: b.value })),
|
|
2564
|
+
axes: Array.from(gp.axes),
|
|
2565
|
+
timestamp: gp.timestamp,
|
|
2566
|
+
},
|
|
2567
|
+
});
|
|
2568
|
+
};
|
|
2569
|
+
const onDisconnect = (e) => {
|
|
2570
|
+
subscriber.next({
|
|
2571
|
+
type: 'disconnected',
|
|
2572
|
+
gamepad: {
|
|
2573
|
+
id: e.gamepad.id,
|
|
2574
|
+
index: e.gamepad.index,
|
|
2575
|
+
connected: false,
|
|
2576
|
+
buttons: [],
|
|
2577
|
+
axes: [],
|
|
2578
|
+
timestamp: e.gamepad.timestamp,
|
|
2579
|
+
},
|
|
2580
|
+
});
|
|
2581
|
+
};
|
|
2582
|
+
window.addEventListener('gamepadconnected', onConnect);
|
|
2583
|
+
window.addEventListener('gamepaddisconnected', onDisconnect);
|
|
2584
|
+
return () => {
|
|
2585
|
+
window.removeEventListener('gamepadconnected', onConnect);
|
|
2586
|
+
window.removeEventListener('gamepaddisconnected', onDisconnect);
|
|
2587
|
+
};
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
function gamepadPollStream(index, intervalMs = 16) {
|
|
2591
|
+
return new Observable((subscriber) => {
|
|
2592
|
+
let rafId;
|
|
2593
|
+
const poll = () => {
|
|
2594
|
+
const state = gamepadSnapshot(index);
|
|
2595
|
+
if (state) {
|
|
2596
|
+
subscriber.next(state);
|
|
2597
|
+
}
|
|
2598
|
+
rafId = requestAnimationFrame(poll);
|
|
2599
|
+
};
|
|
2600
|
+
if (intervalMs <= 16) {
|
|
2601
|
+
rafId = requestAnimationFrame(poll);
|
|
2602
|
+
return () => cancelAnimationFrame(rafId);
|
|
2603
|
+
}
|
|
2604
|
+
const intervalId = setInterval(() => {
|
|
2605
|
+
const state = gamepadSnapshot(index);
|
|
2606
|
+
if (state)
|
|
2607
|
+
subscriber.next(state);
|
|
2608
|
+
}, intervalMs);
|
|
2609
|
+
return () => clearInterval(intervalId);
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
class GamepadService {
|
|
2614
|
+
platformId = inject(PLATFORM_ID);
|
|
2615
|
+
isSupported() {
|
|
2616
|
+
return isPlatformBrowser(this.platformId) && isGamepadSupported();
|
|
2617
|
+
}
|
|
2618
|
+
getSnapshot(index) {
|
|
2619
|
+
if (!this.isSupported())
|
|
2620
|
+
return null;
|
|
2621
|
+
return gamepadSnapshot(index);
|
|
2622
|
+
}
|
|
2623
|
+
getConnectedGamepads() {
|
|
2624
|
+
if (!this.isSupported())
|
|
2625
|
+
return [];
|
|
2626
|
+
return navigator
|
|
2627
|
+
.getGamepads()
|
|
2628
|
+
.filter((gp) => gp !== null)
|
|
2629
|
+
.map((gp) => ({
|
|
2630
|
+
id: gp.id,
|
|
2631
|
+
index: gp.index,
|
|
2632
|
+
connected: gp.connected,
|
|
2633
|
+
buttons: gp.buttons.map((b) => ({ pressed: b.pressed, value: b.value })),
|
|
2634
|
+
axes: Array.from(gp.axes),
|
|
2635
|
+
timestamp: gp.timestamp,
|
|
2636
|
+
}));
|
|
2637
|
+
}
|
|
2638
|
+
watchConnections() {
|
|
2639
|
+
if (!this.isSupported()) {
|
|
2640
|
+
return new Observable((o) => o.error(new Error('Gamepad API not supported')));
|
|
2641
|
+
}
|
|
2642
|
+
return gamepadConnectionStream();
|
|
2643
|
+
}
|
|
2644
|
+
poll(index, intervalMs = 16) {
|
|
2645
|
+
if (!this.isSupported()) {
|
|
2646
|
+
return new Observable((o) => o.error(new Error('Gamepad API not supported')));
|
|
2647
|
+
}
|
|
2648
|
+
return gamepadPollStream(index, intervalMs);
|
|
2649
|
+
}
|
|
2650
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2651
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService });
|
|
2652
|
+
}
|
|
2653
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService, decorators: [{
|
|
2654
|
+
type: Injectable
|
|
2655
|
+
}] });
|
|
2656
|
+
|
|
2657
|
+
function getBluetooth() {
|
|
2658
|
+
return navigator.bluetooth;
|
|
2659
|
+
}
|
|
2660
|
+
class WebBluetoothService {
|
|
2661
|
+
platformId = inject(PLATFORM_ID);
|
|
2662
|
+
isSupported() {
|
|
2663
|
+
return isPlatformBrowser(this.platformId) && !!getBluetooth();
|
|
2664
|
+
}
|
|
2665
|
+
async requestDevice(options = { acceptAllDevices: true }) {
|
|
2666
|
+
if (!this.isSupported()) {
|
|
2667
|
+
throw new Error('Web Bluetooth API not supported');
|
|
2668
|
+
}
|
|
2669
|
+
return getBluetooth().requestDevice(options);
|
|
2670
|
+
}
|
|
2671
|
+
async connect(device) {
|
|
2672
|
+
if (!device.gatt) {
|
|
2673
|
+
throw new Error('GATT server not available on this device');
|
|
2674
|
+
}
|
|
2675
|
+
return device.gatt.connect();
|
|
2676
|
+
}
|
|
2677
|
+
disconnect(device) {
|
|
2678
|
+
device.gatt?.disconnect();
|
|
2679
|
+
}
|
|
2680
|
+
watchDisconnection(device) {
|
|
2681
|
+
return new Observable((subscriber) => {
|
|
2682
|
+
const handler = () => subscriber.next();
|
|
2683
|
+
device.addEventListener('gattserverdisconnected', handler);
|
|
2684
|
+
return () => device.removeEventListener('gattserverdisconnected', handler);
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
async readCharacteristic(server, serviceUuid, characteristicUuid) {
|
|
2688
|
+
const service = await server.getPrimaryService(serviceUuid);
|
|
2689
|
+
const characteristic = await service.getCharacteristic(characteristicUuid);
|
|
2690
|
+
return characteristic.readValue();
|
|
2691
|
+
}
|
|
2692
|
+
async writeCharacteristic(server, serviceUuid, characteristicUuid, value) {
|
|
2693
|
+
const service = await server.getPrimaryService(serviceUuid);
|
|
2694
|
+
const characteristic = await service.getCharacteristic(characteristicUuid);
|
|
2695
|
+
await characteristic.writeValue(value);
|
|
2696
|
+
}
|
|
2697
|
+
watchCharacteristic(server, serviceUuid, characteristicUuid) {
|
|
2698
|
+
return new Observable((subscriber) => {
|
|
2699
|
+
let characteristic;
|
|
2700
|
+
server
|
|
2701
|
+
.getPrimaryService(serviceUuid)
|
|
2702
|
+
.then((service) => service.getCharacteristic(characteristicUuid))
|
|
2703
|
+
.then((char) => {
|
|
2704
|
+
characteristic = char;
|
|
2705
|
+
const handler = (event) => {
|
|
2706
|
+
const target = event.target;
|
|
2707
|
+
if (target.value)
|
|
2708
|
+
subscriber.next(target.value);
|
|
2709
|
+
};
|
|
2710
|
+
characteristic.addEventListener('characteristicvaluechanged', handler);
|
|
2711
|
+
return characteristic.startNotifications();
|
|
2712
|
+
})
|
|
2713
|
+
.catch((err) => subscriber.error(err));
|
|
2714
|
+
return () => {
|
|
2715
|
+
characteristic?.stopNotifications().catch(() => { });
|
|
2716
|
+
};
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2720
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService });
|
|
2721
|
+
}
|
|
2722
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, decorators: [{
|
|
2723
|
+
type: Injectable
|
|
2724
|
+
}] });
|
|
2725
|
+
|
|
2726
|
+
function getUsb() {
|
|
2727
|
+
return navigator.usb;
|
|
2728
|
+
}
|
|
2729
|
+
class WebUsbService {
|
|
2730
|
+
platformId = inject(PLATFORM_ID);
|
|
2731
|
+
isSupported() {
|
|
2732
|
+
return isPlatformBrowser(this.platformId) && !!getUsb();
|
|
2733
|
+
}
|
|
2734
|
+
async requestDevice(filters = []) {
|
|
2735
|
+
if (!this.isSupported()) {
|
|
2736
|
+
throw new Error('WebUSB API not supported');
|
|
2737
|
+
}
|
|
2738
|
+
return getUsb().requestDevice({ filters });
|
|
2739
|
+
}
|
|
2740
|
+
async getDevices() {
|
|
2741
|
+
if (!this.isSupported())
|
|
2742
|
+
return [];
|
|
2743
|
+
return getUsb().getDevices();
|
|
2744
|
+
}
|
|
2745
|
+
async open(device) {
|
|
2746
|
+
await device.open();
|
|
2747
|
+
}
|
|
2748
|
+
async close(device) {
|
|
2749
|
+
await device.close();
|
|
2750
|
+
}
|
|
2751
|
+
async selectConfiguration(device, configurationValue) {
|
|
2752
|
+
await device.selectConfiguration(configurationValue);
|
|
2753
|
+
}
|
|
2754
|
+
async claimInterface(device, interfaceNumber) {
|
|
2755
|
+
await device.claimInterface(interfaceNumber);
|
|
2756
|
+
}
|
|
2757
|
+
async releaseInterface(device, interfaceNumber) {
|
|
2758
|
+
await device.releaseInterface(interfaceNumber);
|
|
2759
|
+
}
|
|
2760
|
+
async transferIn(device, endpointNumber, length) {
|
|
2761
|
+
return device.transferIn(endpointNumber, length);
|
|
2762
|
+
}
|
|
2763
|
+
async transferOut(device, endpointNumber, data) {
|
|
2764
|
+
return device.transferOut(endpointNumber, data);
|
|
2765
|
+
}
|
|
2766
|
+
watchConnection() {
|
|
2767
|
+
if (!this.isSupported()) {
|
|
2768
|
+
return new Observable((o) => o.error(new Error('WebUSB API not supported')));
|
|
2769
|
+
}
|
|
2770
|
+
return new Observable((subscriber) => {
|
|
2771
|
+
const usb = getUsb();
|
|
2772
|
+
const onConnect = (e) => subscriber.next({ device: e.device, type: 'connect' });
|
|
2773
|
+
const onDisconnect = (e) => subscriber.next({ device: e.device, type: 'disconnect' });
|
|
2774
|
+
usb.addEventListener('connect', onConnect);
|
|
2775
|
+
usb.addEventListener('disconnect', onDisconnect);
|
|
2776
|
+
return () => {
|
|
2777
|
+
usb.removeEventListener('connect', onConnect);
|
|
2778
|
+
usb.removeEventListener('disconnect', onDisconnect);
|
|
2779
|
+
};
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
getDeviceInfo(device) {
|
|
2783
|
+
return {
|
|
2784
|
+
vendorId: device.vendorId,
|
|
2785
|
+
productId: device.productId,
|
|
2786
|
+
productName: device.productName,
|
|
2787
|
+
manufacturerName: device.manufacturerName,
|
|
2788
|
+
serialNumber: device.serialNumber,
|
|
2789
|
+
opened: device.opened,
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2793
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService });
|
|
2794
|
+
}
|
|
2795
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, decorators: [{
|
|
2796
|
+
type: Injectable
|
|
2797
|
+
}] });
|
|
2798
|
+
|
|
2799
|
+
function getNdefReaderClass() {
|
|
2800
|
+
return window.NDEFReader;
|
|
2801
|
+
}
|
|
2802
|
+
class WebNfcService {
|
|
2803
|
+
platformId = inject(PLATFORM_ID);
|
|
2804
|
+
isSupported() {
|
|
2805
|
+
return isPlatformBrowser(this.platformId) && 'NDEFReader' in window;
|
|
2806
|
+
}
|
|
2807
|
+
scan() {
|
|
2808
|
+
if (!this.isSupported()) {
|
|
2809
|
+
return new Observable((o) => o.error(new Error('Web NFC API not supported')));
|
|
2810
|
+
}
|
|
2811
|
+
return new Observable((subscriber) => {
|
|
2812
|
+
const abortController = new AbortController();
|
|
2813
|
+
const reader = new (getNdefReaderClass())();
|
|
2814
|
+
const onReading = (event) => {
|
|
2815
|
+
const e = event;
|
|
2816
|
+
subscriber.next({
|
|
2817
|
+
serialNumber: e.serialNumber,
|
|
2818
|
+
message: e.message,
|
|
2819
|
+
});
|
|
2820
|
+
};
|
|
2821
|
+
const onError = (event) => {
|
|
2822
|
+
subscriber.error(event.error ?? new Error('NFC read error'));
|
|
2823
|
+
};
|
|
2824
|
+
reader.addEventListener('reading', onReading);
|
|
2825
|
+
reader.addEventListener('readingerror', onError);
|
|
2826
|
+
reader
|
|
2827
|
+
.scan({ signal: abortController.signal })
|
|
2828
|
+
.catch((err) => subscriber.error(err));
|
|
2829
|
+
return () => abortController.abort();
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
async write(message, options) {
|
|
2833
|
+
if (!this.isSupported()) {
|
|
2834
|
+
throw new Error('Web NFC API not supported');
|
|
2835
|
+
}
|
|
2836
|
+
const reader = new (getNdefReaderClass())();
|
|
2837
|
+
await reader.write(message, options);
|
|
2838
|
+
}
|
|
2839
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2840
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService });
|
|
2841
|
+
}
|
|
2842
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, decorators: [{
|
|
2843
|
+
type: Injectable
|
|
2844
|
+
}] });
|
|
2845
|
+
|
|
2846
|
+
class PaymentRequestService {
|
|
2847
|
+
platformId = inject(PLATFORM_ID);
|
|
2848
|
+
isSupported() {
|
|
2849
|
+
return isPlatformBrowser(this.platformId) && 'PaymentRequest' in window;
|
|
2850
|
+
}
|
|
2851
|
+
async canMakePayment(methods, details) {
|
|
2852
|
+
if (!this.isSupported())
|
|
2853
|
+
return false;
|
|
2854
|
+
const request = new PaymentRequest(methods, details);
|
|
2855
|
+
return request.canMakePayment();
|
|
2856
|
+
}
|
|
2857
|
+
async show(methods, details, options) {
|
|
2858
|
+
if (!this.isSupported()) {
|
|
2859
|
+
throw new Error('Payment Request API not supported');
|
|
2860
|
+
}
|
|
2861
|
+
const request = new PaymentRequest(methods, details, options);
|
|
2862
|
+
const response = await request.show();
|
|
2863
|
+
const result = {
|
|
2864
|
+
methodName: response.methodName,
|
|
2865
|
+
details: response.details,
|
|
2866
|
+
payerName: response.payerName ?? null,
|
|
2867
|
+
payerEmail: response.payerEmail ?? null,
|
|
2868
|
+
payerPhone: response.payerPhone ?? null,
|
|
2869
|
+
};
|
|
2870
|
+
await response.complete('success');
|
|
2871
|
+
return result;
|
|
2872
|
+
}
|
|
2873
|
+
async abort(methods, details) {
|
|
2874
|
+
if (!this.isSupported())
|
|
2875
|
+
return;
|
|
2876
|
+
const request = new PaymentRequest(methods, details);
|
|
2877
|
+
await request.abort();
|
|
2878
|
+
}
|
|
2879
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2880
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService });
|
|
2881
|
+
}
|
|
2882
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, decorators: [{
|
|
2883
|
+
type: Injectable
|
|
2884
|
+
}] });
|
|
2885
|
+
|
|
2886
|
+
class CredentialManagementService {
|
|
2887
|
+
platformId = inject(PLATFORM_ID);
|
|
2888
|
+
isSupported() {
|
|
2889
|
+
return isPlatformBrowser(this.platformId) && 'credentials' in navigator;
|
|
2890
|
+
}
|
|
2891
|
+
isPublicKeySupported() {
|
|
2892
|
+
return this.isSupported() && 'PublicKeyCredential' in window;
|
|
2893
|
+
}
|
|
2894
|
+
async get(options) {
|
|
2895
|
+
if (!this.isSupported()) {
|
|
2896
|
+
throw new Error('Credential Management API not supported');
|
|
2897
|
+
}
|
|
2898
|
+
return navigator.credentials.get(options);
|
|
2899
|
+
}
|
|
2900
|
+
async store(credential) {
|
|
2901
|
+
if (!this.isSupported()) {
|
|
2902
|
+
throw new Error('Credential Management API not supported');
|
|
2903
|
+
}
|
|
2904
|
+
await navigator.credentials.store(credential);
|
|
2905
|
+
}
|
|
2906
|
+
async createPasswordCredential(data) {
|
|
2907
|
+
if (!this.isSupported()) {
|
|
2908
|
+
throw new Error('Credential Management API not supported');
|
|
2909
|
+
}
|
|
2910
|
+
return navigator.credentials.create({
|
|
2911
|
+
password: data,
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
async createPublicKeyCredential(options) {
|
|
2915
|
+
if (!this.isPublicKeySupported()) {
|
|
2916
|
+
throw new Error('PublicKeyCredential API not supported');
|
|
2917
|
+
}
|
|
2918
|
+
return navigator.credentials.create({
|
|
2919
|
+
publicKey: options,
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
async preventSilentAccess() {
|
|
2923
|
+
if (!this.isSupported())
|
|
2924
|
+
return;
|
|
2925
|
+
await navigator.credentials.preventSilentAccess();
|
|
2926
|
+
}
|
|
2927
|
+
async isConditionalMediationAvailable() {
|
|
2928
|
+
if (!this.isPublicKeySupported())
|
|
2929
|
+
return false;
|
|
2930
|
+
if ('isConditionalMediationAvailable' in PublicKeyCredential) {
|
|
2931
|
+
return PublicKeyCredential.isConditionalMediationAvailable();
|
|
2932
|
+
}
|
|
2933
|
+
return false;
|
|
2934
|
+
}
|
|
2935
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2936
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService });
|
|
2937
|
+
}
|
|
2938
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, decorators: [{
|
|
2939
|
+
type: Injectable
|
|
2940
|
+
}] });
|
|
2941
|
+
|
|
1293
2942
|
// Common types for browser APIs
|
|
1294
2943
|
|
|
2944
|
+
function injectPageVisibility() {
|
|
2945
|
+
const destroyRef = inject(DestroyRef);
|
|
2946
|
+
const platformId = inject(PLATFORM_ID);
|
|
2947
|
+
const initial = isPlatformBrowser(platformId) && typeof document !== 'undefined'
|
|
2948
|
+
? document.visibilityState
|
|
2949
|
+
: 'visible';
|
|
2950
|
+
const state = signal(initial, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
2951
|
+
const sub = pageVisibilityStream().subscribe((s) => state.set(s));
|
|
2952
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
2953
|
+
return {
|
|
2954
|
+
state: state.asReadonly(),
|
|
2955
|
+
isVisible: computed(() => state() === 'visible'),
|
|
2956
|
+
isHidden: computed(() => state() !== 'visible'),
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
function injectResizeObserver(elementOrRef, options) {
|
|
2961
|
+
const destroyRef = inject(DestroyRef);
|
|
2962
|
+
const platformId = inject(PLATFORM_ID);
|
|
2963
|
+
const size = signal(null, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2964
|
+
if (isPlatformBrowser(platformId) && isResizeObserverSupported()) {
|
|
2965
|
+
if (isSignal(elementOrRef)) {
|
|
2966
|
+
let sub;
|
|
2967
|
+
effect((onCleanup) => {
|
|
2968
|
+
sub?.unsubscribe();
|
|
2969
|
+
const raw = elementOrRef();
|
|
2970
|
+
if (raw) {
|
|
2971
|
+
const el = raw instanceof ElementRef ? raw.nativeElement : raw;
|
|
2972
|
+
sub = resizeObserverStream(el, options).subscribe((s) => size.set(s));
|
|
2973
|
+
}
|
|
2974
|
+
onCleanup(() => sub?.unsubscribe());
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
else {
|
|
2978
|
+
const el = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
|
|
2979
|
+
const sub = resizeObserverStream(el, options).subscribe((s) => size.set(s));
|
|
2980
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
return {
|
|
2984
|
+
size: size.asReadonly(),
|
|
2985
|
+
width: computed(() => size()?.width ?? 0),
|
|
2986
|
+
height: computed(() => size()?.height ?? 0),
|
|
2987
|
+
inlineSize: computed(() => size()?.inlineSize ?? 0),
|
|
2988
|
+
blockSize: computed(() => size()?.blockSize ?? 0),
|
|
2989
|
+
};
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
function injectIntersectionObserver(elementOrRef, options) {
|
|
2993
|
+
const destroyRef = inject(DestroyRef);
|
|
2994
|
+
const platformId = inject(PLATFORM_ID);
|
|
2995
|
+
const isIntersecting = signal(false, ...(ngDevMode ? [{ debugName: "isIntersecting" }] : /* istanbul ignore next */ []));
|
|
2996
|
+
if (isPlatformBrowser(platformId) && isIntersectionObserverSupported()) {
|
|
2997
|
+
if (isSignal(elementOrRef)) {
|
|
2998
|
+
let sub;
|
|
2999
|
+
effect((onCleanup) => {
|
|
3000
|
+
sub?.unsubscribe();
|
|
3001
|
+
const raw = elementOrRef();
|
|
3002
|
+
if (raw) {
|
|
3003
|
+
const el = raw instanceof ElementRef ? raw.nativeElement : raw;
|
|
3004
|
+
sub = intersectionObserverStream(el, options).subscribe((v) => isIntersecting.set(v));
|
|
3005
|
+
}
|
|
3006
|
+
onCleanup(() => sub?.unsubscribe());
|
|
3007
|
+
});
|
|
3008
|
+
}
|
|
3009
|
+
else {
|
|
3010
|
+
const el = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
|
|
3011
|
+
const sub = intersectionObserverStream(el, options).subscribe((v) => isIntersecting.set(v));
|
|
3012
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
return {
|
|
3016
|
+
isIntersecting: isIntersecting.asReadonly(),
|
|
3017
|
+
isVisible: computed(() => isIntersecting()),
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
function injectNetworkInformation() {
|
|
3022
|
+
const destroyRef = inject(DestroyRef);
|
|
3023
|
+
const platformId = inject(PLATFORM_ID);
|
|
3024
|
+
const snapshot = signal(isPlatformBrowser(platformId) ? getNetworkSnapshot() : { online: true }, ...(ngDevMode ? [{ debugName: "snapshot" }] : /* istanbul ignore next */ []));
|
|
3025
|
+
const sub = networkInformationStream().subscribe((n) => snapshot.set(n));
|
|
3026
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3027
|
+
return {
|
|
3028
|
+
snapshot: snapshot.asReadonly(),
|
|
3029
|
+
online: computed(() => snapshot().online),
|
|
3030
|
+
effectiveType: computed(() => snapshot().effectiveType),
|
|
3031
|
+
downlink: computed(() => snapshot().downlink),
|
|
3032
|
+
rtt: computed(() => snapshot().rtt),
|
|
3033
|
+
type: computed(() => snapshot().type),
|
|
3034
|
+
saveData: computed(() => snapshot().saveData),
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
|
|
3038
|
+
function injectScreenOrientation() {
|
|
3039
|
+
const destroyRef = inject(DestroyRef);
|
|
3040
|
+
const platformId = inject(PLATFORM_ID);
|
|
3041
|
+
const orientation = signal(isPlatformBrowser(platformId)
|
|
3042
|
+
? getOrientationSnapshot()
|
|
3043
|
+
: { type: 'portrait-primary', angle: 0 }, ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
|
|
3044
|
+
const sub = screenOrientationStream().subscribe((o) => orientation.set(o));
|
|
3045
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3046
|
+
return {
|
|
3047
|
+
orientation: orientation.asReadonly(),
|
|
3048
|
+
type: computed(() => orientation().type),
|
|
3049
|
+
angle: computed(() => orientation().angle),
|
|
3050
|
+
isPortrait: computed(() => orientation().type.startsWith('portrait')),
|
|
3051
|
+
isLandscape: computed(() => orientation().type.startsWith('landscape')),
|
|
3052
|
+
async lock(o) {
|
|
3053
|
+
await screen.orientation.lock(o);
|
|
3054
|
+
},
|
|
3055
|
+
unlock() {
|
|
3056
|
+
screen.orientation.unlock();
|
|
3057
|
+
},
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
function injectMutationObserver(elementOrRef, options) {
|
|
3062
|
+
const destroyRef = inject(DestroyRef);
|
|
3063
|
+
const platformId = inject(PLATFORM_ID);
|
|
3064
|
+
const mutations = signal([], ...(ngDevMode ? [{ debugName: "mutations" }] : /* istanbul ignore next */ []));
|
|
3065
|
+
if (isPlatformBrowser(platformId) && isMutationObserverSupported()) {
|
|
3066
|
+
if (isSignal(elementOrRef)) {
|
|
3067
|
+
let sub;
|
|
3068
|
+
effect((onCleanup) => {
|
|
3069
|
+
sub?.unsubscribe();
|
|
3070
|
+
const raw = elementOrRef();
|
|
3071
|
+
if (raw) {
|
|
3072
|
+
const el = raw instanceof ElementRef ? raw.nativeElement : raw;
|
|
3073
|
+
sub = mutationObserverStream(el, options).subscribe((m) => mutations.set(m));
|
|
3074
|
+
}
|
|
3075
|
+
onCleanup(() => sub?.unsubscribe());
|
|
3076
|
+
});
|
|
3077
|
+
}
|
|
3078
|
+
else {
|
|
3079
|
+
const el = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
|
|
3080
|
+
const sub = mutationObserverStream(el, options).subscribe((m) => mutations.set(m));
|
|
3081
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
return {
|
|
3085
|
+
mutations: mutations.asReadonly(),
|
|
3086
|
+
mutationCount: computed(() => mutations().length),
|
|
3087
|
+
};
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
function injectPerformanceObserver(config) {
|
|
3091
|
+
const destroyRef = inject(DestroyRef);
|
|
3092
|
+
const platformId = inject(PLATFORM_ID);
|
|
3093
|
+
const entries = signal([], ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
|
|
3094
|
+
if (isPlatformBrowser(platformId) && isPerformanceObserverSupported()) {
|
|
3095
|
+
const sub = performanceObserverStream(config).subscribe((e) => entries.set(e));
|
|
3096
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3097
|
+
}
|
|
3098
|
+
return {
|
|
3099
|
+
entries: entries.asReadonly(),
|
|
3100
|
+
entryCount: computed(() => entries().length),
|
|
3101
|
+
latestEntry: computed(() => entries().at(-1)),
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
function getIdleDetectorClass() {
|
|
3106
|
+
return window.IdleDetector;
|
|
3107
|
+
}
|
|
3108
|
+
function injectIdleDetector(options = {}) {
|
|
3109
|
+
const destroyRef = inject(DestroyRef);
|
|
3110
|
+
const platformId = inject(PLATFORM_ID);
|
|
3111
|
+
const defaultState = { user: 'active', screen: 'unlocked' };
|
|
3112
|
+
const state = signal(defaultState, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
3113
|
+
if (isPlatformBrowser(platformId) && 'IdleDetector' in window) {
|
|
3114
|
+
const abortController = new AbortController();
|
|
3115
|
+
const detector = new (getIdleDetectorClass())();
|
|
3116
|
+
detector.addEventListener('change', () => {
|
|
3117
|
+
state.set({
|
|
3118
|
+
user: detector.userState,
|
|
3119
|
+
screen: detector.screenState,
|
|
3120
|
+
});
|
|
3121
|
+
});
|
|
3122
|
+
detector
|
|
3123
|
+
.start({
|
|
3124
|
+
threshold: options.threshold ?? 60_000,
|
|
3125
|
+
signal: abortController.signal,
|
|
3126
|
+
})
|
|
3127
|
+
.catch(() => {
|
|
3128
|
+
/* permission denied or unsupported — keep defaults */
|
|
3129
|
+
});
|
|
3130
|
+
destroyRef.onDestroy(() => abortController.abort());
|
|
3131
|
+
}
|
|
3132
|
+
return {
|
|
3133
|
+
state: state.asReadonly(),
|
|
3134
|
+
userState: computed(() => state().user),
|
|
3135
|
+
screenState: computed(() => state().screen),
|
|
3136
|
+
isUserIdle: computed(() => state().user === 'idle'),
|
|
3137
|
+
isScreenLocked: computed(() => state().screen === 'locked'),
|
|
3138
|
+
};
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
function injectGamepad(index, intervalMs = 16) {
|
|
3142
|
+
const destroyRef = inject(DestroyRef);
|
|
3143
|
+
const platformId = inject(PLATFORM_ID);
|
|
3144
|
+
const state = signal(null, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
3145
|
+
if (isPlatformBrowser(platformId) && isGamepadSupported()) {
|
|
3146
|
+
const sub = gamepadPollStream(index, intervalMs).subscribe((s) => state.set(s));
|
|
3147
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3148
|
+
}
|
|
3149
|
+
return {
|
|
3150
|
+
state: state.asReadonly(),
|
|
3151
|
+
connected: computed(() => state()?.connected ?? false),
|
|
3152
|
+
buttons: computed(() => state()?.buttons ?? []),
|
|
3153
|
+
axes: computed(() => state()?.axes ?? []),
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
|
|
1295
3157
|
class BrowserSupportUtil {
|
|
1296
3158
|
static isSupported(feature) {
|
|
1297
3159
|
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
@@ -1417,6 +3279,31 @@ const defaultBrowserWebApisConfig = {
|
|
|
1417
3279
|
enableWebStorage: false,
|
|
1418
3280
|
enableWebSocket: false,
|
|
1419
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,
|
|
1420
3307
|
};
|
|
1421
3308
|
function provideBrowserWebApis(config = {}) {
|
|
1422
3309
|
const mergedConfig = { ...defaultBrowserWebApisConfig, ...config };
|
|
@@ -1432,6 +3319,31 @@ function provideBrowserWebApis(config = {}) {
|
|
|
1432
3319
|
[mergedConfig.enableWebStorage, WebStorageService],
|
|
1433
3320
|
[mergedConfig.enableWebSocket, WebSocketService],
|
|
1434
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],
|
|
1435
3347
|
];
|
|
1436
3348
|
for (const [enabled, provider] of conditionalProviders) {
|
|
1437
3349
|
if (enabled) {
|
|
@@ -1492,6 +3404,81 @@ function provideCommunicationApis() {
|
|
|
1492
3404
|
WebSocketService,
|
|
1493
3405
|
]);
|
|
1494
3406
|
}
|
|
3407
|
+
function provideIntersectionObserver() {
|
|
3408
|
+
return makeEnvironmentProviders([IntersectionObserverService]);
|
|
3409
|
+
}
|
|
3410
|
+
function provideResizeObserver() {
|
|
3411
|
+
return makeEnvironmentProviders([ResizeObserverService]);
|
|
3412
|
+
}
|
|
3413
|
+
function providePageVisibility() {
|
|
3414
|
+
return makeEnvironmentProviders([PageVisibilityService]);
|
|
3415
|
+
}
|
|
3416
|
+
function provideBroadcastChannel() {
|
|
3417
|
+
return makeEnvironmentProviders([BroadcastChannelService]);
|
|
3418
|
+
}
|
|
3419
|
+
function provideNetworkInformation() {
|
|
3420
|
+
return makeEnvironmentProviders([NetworkInformationService]);
|
|
3421
|
+
}
|
|
3422
|
+
function provideScreenWakeLock() {
|
|
3423
|
+
return makeEnvironmentProviders([PermissionsService, ScreenWakeLockService]);
|
|
3424
|
+
}
|
|
3425
|
+
function provideScreenOrientation() {
|
|
3426
|
+
return makeEnvironmentProviders([ScreenOrientationService]);
|
|
3427
|
+
}
|
|
3428
|
+
function provideFullscreen() {
|
|
3429
|
+
return makeEnvironmentProviders([FullscreenService]);
|
|
3430
|
+
}
|
|
3431
|
+
function provideFileSystemAccess() {
|
|
3432
|
+
return makeEnvironmentProviders([PermissionsService, FileSystemAccessService]);
|
|
3433
|
+
}
|
|
3434
|
+
function provideMediaRecorder() {
|
|
3435
|
+
return makeEnvironmentProviders([PermissionsService, MediaRecorderService]);
|
|
3436
|
+
}
|
|
3437
|
+
function provideServerSentEvents() {
|
|
3438
|
+
return makeEnvironmentProviders([ServerSentEventsService]);
|
|
3439
|
+
}
|
|
3440
|
+
function provideVibration() {
|
|
3441
|
+
return makeEnvironmentProviders([VibrationService]);
|
|
3442
|
+
}
|
|
3443
|
+
function provideSpeechSynthesis() {
|
|
3444
|
+
return makeEnvironmentProviders([SpeechSynthesisService]);
|
|
3445
|
+
}
|
|
3446
|
+
function provideMutationObserver() {
|
|
3447
|
+
return makeEnvironmentProviders([MutationObserverService]);
|
|
3448
|
+
}
|
|
3449
|
+
function providePerformanceObserver() {
|
|
3450
|
+
return makeEnvironmentProviders([PerformanceObserverService]);
|
|
3451
|
+
}
|
|
3452
|
+
function provideIdleDetector() {
|
|
3453
|
+
return makeEnvironmentProviders([PermissionsService, IdleDetectorService]);
|
|
3454
|
+
}
|
|
3455
|
+
function provideEyeDropper() {
|
|
3456
|
+
return makeEnvironmentProviders([EyeDropperService]);
|
|
3457
|
+
}
|
|
3458
|
+
function provideBarcodeDetector() {
|
|
3459
|
+
return makeEnvironmentProviders([BarcodeDetectorService]);
|
|
3460
|
+
}
|
|
3461
|
+
function provideWebAudio() {
|
|
3462
|
+
return makeEnvironmentProviders([WebAudioService]);
|
|
3463
|
+
}
|
|
3464
|
+
function provideGamepad() {
|
|
3465
|
+
return makeEnvironmentProviders([GamepadService]);
|
|
3466
|
+
}
|
|
3467
|
+
function provideWebBluetooth() {
|
|
3468
|
+
return makeEnvironmentProviders([WebBluetoothService]);
|
|
3469
|
+
}
|
|
3470
|
+
function provideWebUsb() {
|
|
3471
|
+
return makeEnvironmentProviders([WebUsbService]);
|
|
3472
|
+
}
|
|
3473
|
+
function provideWebNfc() {
|
|
3474
|
+
return makeEnvironmentProviders([WebNfcService]);
|
|
3475
|
+
}
|
|
3476
|
+
function providePaymentRequest() {
|
|
3477
|
+
return makeEnvironmentProviders([PaymentRequestService]);
|
|
3478
|
+
}
|
|
3479
|
+
function provideCredentialManagement() {
|
|
3480
|
+
return makeEnvironmentProviders([CredentialManagementService]);
|
|
3481
|
+
}
|
|
1495
3482
|
|
|
1496
3483
|
// Browser Web APIs Services
|
|
1497
3484
|
// Version
|
|
@@ -1501,4 +3488,4 @@ const version = '0.1.0';
|
|
|
1501
3488
|
* Generated bundle index. Do not edit.
|
|
1502
3489
|
*/
|
|
1503
3490
|
|
|
1504
|
-
export { BatteryService, BrowserApiBaseService, BrowserCapabilityService, BrowserSupportUtil, CameraService, ClipboardService, GeolocationService, MediaDevicesService, NotificationService, PermissionsService, WebShareService, WebSocketService, WebStorageService, WebWorkerService, permissionGuard as createPermissionGuard, defaultBrowserWebApisConfig, permissionGuard, provideBattery, provideBrowserWebApis, provideCamera, provideClipboard, provideCommunicationApis, provideGeolocation, provideLocationApis, provideMediaApis, provideMediaDevices, provideNotifications, providePermissions, provideStorageApis, provideWebShare, provideWebSocket, provideWebStorage, provideWebWorker, version };
|
|
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 };
|