@angular-helpers/browser-web-apis 21.5.0 → 21.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, DestroyRef, PLATFORM_ID, Injectable, signal, computed, isSignal, effect, ElementRef, makeEnvironmentProviders } from '@angular/core';
3
3
  import { isPlatformBrowser, isPlatformServer } from '@angular/common';
4
- import { Observable, fromEvent, BehaviorSubject, Subject, of, map as map$1 } 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';
@@ -1036,196 +1036,424 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
1036
1036
  type: Injectable
1037
1037
  }], ctorParameters: () => [] });
1038
1038
 
1039
- class WebSocketService extends BrowserApiBaseService {
1040
- webSocket = null;
1041
- statusSubject = new BehaviorSubject({
1042
- connected: false,
1043
- connecting: false,
1044
- reconnecting: false,
1045
- reconnectAttempts: 0,
1046
- });
1047
- messageSubject = new Subject();
1048
- reconnectAttempts = 0;
1039
+ const DEFAULT_MAX_RECONNECT_DELAY = 30_000;
1040
+ const DEFAULT_REQUEST_TIMEOUT = 30_000;
1041
+ /**
1042
+ * Stateful WebSocket client wrapping a single connection. One instance per logical
1043
+ * connection (do NOT share between `connect()` calls).
1044
+ *
1045
+ * Surfaces:
1046
+ * - `status`: signal of the current connection state.
1047
+ * - `messages$`: stream of every received message (parsed JSON).
1048
+ * - `send` / `sendRaw`: outbound traffic.
1049
+ * - `request<T>(type, data)`: round-trip with id correlation and timeout.
1050
+ * - `close`: idempotent disposal.
1051
+ *
1052
+ * Reconnect uses exponential backoff with jitter, capped by `maxReconnectDelay`.
1053
+ */
1054
+ class WebSocketClient {
1055
+ config;
1056
+ logger;
1057
+ socket = null;
1049
1058
  reconnectTimer = null;
1050
1059
  heartbeatTimer = null;
1051
- _cleanup = this.destroyRef.onDestroy(() => this.disconnect());
1052
- getApiName() {
1053
- return 'websocket';
1054
- }
1055
- ensureSupported() {
1056
- super.ensureSupported();
1057
- if (typeof WebSocket === 'undefined') {
1058
- throw new Error('WebSocket API not supported in this browser');
1060
+ _status;
1061
+ _messages$ = new Subject();
1062
+ pendingRequests = new Map();
1063
+ disposed = false;
1064
+ reconnectAttempts = 0;
1065
+ constructor(config, logger, destroyRef) {
1066
+ this.config = config;
1067
+ this.logger = logger;
1068
+ this._status = signal({
1069
+ state: 'idle',
1070
+ reconnectAttempts: 0,
1071
+ error: null,
1072
+ }, ...(ngDevMode ? [{ debugName: "_status" }] : /* istanbul ignore next */ []));
1073
+ if (destroyRef) {
1074
+ destroyRef.onDestroy(() => this.close());
1059
1075
  }
1076
+ this.openSocket();
1060
1077
  }
1061
- connect(config) {
1062
- this.ensureSupported();
1063
- return new Observable((observer) => {
1064
- this.disconnect(); // Disconnect existing connection if any
1065
- this.updateStatus({
1066
- connected: false,
1067
- connecting: true,
1068
- reconnecting: false,
1069
- reconnectAttempts: 0,
1070
- });
1071
- try {
1072
- this.webSocket = new WebSocket(config.url, config.protocols);
1073
- this.setupWebSocketHandlers(config);
1074
- observer.next(this.statusSubject.getValue());
1075
- }
1076
- catch (error) {
1077
- this.logError('Error creating WebSocket:', error);
1078
- this.updateStatus({
1079
- connected: false,
1080
- connecting: false,
1081
- reconnecting: false,
1082
- error: error instanceof Error ? error.message : 'Connection failed',
1083
- reconnectAttempts: 0,
1084
- });
1085
- observer.next(this.statusSubject.getValue());
1086
- }
1087
- return () => {
1088
- this.disconnect();
1089
- };
1090
- });
1078
+ get status() {
1079
+ return this._status.asReadonly();
1091
1080
  }
1092
- disconnect() {
1093
- if (this.reconnectTimer) {
1094
- clearTimeout(this.reconnectTimer);
1095
- this.reconnectTimer = null;
1096
- }
1097
- if (this.heartbeatTimer) {
1098
- clearInterval(this.heartbeatTimer);
1099
- this.heartbeatTimer = null;
1100
- }
1101
- if (this.webSocket) {
1102
- this.webSocket.close();
1103
- this.webSocket = null;
1104
- }
1105
- this.updateStatus({
1106
- connected: false,
1107
- connecting: false,
1108
- reconnecting: false,
1109
- reconnectAttempts: 0,
1110
- });
1081
+ get messages$() {
1082
+ return this._messages$.asObservable();
1083
+ }
1084
+ messagesByType(type) {
1085
+ return this._messages$
1086
+ .asObservable()
1087
+ .pipe(filter((msg) => msg.type === type));
1111
1088
  }
1112
1089
  send(message) {
1113
- if (!this.webSocket || this.webSocket.readyState !== WebSocket.OPEN) {
1090
+ if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
1114
1091
  throw new Error('WebSocket is not connected');
1115
1092
  }
1116
- const messageWithTimestamp = {
1093
+ const enriched = {
1117
1094
  ...message,
1118
- timestamp: Date.now(),
1095
+ id: message.id ?? this.generateId(),
1096
+ timestamp: message.timestamp ?? Date.now(),
1119
1097
  };
1120
- this.webSocket.send(JSON.stringify(messageWithTimestamp));
1098
+ this.socket.send(JSON.stringify(enriched));
1121
1099
  }
1122
1100
  sendRaw(data) {
1123
- if (!this.webSocket || this.webSocket.readyState !== WebSocket.OPEN) {
1101
+ if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
1124
1102
  throw new Error('WebSocket is not connected');
1125
1103
  }
1126
- this.webSocket.send(data);
1104
+ this.socket.send(data);
1127
1105
  }
1128
- getStatus() {
1129
- return this.statusSubject.asObservable();
1106
+ /**
1107
+ * Send a message and await a correlated response. The server MUST echo back the
1108
+ * `correlationId` from the request as `correlationId` on the response message.
1109
+ */
1110
+ request(type, data, opts) {
1111
+ const id = this.generateId();
1112
+ const timeoutMs = opts?.timeout ?? DEFAULT_REQUEST_TIMEOUT;
1113
+ return new Promise((resolve, reject) => {
1114
+ const timer = setTimeout(() => {
1115
+ this.pendingRequests.delete(id);
1116
+ reject(new Error(`WebSocket request timeout after ${timeoutMs}ms`));
1117
+ }, timeoutMs);
1118
+ this.pendingRequests.set(id, {
1119
+ resolve: resolve,
1120
+ reject,
1121
+ timer,
1122
+ });
1123
+ try {
1124
+ this.send({ id, type, data, correlationId: id });
1125
+ }
1126
+ catch (error) {
1127
+ clearTimeout(timer);
1128
+ this.pendingRequests.delete(id);
1129
+ reject(error instanceof Error ? error : new Error('WebSocket send failed'));
1130
+ }
1131
+ });
1130
1132
  }
1131
- getMessages() {
1132
- return this.messageSubject.asObservable();
1133
+ close() {
1134
+ if (this.disposed)
1135
+ return;
1136
+ this.disposed = true;
1137
+ this.clearTimers();
1138
+ if (this.socket) {
1139
+ try {
1140
+ this.socket.close();
1141
+ }
1142
+ catch {
1143
+ // Ignore — already closing.
1144
+ }
1145
+ this.socket = null;
1146
+ }
1147
+ this.rejectAllPending(new Error('WebSocket closed'));
1148
+ this.updateStatus({ state: 'closed', error: null });
1133
1149
  }
1134
- getMessagesByType(type) {
1135
- return this.messageSubject
1136
- .asObservable()
1137
- .pipe(filter((msg) => msg.type === type));
1150
+ /** Internal handle for tests and advanced usage. */
1151
+ getNativeSocket() {
1152
+ return this.socket;
1153
+ }
1154
+ // ---------- internals ----------
1155
+ openSocket() {
1156
+ if (this.disposed)
1157
+ return;
1158
+ this.updateStatus({ state: 'connecting', error: null });
1159
+ try {
1160
+ this.socket = new WebSocket(this.config.url, this.config.protocols);
1161
+ this.attachHandlers();
1162
+ }
1163
+ catch (error) {
1164
+ const message = error instanceof Error ? error.message : 'WebSocket open failed';
1165
+ this.logger.error('[websocket] Failed to construct socket', error);
1166
+ this.updateStatus({ state: 'closed', error: message });
1167
+ this.scheduleReconnect();
1168
+ }
1138
1169
  }
1139
- setupWebSocketHandlers(config) {
1140
- if (!this.webSocket)
1170
+ attachHandlers() {
1171
+ if (!this.socket)
1141
1172
  return;
1142
- this.webSocket.onopen = () => {
1143
- this.logInfo(`Connected to: ${config.url}`);
1173
+ this.socket.onopen = () => {
1144
1174
  this.reconnectAttempts = 0;
1145
- this.updateStatus({
1146
- connected: true,
1147
- connecting: false,
1148
- reconnecting: false,
1149
- reconnectAttempts: 0,
1150
- });
1151
- // Start heartbeat if configured
1152
- if (config.heartbeatInterval && config.heartbeatMessage) {
1153
- this.startHeartbeat(config);
1154
- }
1175
+ this.updateStatus({ state: 'open', error: null, reconnectAttempts: 0 });
1176
+ this.startHeartbeat();
1155
1177
  };
1156
- this.webSocket.onclose = (event) => {
1157
- this.logInfo(`Connection closed: ${event.code} ${event.reason}`);
1178
+ this.socket.onclose = (event) => {
1179
+ this.stopHeartbeat();
1180
+ if (this.disposed)
1181
+ return;
1158
1182
  this.updateStatus({
1159
- connected: false,
1160
- connecting: false,
1161
- reconnecting: false,
1162
- reconnectAttempts: this.reconnectAttempts,
1183
+ state: 'closed',
1184
+ error: event.wasClean ? null : `closed: ${event.code} ${event.reason}`,
1163
1185
  });
1164
- // Attempt reconnection if not a clean close and reconnect is enabled
1165
- if (!event.wasClean && config.reconnectInterval && config.maxReconnectAttempts) {
1166
- this.attemptReconnect(config);
1186
+ if (!event.wasClean) {
1187
+ this.scheduleReconnect();
1167
1188
  }
1168
1189
  };
1169
- this.webSocket.onerror = (error) => {
1170
- this.logError('WebSocket error:', error);
1171
- this.updateStatus({
1172
- connected: false,
1173
- connecting: false,
1174
- reconnecting: false,
1175
- error: 'WebSocket connection error',
1176
- reconnectAttempts: this.reconnectAttempts,
1177
- });
1190
+ this.socket.onerror = () => {
1191
+ this.updateStatus({ error: 'WebSocket connection error' });
1178
1192
  };
1179
- this.webSocket.onmessage = (event) => {
1180
- try {
1181
- const message = JSON.parse(event.data);
1182
- this.messageSubject.next(message);
1183
- }
1184
- catch (error) {
1185
- this.logError('Error parsing message:', error);
1186
- }
1193
+ this.socket.onmessage = (event) => {
1194
+ this.handleIncoming(event.data);
1187
1195
  };
1188
1196
  }
1189
- startHeartbeat(config) {
1190
- this.heartbeatTimer = setInterval(() => {
1191
- if (this.webSocket && this.webSocket.readyState === WebSocket.OPEN) {
1192
- this.send({
1193
- type: 'heartbeat',
1194
- data: config.heartbeatMessage,
1195
- });
1196
- }
1197
- }, config.heartbeatInterval);
1197
+ handleIncoming(raw) {
1198
+ let message;
1199
+ try {
1200
+ const text = typeof raw === 'string' ? raw : String(raw);
1201
+ message = JSON.parse(text);
1202
+ }
1203
+ catch (error) {
1204
+ this.logger.warn('[websocket] Failed to parse incoming message');
1205
+ this.logger.error('[websocket] parse error', error);
1206
+ return;
1207
+ }
1208
+ const correlationId = message.correlationId ?? message.id;
1209
+ if (correlationId && this.pendingRequests.has(correlationId)) {
1210
+ const pending = this.pendingRequests.get(correlationId);
1211
+ clearTimeout(pending.timer);
1212
+ this.pendingRequests.delete(correlationId);
1213
+ pending.resolve(message.data);
1214
+ return;
1215
+ }
1216
+ this._messages$.next(message);
1198
1217
  }
1199
- attemptReconnect(config) {
1200
- if (this.reconnectAttempts >= (config.maxReconnectAttempts || 5)) {
1201
- this.logInfo('Max reconnect attempts reached');
1218
+ scheduleReconnect() {
1219
+ if (this.disposed)
1220
+ return;
1221
+ const interval = this.config.reconnectInterval ?? 0;
1222
+ const maxAttempts = this.config.maxReconnectAttempts ?? 0;
1223
+ if (interval <= 0 || maxAttempts <= 0)
1224
+ return;
1225
+ if (this.reconnectAttempts >= maxAttempts) {
1226
+ this.updateStatus({
1227
+ state: 'closed',
1228
+ error: `Max reconnect attempts (${maxAttempts}) reached`,
1229
+ });
1202
1230
  return;
1203
1231
  }
1204
- this.reconnectAttempts++;
1232
+ this.reconnectAttempts += 1;
1233
+ const delay = WebSocketClient.computeBackoffDelay(this.reconnectAttempts, interval, this.config.maxReconnectDelay ?? DEFAULT_MAX_RECONNECT_DELAY);
1205
1234
  this.updateStatus({
1206
- connected: false,
1207
- connecting: false,
1208
- reconnecting: true,
1235
+ state: 'reconnecting',
1209
1236
  reconnectAttempts: this.reconnectAttempts,
1210
1237
  });
1211
1238
  this.reconnectTimer = setTimeout(() => {
1212
- this.logInfo(`Reconnect attempt ${this.reconnectAttempts}`);
1213
- this.connect(config);
1214
- }, config.reconnectInterval || 3000);
1239
+ this.reconnectTimer = null;
1240
+ this.openSocket();
1241
+ }, delay);
1215
1242
  }
1216
- updateStatus(status) {
1217
- const newStatus = { ...this.statusSubject.getValue(), ...status };
1218
- this.statusSubject.next(newStatus);
1243
+ /**
1244
+ * Exponential backoff with full jitter:
1245
+ * baseDelay = min(maxDelay, interval * 2^(attempt - 1))
1246
+ * delay = random(0, baseDelay)
1247
+ */
1248
+ static computeBackoffDelay(attempt, interval, maxDelay) {
1249
+ const exp = Math.min(maxDelay, interval * Math.pow(2, attempt - 1));
1250
+ return Math.floor(Math.random() * exp);
1251
+ }
1252
+ startHeartbeat() {
1253
+ const { heartbeatInterval, heartbeatMessage } = this.config;
1254
+ if (!heartbeatInterval || heartbeatMessage === undefined)
1255
+ return;
1256
+ this.stopHeartbeat();
1257
+ this.heartbeatTimer = setInterval(() => {
1258
+ if (this.socket && this.socket.readyState === WebSocket.OPEN) {
1259
+ try {
1260
+ this.send({ type: 'heartbeat', data: heartbeatMessage });
1261
+ }
1262
+ catch (error) {
1263
+ this.logger.warn('[websocket] heartbeat send failed');
1264
+ this.logger.error('[websocket] heartbeat error', error);
1265
+ }
1266
+ }
1267
+ }, heartbeatInterval);
1268
+ }
1269
+ stopHeartbeat() {
1270
+ if (this.heartbeatTimer) {
1271
+ clearInterval(this.heartbeatTimer);
1272
+ this.heartbeatTimer = null;
1273
+ }
1274
+ }
1275
+ clearTimers() {
1276
+ if (this.reconnectTimer) {
1277
+ clearTimeout(this.reconnectTimer);
1278
+ this.reconnectTimer = null;
1279
+ }
1280
+ this.stopHeartbeat();
1281
+ }
1282
+ rejectAllPending(reason) {
1283
+ this.pendingRequests.forEach((entry) => {
1284
+ clearTimeout(entry.timer);
1285
+ entry.reject(reason);
1286
+ });
1287
+ this.pendingRequests.clear();
1288
+ }
1289
+ updateStatus(partial) {
1290
+ this._status.update((current) => ({ ...current, ...partial }));
1291
+ }
1292
+ generateId() {
1293
+ if (typeof globalThis.crypto?.randomUUID === 'function') {
1294
+ return globalThis.crypto.randomUUID();
1295
+ }
1296
+ return `ws-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
1297
+ }
1298
+ }
1299
+
1300
+ let legacyDeprecationLogged = false;
1301
+ /**
1302
+ * Service that creates and tracks `WebSocketClient` instances.
1303
+ *
1304
+ * Preferred usage:
1305
+ * ```ts
1306
+ * const ws = inject(WebSocketService);
1307
+ * const client = ws.createClient({ url: 'wss://...' });
1308
+ * effect(() => console.log(client.status()));
1309
+ * await client.request('ping', {});
1310
+ * ```
1311
+ *
1312
+ * Legacy usage (`connect()` returning Observable) is preserved for one minor cycle
1313
+ * and will be removed in v22.
1314
+ */
1315
+ class WebSocketService extends BrowserApiBaseService {
1316
+ wsLogger = inject(BROWSER_API_LOGGER);
1317
+ clients = new Set();
1318
+ _cleanup = this.destroyRef.onDestroy(() => this.disposeAll());
1319
+ /** Legacy single-connection holder used by deprecated `connect()`/`send()` API. */
1320
+ legacyClient = null;
1321
+ getApiName() {
1322
+ return 'websocket';
1323
+ }
1324
+ ensureSupported() {
1325
+ super.ensureSupported();
1326
+ if (typeof WebSocket === 'undefined') {
1327
+ throw new Error('WebSocket API not supported in this browser');
1328
+ }
1329
+ }
1330
+ /**
1331
+ * Create a new WebSocket client. The client owns one connection and is the recommended
1332
+ * surface for all interactions (status signal, request/response, reconnect, etc.).
1333
+ *
1334
+ * The returned client is automatically disposed when the host injector is destroyed.
1335
+ */
1336
+ createClient(config) {
1337
+ this.ensureSupported();
1338
+ const client = new WebSocketClient(config, this.wsLogger, this.destroyRef);
1339
+ this.clients.add(client);
1340
+ return client;
1341
+ }
1342
+ /** Dispose every client created via `createClient()` (also called automatically on destroy). */
1343
+ disposeAll() {
1344
+ for (const client of this.clients) {
1345
+ client.close();
1346
+ }
1347
+ this.clients.clear();
1348
+ if (this.legacyClient) {
1349
+ this.legacyClient.close();
1350
+ this.legacyClient = null;
1351
+ }
1352
+ }
1353
+ // ---------- legacy API (deprecated) ----------
1354
+ /**
1355
+ * @deprecated Use {@link createClient} which returns a `WebSocketClient` exposing a
1356
+ * status signal, request/response, and proper reconnect. This wrapper will be removed
1357
+ * in v22.
1358
+ */
1359
+ connect(config) {
1360
+ this.ensureSupported();
1361
+ this.warnLegacyOnce();
1362
+ return new Observable((observer) => {
1363
+ if (this.legacyClient) {
1364
+ this.legacyClient.close();
1365
+ }
1366
+ const client = new WebSocketClient(config, this.wsLogger);
1367
+ this.legacyClient = client;
1368
+ const sub = toObservableLike(client).subscribe({
1369
+ next: (status) => observer.next(status),
1370
+ error: (err) => observer.error(err),
1371
+ });
1372
+ return () => {
1373
+ sub.unsubscribe();
1374
+ client.close();
1375
+ if (this.legacyClient === client) {
1376
+ this.legacyClient = null;
1377
+ }
1378
+ };
1379
+ });
1380
+ }
1381
+ /** @deprecated Use {@link createClient} and call `client.close()`. */
1382
+ disconnect() {
1383
+ if (this.legacyClient) {
1384
+ this.legacyClient.close();
1385
+ this.legacyClient = null;
1386
+ }
1387
+ }
1388
+ /** @deprecated Use the client returned by {@link createClient}. */
1389
+ send(message) {
1390
+ if (!this.legacyClient) {
1391
+ throw new Error('No active legacy WebSocket. Call connect() first or use createClient().');
1392
+ }
1393
+ this.legacyClient.send(message);
1394
+ }
1395
+ /** @deprecated Use the client returned by {@link createClient}. */
1396
+ sendRaw(data) {
1397
+ if (!this.legacyClient) {
1398
+ throw new Error('No active legacy WebSocket. Call connect() first or use createClient().');
1399
+ }
1400
+ this.legacyClient.sendRaw(data);
1401
+ }
1402
+ /** @deprecated Use `client.status` from {@link createClient}. */
1403
+ getStatus() {
1404
+ return new Observable((observer) => {
1405
+ if (!this.legacyClient) {
1406
+ observer.next({
1407
+ connected: false,
1408
+ connecting: false,
1409
+ reconnecting: false,
1410
+ reconnectAttempts: 0,
1411
+ });
1412
+ return () => {
1413
+ // No-op
1414
+ };
1415
+ }
1416
+ const sub = toObservableLike(this.legacyClient).subscribe((status) => observer.next(status));
1417
+ return () => sub.unsubscribe();
1418
+ });
1219
1419
  }
1220
- // Direct access to native WebSocket
1420
+ /** @deprecated Use `client.messages$` from {@link createClient}. */
1421
+ getMessages() {
1422
+ if (!this.legacyClient) {
1423
+ return new Observable(() => {
1424
+ // No-op stream until connected.
1425
+ });
1426
+ }
1427
+ return this.legacyClient.messages$;
1428
+ }
1429
+ /** @deprecated Use `client.messagesByType()` from {@link createClient}. */
1430
+ getMessagesByType(type) {
1431
+ if (!this.legacyClient) {
1432
+ return new Observable(() => {
1433
+ // No-op stream until connected.
1434
+ });
1435
+ }
1436
+ return this.legacyClient.messagesByType(type);
1437
+ }
1438
+ /** @deprecated Use the client returned by {@link createClient}. */
1221
1439
  getNativeWebSocket() {
1222
- return this.webSocket;
1440
+ return this.legacyClient?.getNativeSocket() ?? null;
1223
1441
  }
1442
+ /** @deprecated Use `client.status()` from {@link createClient}. */
1224
1443
  isConnected() {
1225
- return this.webSocket?.readyState === WebSocket.OPEN;
1444
+ return this.legacyClient?.status().state === 'open';
1226
1445
  }
1446
+ /** @deprecated Use the native socket via `client.getNativeSocket()`. */
1227
1447
  getReadyState() {
1228
- return this.webSocket?.readyState ?? WebSocket.CLOSED;
1448
+ return this.legacyClient?.getNativeSocket()?.readyState ?? WebSocket.CLOSED;
1449
+ }
1450
+ warnLegacyOnce() {
1451
+ if (legacyDeprecationLogged)
1452
+ return;
1453
+ legacyDeprecationLogged = true;
1454
+ this.wsLogger.warn('[websocket] WebSocketService.connect() is deprecated. Use WebSocketService.createClient() ' +
1455
+ 'which returns a WebSocketClient with a status signal, request/response, and proper reconnect. ' +
1456
+ 'The legacy API will be removed in v22.');
1229
1457
  }
1230
1458
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebSocketService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1231
1459
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebSocketService });
@@ -1233,6 +1461,27 @@ class WebSocketService extends BrowserApiBaseService {
1233
1461
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebSocketService, decorators: [{
1234
1462
  type: Injectable
1235
1463
  }] });
1464
+ /**
1465
+ * Build a stream of legacy `WebSocketStatus` snapshots from a v2 client. Used to keep the
1466
+ * deprecated `connect()` API behaving like before (Observable of legacy status).
1467
+ */
1468
+ function toObservableLike(client) {
1469
+ return new Observable((observer) => {
1470
+ const emit = () => {
1471
+ const v2 = client.status();
1472
+ observer.next({
1473
+ connected: v2.state === 'open',
1474
+ connecting: v2.state === 'connecting',
1475
+ reconnecting: v2.state === 'reconnecting',
1476
+ error: v2.error ?? undefined,
1477
+ reconnectAttempts: v2.reconnectAttempts,
1478
+ });
1479
+ };
1480
+ emit();
1481
+ const id = setInterval(emit, 100);
1482
+ return () => clearInterval(id);
1483
+ });
1484
+ }
1236
1485
 
1237
1486
  class WebWorkerService extends BrowserApiBaseService {
1238
1487
  workers = new Map();
@@ -2441,106 +2690,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2441
2690
  type: Injectable
2442
2691
  }] });
2443
2692
 
2444
- function getIdleDetectorClass$1() {
2445
- return window.IdleDetector;
2446
- }
2447
- class IdleDetectorService extends BrowserApiBaseService {
2448
- getApiName() {
2449
- return 'idle-detector';
2450
- }
2451
- isSupported() {
2452
- return this.isBrowserEnvironment() && 'IdleDetector' in window;
2453
- }
2454
- async requestPermission() {
2455
- if (!this.isSupported()) {
2456
- throw new Error('IdleDetector API not supported');
2457
- }
2458
- return getIdleDetectorClass$1().requestPermission();
2459
- }
2460
- watch(options = {}) {
2461
- if (!this.isSupported()) {
2462
- return new Observable((o) => o.error(new Error('IdleDetector API not supported')));
2463
- }
2464
- return new Observable((subscriber) => {
2465
- const abortController = new AbortController();
2466
- const detector = new (getIdleDetectorClass$1())();
2467
- detector.addEventListener('change', () => {
2468
- subscriber.next({
2469
- user: detector.userState,
2470
- screen: detector.screenState,
2471
- });
2472
- });
2473
- detector
2474
- .start({
2475
- threshold: options.threshold ?? 60_000,
2476
- signal: abortController.signal,
2477
- })
2478
- .catch((err) => subscriber.error(err));
2479
- return () => abortController.abort();
2480
- });
2481
- }
2482
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2483
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService });
2484
- }
2485
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, decorators: [{
2486
- type: Injectable
2487
- }] });
2488
-
2489
- function getEyeDropperClass() {
2490
- return window.EyeDropper;
2491
- }
2492
- class EyeDropperService extends BrowserApiBaseService {
2493
- getApiName() {
2494
- return 'eye-dropper';
2495
- }
2496
- isSupported() {
2497
- return this.isBrowserEnvironment() && 'EyeDropper' in window;
2498
- }
2499
- async open(signal) {
2500
- if (!this.isSupported()) {
2501
- throw new Error('EyeDropper API not supported');
2502
- }
2503
- const dropper = new (getEyeDropperClass())();
2504
- return dropper.open(signal ? { signal } : undefined);
2505
- }
2506
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2507
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService });
2508
- }
2509
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, decorators: [{
2510
- type: Injectable
2511
- }] });
2512
-
2513
- function getBarcodeDetectorClass() {
2514
- return window.BarcodeDetector;
2515
- }
2516
- class BarcodeDetectorService extends BrowserApiBaseService {
2517
- getApiName() {
2518
- return 'barcode-detector';
2519
- }
2520
- isSupported() {
2521
- return this.isBrowserEnvironment() && 'BarcodeDetector' in window;
2522
- }
2523
- async getSupportedFormats() {
2524
- if (!this.isSupported())
2525
- return [];
2526
- return getBarcodeDetectorClass().getSupportedFormats();
2527
- }
2528
- async detect(image, formats) {
2529
- if (!this.isSupported()) {
2530
- throw new Error('BarcodeDetector API not supported');
2531
- }
2532
- const detector = formats
2533
- ? new (getBarcodeDetectorClass())({ formats })
2534
- : new (getBarcodeDetectorClass())();
2535
- return detector.detect(image);
2536
- }
2537
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2538
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService });
2539
- }
2540
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, decorators: [{
2541
- type: Injectable
2542
- }] });
2543
-
2544
2693
  class WebAudioService extends BrowserApiBaseService {
2545
2694
  getApiName() {
2546
2695
  return 'web-audio';
@@ -2750,301 +2899,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
2750
2899
  type: Injectable
2751
2900
  }] });
2752
2901
 
2753
- function getBluetooth() {
2754
- return navigator.bluetooth;
2755
- }
2756
- class WebBluetoothService extends BrowserApiBaseService {
2757
- getApiName() {
2758
- return 'web-bluetooth';
2759
- }
2760
- isSupported() {
2761
- return this.isBrowserEnvironment() && !!getBluetooth();
2762
- }
2763
- async requestDevice(options = { acceptAllDevices: true }) {
2764
- if (!this.isSupported()) {
2765
- throw new Error('Web Bluetooth API not supported');
2766
- }
2767
- return getBluetooth().requestDevice(options);
2768
- }
2769
- async connect(device) {
2770
- if (!device.gatt) {
2771
- throw new Error('GATT server not available on this device');
2772
- }
2773
- return device.gatt.connect();
2774
- }
2775
- disconnect(device) {
2776
- device.gatt?.disconnect();
2777
- }
2778
- watchDisconnection(device) {
2779
- return new Observable((subscriber) => {
2780
- const handler = () => subscriber.next();
2781
- device.addEventListener('gattserverdisconnected', handler);
2782
- return () => device.removeEventListener('gattserverdisconnected', handler);
2783
- });
2784
- }
2785
- async readCharacteristic(server, serviceUuid, characteristicUuid) {
2786
- const service = await server.getPrimaryService(serviceUuid);
2787
- const characteristic = await service.getCharacteristic(characteristicUuid);
2788
- return characteristic.readValue();
2789
- }
2790
- async writeCharacteristic(server, serviceUuid, characteristicUuid, value) {
2791
- const service = await server.getPrimaryService(serviceUuid);
2792
- const characteristic = await service.getCharacteristic(characteristicUuid);
2793
- await characteristic.writeValue(value);
2794
- }
2795
- watchCharacteristic(server, serviceUuid, characteristicUuid) {
2796
- return new Observable((subscriber) => {
2797
- let characteristic;
2798
- server
2799
- .getPrimaryService(serviceUuid)
2800
- .then((service) => service.getCharacteristic(characteristicUuid))
2801
- .then((char) => {
2802
- characteristic = char;
2803
- const handler = (event) => {
2804
- const target = event.target;
2805
- if (target.value)
2806
- subscriber.next(target.value);
2807
- };
2808
- characteristic.addEventListener('characteristicvaluechanged', handler);
2809
- return characteristic.startNotifications();
2810
- })
2811
- .catch((err) => subscriber.error(err));
2812
- return () => {
2813
- characteristic?.stopNotifications().catch(() => { });
2814
- };
2815
- });
2816
- }
2817
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2818
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService });
2819
- }
2820
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, decorators: [{
2821
- type: Injectable
2822
- }] });
2823
-
2824
- function getUsb() {
2825
- return navigator.usb;
2826
- }
2827
- class WebUsbService extends BrowserApiBaseService {
2828
- getApiName() {
2829
- return 'web-usb';
2830
- }
2831
- isSupported() {
2832
- return this.isBrowserEnvironment() && !!getUsb();
2833
- }
2834
- async requestDevice(filters = []) {
2835
- if (!this.isSupported()) {
2836
- throw new Error('WebUSB API not supported');
2837
- }
2838
- return getUsb().requestDevice({ filters });
2839
- }
2840
- async getDevices() {
2841
- if (!this.isSupported())
2842
- return [];
2843
- return getUsb().getDevices();
2844
- }
2845
- async open(device) {
2846
- await device.open();
2847
- }
2848
- async close(device) {
2849
- await device.close();
2850
- }
2851
- async selectConfiguration(device, configurationValue) {
2852
- await device.selectConfiguration(configurationValue);
2853
- }
2854
- async claimInterface(device, interfaceNumber) {
2855
- await device.claimInterface(interfaceNumber);
2856
- }
2857
- async releaseInterface(device, interfaceNumber) {
2858
- await device.releaseInterface(interfaceNumber);
2859
- }
2860
- async transferIn(device, endpointNumber, length) {
2861
- return device.transferIn(endpointNumber, length);
2862
- }
2863
- async transferOut(device, endpointNumber, data) {
2864
- return device.transferOut(endpointNumber, data);
2865
- }
2866
- watchConnection() {
2867
- if (!this.isSupported()) {
2868
- return new Observable((o) => o.error(new Error('WebUSB API not supported')));
2869
- }
2870
- return new Observable((subscriber) => {
2871
- const usb = getUsb();
2872
- const onConnect = (e) => subscriber.next({ device: e.device, type: 'connect' });
2873
- const onDisconnect = (e) => subscriber.next({ device: e.device, type: 'disconnect' });
2874
- usb.addEventListener('connect', onConnect);
2875
- usb.addEventListener('disconnect', onDisconnect);
2876
- return () => {
2877
- usb.removeEventListener('connect', onConnect);
2878
- usb.removeEventListener('disconnect', onDisconnect);
2879
- };
2880
- });
2881
- }
2882
- getDeviceInfo(device) {
2883
- return {
2884
- vendorId: device.vendorId,
2885
- productId: device.productId,
2886
- productName: device.productName,
2887
- manufacturerName: device.manufacturerName,
2888
- serialNumber: device.serialNumber,
2889
- opened: device.opened,
2890
- };
2891
- }
2892
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2893
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService });
2894
- }
2895
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, decorators: [{
2896
- type: Injectable
2897
- }] });
2898
-
2899
- function getNdefReaderClass() {
2900
- return window.NDEFReader;
2901
- }
2902
- class WebNfcService extends BrowserApiBaseService {
2903
- getApiName() {
2904
- return 'web-nfc';
2905
- }
2906
- isSupported() {
2907
- return this.isBrowserEnvironment() && 'NDEFReader' in window;
2908
- }
2909
- scan() {
2910
- if (!this.isSupported()) {
2911
- return new Observable((o) => o.error(new Error('Web NFC API not supported')));
2912
- }
2913
- return new Observable((subscriber) => {
2914
- const abortController = new AbortController();
2915
- const reader = new (getNdefReaderClass())();
2916
- const onReading = (event) => {
2917
- const e = event;
2918
- subscriber.next({
2919
- serialNumber: e.serialNumber,
2920
- message: e.message,
2921
- });
2922
- };
2923
- const onError = (event) => {
2924
- subscriber.error(event.error ?? new Error('NFC read error'));
2925
- };
2926
- reader.addEventListener('reading', onReading);
2927
- reader.addEventListener('readingerror', onError);
2928
- reader
2929
- .scan({ signal: abortController.signal })
2930
- .catch((err) => subscriber.error(err));
2931
- return () => abortController.abort();
2932
- });
2933
- }
2934
- async write(message, options) {
2935
- if (!this.isSupported()) {
2936
- throw new Error('Web NFC API not supported');
2937
- }
2938
- const reader = new (getNdefReaderClass())();
2939
- await reader.write(message, options);
2940
- }
2941
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2942
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService });
2943
- }
2944
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, decorators: [{
2945
- type: Injectable
2946
- }] });
2947
-
2948
- class PaymentRequestService extends BrowserApiBaseService {
2949
- getApiName() {
2950
- return 'payment-request';
2951
- }
2952
- isSupported() {
2953
- return this.isBrowserEnvironment() && 'PaymentRequest' in window;
2954
- }
2955
- async canMakePayment(methods, details) {
2956
- if (!this.isSupported())
2957
- return false;
2958
- const request = new PaymentRequest(methods, details);
2959
- return request.canMakePayment();
2960
- }
2961
- async show(methods, details, options) {
2962
- if (!this.isSupported()) {
2963
- throw new Error('Payment Request API not supported');
2964
- }
2965
- const request = new PaymentRequest(methods, details, options);
2966
- const response = await request.show();
2967
- const result = {
2968
- methodName: response.methodName,
2969
- details: response.details,
2970
- payerName: response.payerName ?? null,
2971
- payerEmail: response.payerEmail ?? null,
2972
- payerPhone: response.payerPhone ?? null,
2973
- };
2974
- await response.complete('success');
2975
- return result;
2976
- }
2977
- async abort(methods, details) {
2978
- if (!this.isSupported())
2979
- return;
2980
- const request = new PaymentRequest(methods, details);
2981
- await request.abort();
2982
- }
2983
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2984
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService });
2985
- }
2986
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, decorators: [{
2987
- type: Injectable
2988
- }] });
2989
-
2990
- class CredentialManagementService extends BrowserApiBaseService {
2991
- getApiName() {
2992
- return 'credential-management';
2993
- }
2994
- isSupported() {
2995
- return this.isBrowserEnvironment() && 'credentials' in navigator;
2996
- }
2997
- isPublicKeySupported() {
2998
- return this.isSupported() && 'PublicKeyCredential' in window;
2999
- }
3000
- async get(options) {
3001
- if (!this.isSupported()) {
3002
- throw new Error('Credential Management API not supported');
3003
- }
3004
- return navigator.credentials.get(options);
3005
- }
3006
- async store(credential) {
3007
- if (!this.isSupported()) {
3008
- throw new Error('Credential Management API not supported');
3009
- }
3010
- await navigator.credentials.store(credential);
3011
- }
3012
- async createPasswordCredential(data) {
3013
- if (!this.isSupported()) {
3014
- throw new Error('Credential Management API not supported');
3015
- }
3016
- return navigator.credentials.create({
3017
- password: data,
3018
- });
3019
- }
3020
- async createPublicKeyCredential(options) {
3021
- if (!this.isPublicKeySupported()) {
3022
- throw new Error('PublicKeyCredential API not supported');
3023
- }
3024
- return navigator.credentials.create({
3025
- publicKey: options,
3026
- });
3027
- }
3028
- async preventSilentAccess() {
3029
- if (!this.isSupported())
3030
- return;
3031
- await navigator.credentials.preventSilentAccess();
3032
- }
3033
- async isConditionalMediationAvailable() {
3034
- if (!this.isPublicKeySupported())
3035
- return false;
3036
- if ('isConditionalMediationAvailable' in PublicKeyCredential) {
3037
- return PublicKeyCredential.isConditionalMediationAvailable();
3038
- }
3039
- return false;
3040
- }
3041
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
3042
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService });
3043
- }
3044
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, decorators: [{
3045
- type: Injectable
3046
- }] });
3047
-
3048
2902
  // Common types for browser APIs
3049
2903
 
3050
2904
  function injectPageVisibility() {
@@ -3208,42 +3062,6 @@ function injectPerformanceObserver(config) {
3208
3062
  };
3209
3063
  }
3210
3064
 
3211
- function getIdleDetectorClass() {
3212
- return window.IdleDetector;
3213
- }
3214
- function injectIdleDetector(options = {}) {
3215
- const destroyRef = inject(DestroyRef);
3216
- const platformId = inject(PLATFORM_ID);
3217
- const defaultState = { user: 'active', screen: 'unlocked' };
3218
- const state = signal(defaultState, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
3219
- if (isPlatformBrowser(platformId) && 'IdleDetector' in window) {
3220
- const abortController = new AbortController();
3221
- const detector = new (getIdleDetectorClass())();
3222
- detector.addEventListener('change', () => {
3223
- state.set({
3224
- user: detector.userState,
3225
- screen: detector.screenState,
3226
- });
3227
- });
3228
- detector
3229
- .start({
3230
- threshold: options.threshold ?? 60_000,
3231
- signal: abortController.signal,
3232
- })
3233
- .catch(() => {
3234
- /* permission denied or unsupported — keep defaults */
3235
- });
3236
- destroyRef.onDestroy(() => abortController.abort());
3237
- }
3238
- return {
3239
- state: state.asReadonly(),
3240
- userState: computed(() => state().user),
3241
- screenState: computed(() => state().screen),
3242
- isUserIdle: computed(() => state().user === 'idle'),
3243
- isScreenLocked: computed(() => state().screen === 'locked'),
3244
- };
3245
- }
3246
-
3247
3065
  function injectGamepad(index, intervalMs = 16) {
3248
3066
  const destroyRef = inject(DestroyRef);
3249
3067
  const platformId = inject(PLATFORM_ID);
@@ -3410,10 +3228,6 @@ function provideMediaRecorder() {
3410
3228
  return makeEnvironmentProviders([PermissionsService, MediaRecorderService]);
3411
3229
  }
3412
3230
 
3413
- function provideIdleDetector() {
3414
- return makeEnvironmentProviders([PermissionsService, IdleDetectorService]);
3415
- }
3416
-
3417
3231
  function provideBattery() {
3418
3232
  return makeEnvironmentProviders([BatteryService]);
3419
3233
  }
@@ -3482,14 +3296,6 @@ function providePerformanceObserver() {
3482
3296
  return makeEnvironmentProviders([PerformanceObserverService]);
3483
3297
  }
3484
3298
 
3485
- function provideEyeDropper() {
3486
- return makeEnvironmentProviders([EyeDropperService]);
3487
- }
3488
-
3489
- function provideBarcodeDetector() {
3490
- return makeEnvironmentProviders([BarcodeDetectorService]);
3491
- }
3492
-
3493
3299
  function provideWebAudio() {
3494
3300
  return makeEnvironmentProviders([WebAudioService]);
3495
3301
  }
@@ -3498,26 +3304,6 @@ function provideGamepad() {
3498
3304
  return makeEnvironmentProviders([GamepadService]);
3499
3305
  }
3500
3306
 
3501
- function provideWebBluetooth() {
3502
- return makeEnvironmentProviders([WebBluetoothService]);
3503
- }
3504
-
3505
- function provideWebUsb() {
3506
- return makeEnvironmentProviders([WebUsbService]);
3507
- }
3508
-
3509
- function provideWebNfc() {
3510
- return makeEnvironmentProviders([WebNfcService]);
3511
- }
3512
-
3513
- function providePaymentRequest() {
3514
- return makeEnvironmentProviders([PaymentRequestService]);
3515
- }
3516
-
3517
- function provideCredentialManagement() {
3518
- return makeEnvironmentProviders([CredentialManagementService]);
3519
- }
3520
-
3521
3307
  function provideMediaApis() {
3522
3308
  return makeEnvironmentProviders([PermissionsService, CameraService, MediaDevicesService]);
3523
3309
  }
@@ -3562,16 +3348,8 @@ const defaultBrowserWebApisConfig = {
3562
3348
  enableSpeechSynthesis: false,
3563
3349
  enableMutationObserver: false,
3564
3350
  enablePerformanceObserver: false,
3565
- enableIdleDetector: false,
3566
- enableEyeDropper: false,
3567
- enableBarcodeDetector: false,
3568
3351
  enableWebAudio: false,
3569
3352
  enableGamepad: false,
3570
- enableWebBluetooth: false,
3571
- enableWebUsb: false,
3572
- enableWebNfc: false,
3573
- enablePaymentRequest: false,
3574
- enableCredentialManagement: false,
3575
3353
  };
3576
3354
  function provideBrowserWebApis(config = {}) {
3577
3355
  const mergedConfig = { ...defaultBrowserWebApisConfig, ...config };
@@ -3602,16 +3380,8 @@ function provideBrowserWebApis(config = {}) {
3602
3380
  [mergedConfig.enableSpeechSynthesis, SpeechSynthesisService],
3603
3381
  [mergedConfig.enableMutationObserver, MutationObserverService],
3604
3382
  [mergedConfig.enablePerformanceObserver, PerformanceObserverService],
3605
- [mergedConfig.enableIdleDetector, IdleDetectorService],
3606
- [mergedConfig.enableEyeDropper, EyeDropperService],
3607
- [mergedConfig.enableBarcodeDetector, BarcodeDetectorService],
3608
3383
  [mergedConfig.enableWebAudio, WebAudioService],
3609
3384
  [mergedConfig.enableGamepad, GamepadService],
3610
- [mergedConfig.enableWebBluetooth, WebBluetoothService],
3611
- [mergedConfig.enableWebUsb, WebUsbService],
3612
- [mergedConfig.enableWebNfc, WebNfcService],
3613
- [mergedConfig.enablePaymentRequest, PaymentRequestService],
3614
- [mergedConfig.enableCredentialManagement, CredentialManagementService],
3615
3385
  ];
3616
3386
  for (const [enabled, provider] of conditionalProviders) {
3617
3387
  if (enabled) {
@@ -3629,4 +3399,4 @@ const version = '0.1.0';
3629
3399
  * Generated bundle index. Do not edit.
3630
3400
  */
3631
3401
 
3632
- export { BROWSER_API_LOGGER, BarcodeDetectorService, BatteryService, BroadcastChannelService, BrowserApiBaseService, BrowserCapabilityService, BrowserSupportUtil, CameraService, ClipboardService, ConnectionRegistryBaseService, CredentialManagementService, EyeDropperService, FileSystemAccessService, FullscreenService, GamepadService, GeolocationService, IdleDetectorService, IntersectionObserverService, MediaDevicesService, MediaRecorderService, MutationObserverService, NetworkInformationService, NotificationService, PageVisibilityService, PaymentRequestService, PerformanceObserverService, PermissionsService, ResizeObserverService, ScreenOrientationService, ScreenWakeLockService, ServerSentEventsService, SpeechSynthesisService, VibrationService, WebAudioService, WebBluetoothService, WebNfcService, WebShareService, WebSocketService, WebStorageService, WebUsbService, WebWorkerService, permissionGuard as createPermissionGuard, defaultBrowserWebApisConfig, injectGamepad, injectIdleDetector, injectIntersectionObserver, injectMutationObserver, injectNetworkInformation, injectPageVisibility, injectPerformanceObserver, injectResizeObserver, injectScreenOrientation, permissionGuard, provideBarcodeDetector, provideBattery, provideBroadcastChannel, provideBrowserWebApis, provideCamera, provideClipboard, provideCommunicationApis, provideCredentialManagement, provideEyeDropper, provideFileSystemAccess, provideFullscreen, provideGamepad, provideGeolocation, provideIdleDetector, provideIntersectionObserver, provideLocationApis, provideMediaApis, provideMediaDevices, provideMediaRecorder, provideMutationObserver, provideNetworkInformation, provideNotifications, providePageVisibility, providePaymentRequest, providePerformanceObserver, providePermissions, provideResizeObserver, provideScreenOrientation, provideScreenWakeLock, provideServerSentEvents, provideSpeechSynthesis, provideStorageApis, provideVibration, provideWebAudio, provideWebBluetooth, provideWebNfc, provideWebShare, provideWebSocket, provideWebStorage, provideWebUsb, provideWebWorker, version };
3402
+ export { BROWSER_API_LOGGER, BatteryService, BroadcastChannelService, BrowserApiBaseService, BrowserCapabilityService, BrowserSupportUtil, CameraService, ClipboardService, ConnectionRegistryBaseService, FileSystemAccessService, FullscreenService, GamepadService, GeolocationService, IntersectionObserverService, MediaDevicesService, MediaRecorderService, MutationObserverService, NetworkInformationService, NotificationService, PageVisibilityService, PerformanceObserverService, PermissionsService, ResizeObserverService, ScreenOrientationService, ScreenWakeLockService, ServerSentEventsService, SpeechSynthesisService, VibrationService, WebAudioService, WebShareService, WebSocketClient, WebSocketService, WebStorageService, WebWorkerService, permissionGuard as createPermissionGuard, defaultBrowserWebApisConfig, injectGamepad, injectIntersectionObserver, injectMutationObserver, injectNetworkInformation, injectPageVisibility, injectPerformanceObserver, injectResizeObserver, injectScreenOrientation, permissionGuard, provideBattery, provideBroadcastChannel, provideBrowserWebApis, provideCamera, provideClipboard, provideCommunicationApis, provideFileSystemAccess, provideFullscreen, provideGamepad, provideGeolocation, provideIntersectionObserver, provideLocationApis, provideMediaApis, provideMediaDevices, provideMediaRecorder, provideMutationObserver, provideNetworkInformation, provideNotifications, providePageVisibility, providePerformanceObserver, providePermissions, provideResizeObserver, provideScreenOrientation, provideScreenWakeLock, provideServerSentEvents, provideSpeechSynthesis, provideStorageApis, provideVibration, provideWebAudio, provideWebShare, provideWebSocket, provideWebStorage, provideWebWorker, version };