{"version":3,"file":"ngxtension-inject-network.mjs","sources":["../../../../libs/ngxtension/inject-network/src/inject-network.ts","../../../../libs/ngxtension/inject-network/src/ngxtension-inject-network.ts"],"sourcesContent":["import { DOCUMENT } from '@angular/common';\nimport { inject, signal, type Injector, type Signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { assertInjector } from 'ngxtension/assert-injector';\nimport { fromEvent, map, merge, startWith } from 'rxjs';\n\n// Ported from https://vueuse.org/core/useNetwork/\n\nexport type NetworkType =\n\t| 'bluetooth'\n\t| 'cellular'\n\t| 'ethernet'\n\t| 'none'\n\t| 'wifi'\n\t| 'wimax'\n\t| 'other'\n\t| 'unknown';\n\nexport type NetworkEffectiveType = 'slow-2g' | '2g' | '3g' | '4g' | '5g';\n\nexport interface NetworkState {\n\tsupported: Signal<boolean>;\n\tonline: Signal<boolean>;\n\t/**\n\t * The time since the user was last connected.\n\t */\n\tofflineAt: Signal<number | undefined>;\n\t/**\n\t * At this time, if the user is offline and reconnects\n\t */\n\tonlineAt: Signal<number | undefined>;\n\t/**\n\t * The download speed in Mbps.\n\t */\n\tdownlink: Signal<number | undefined>;\n\t/**\n\t * The max reachable download speed in Mbps.\n\t */\n\tdownlinkMax: Signal<number | undefined>;\n\t/**\n\t * The detected effective speed type.\n\t */\n\teffectiveType: Signal<NetworkEffectiveType | undefined>;\n\t/**\n\t * The estimated effective round-trip time of the current connection.\n\t */\n\trtt: Signal<number | undefined>;\n\t/**\n\t * If the user activated data saver mode.\n\t */\n\tsaveData: Signal<boolean | undefined>;\n\t/**\n\t * The detected connection/network type.\n\t */\n\ttype: Signal<NetworkType>;\n}\n\nexport interface InjectNetworkOptions {\n\tinjector?: Injector;\n\twindow?: Window;\n}\n\n/**\n * This injector is useful for tracking the current network state of the user. It provides information about the system's connection type, such as 'wifi' or 'cellular'. This utility, along with a singular property added to the Navigator interface (Navigator.connection), allows for the identification of the general type of network connection a system is using. This functionality is particularly useful for choosing between high definition or low definition content depending on the user's network connection.\n *\n * @example\n * ```ts\n * const network = injectNetwork();\n * effect(() => {\n *  console.log(this.network.type());\n *  console.log(this.network.downlink());\n *  console.log(this.network.downlinkMax());\n *  console.log(this.network.effectiveType());\n *  console.log(this.network.rtt());\n *  console.log(this.network.saveData());\n *  console.log(this.network.online());\n *  console.log(this.network.offlineAt());\n *  console.log(this.network.onlineAt());\n *  console.log(this.network.supported());\n *  });\n *  ```\n *\n * @param options An optional object with the following properties:\n *   - `window`: (Optional) Specifies a custom `Window` instance. This is useful when working with iframes or in testing environments where the global `window` might not be appropriate.\n *   - `injector`: (Optional) Specifies a custom `Injector` instance for dependency injection. This allows for more flexible and testable code by decoupling from a global state or context.\n *\n * @returns A readonly object with the following properties:\n *  - `supported`: A signal that emits `true` if the browser supports the Network Information API, otherwise `false`.\n *  - `online`: A signal that emits `true` if the user is online, otherwise `false`.\n *  - `offlineAt`: A signal that emits the time since the user was last connected.\n *  - `onlineAt`: A signal that emits the time since the user was last disconnected.\n *  - `downlink`: A signal that emits the download speed in Mbps.\n *  - `downlinkMax`: A signal that emits the max reachable download speed in Mbps.\n *  - `effectiveType`: A signal that emits the detected effective speed type.\n *  - `rtt`: A signal that emits the estimated effective round-trip time of the current connection.\n *  - `saveData`: A signal that emits `true` if the user activated data saver mode, otherwise `false`.\n *  - `type`: A signal that emits the detected connection/network type.\n */\nexport function injectNetwork({\n\tinjector,\n\twindow: customWindow,\n}: InjectNetworkOptions = {}): Readonly<NetworkState> {\n\treturn assertInjector(injectNetwork, injector, () => {\n\t\tconst window: Window = customWindow ?? inject(DOCUMENT).defaultView!;\n\t\tconst navigator = window?.navigator;\n\n\t\tconst supported = signal(\n\t\t\twindow?.navigator && 'connection' in window.navigator,\n\t\t);\n\n\t\tconst online = signal(true);\n\t\tconst saveData = signal(false);\n\t\tconst offlineAt = signal<number | undefined>(undefined);\n\t\tconst onlineAt = signal<number | undefined>(undefined);\n\t\tconst downlink = signal<number | undefined>(undefined);\n\t\tconst downlinkMax = signal<number | undefined>(undefined);\n\t\tconst rtt = signal<number | undefined>(undefined);\n\t\tconst effectiveType = signal<NetworkEffectiveType | undefined>(undefined);\n\t\tconst type = signal<NetworkType>('unknown');\n\n\t\tconst connection = supported() && (navigator as any).connection;\n\n\t\tconst updateNetworkInformation = () => {\n\t\t\tif (!navigator) return;\n\n\t\t\tofflineAt.set(online() ? undefined : Date.now());\n\t\t\tonlineAt.set(online() ? Date.now() : undefined);\n\n\t\t\tif (connection) {\n\t\t\t\tdownlink.set(connection.downlink);\n\t\t\t\tdownlinkMax.set(connection.downlinkMax);\n\t\t\t\teffectiveType.set(connection.effectiveType);\n\t\t\t\trtt.set(connection.rtt);\n\t\t\t\tsaveData.set(connection.saveData);\n\t\t\t\ttype.set(connection.type);\n\t\t\t}\n\t\t};\n\n\t\tif (window) {\n\t\t\tmerge(\n\t\t\t\tfromEvent(window, 'online').pipe(map(() => true)),\n\t\t\t\tfromEvent(window, 'offline').pipe(map(() => false)),\n\t\t\t)\n\t\t\t\t.pipe(takeUntilDestroyed())\n\t\t\t\t.subscribe((isOnline) => {\n\t\t\t\t\tonline.set(isOnline);\n\t\t\t\t\tif (isOnline) {\n\t\t\t\t\t\tonlineAt.set(Date.now());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tofflineAt.set(Date.now());\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tif (connection) {\n\t\t\tfromEvent(connection, 'change')\n\t\t\t\t.pipe(\n\t\t\t\t\tstartWith(null), // we need to start with null to trigger the first update\n\t\t\t\t\ttakeUntilDestroyed(),\n\t\t\t\t)\n\t\t\t\t.subscribe(() => updateNetworkInformation());\n\t\t}\n\n\t\treturn {\n\t\t\tsupported: supported.asReadonly(),\n\t\t\tonline: online.asReadonly(),\n\t\t\tsaveData: saveData.asReadonly(),\n\t\t\tofflineAt: offlineAt.asReadonly(),\n\t\t\tonlineAt: onlineAt.asReadonly(),\n\t\t\tdownlink: downlink.asReadonly(),\n\t\t\tdownlinkMax: downlinkMax.asReadonly(),\n\t\t\teffectiveType: effectiveType.asReadonly(),\n\t\t\trtt: rtt.asReadonly(),\n\t\t\ttype: type.asReadonly(),\n\t\t};\n\t});\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AA8DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;AACG,SAAU,aAAa,CAAC,EAC7B,QAAQ,EACR,MAAM,EAAE,YAAY,GAAA,GACK,EAAE,EAAA;AAC3B,IAAA,OAAO,cAAc,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAK;QACnD,MAAM,MAAM,GAAW,YAAY,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAY,CAAC;AACrE,QAAA,MAAM,SAAS,GAAG,MAAM,EAAE,SAAS,CAAC;AAEpC,QAAA,MAAM,SAAS,GAAG,MAAM,CACvB,MAAM,EAAE,SAAS,IAAI,YAAY,IAAI,MAAM,CAAC,SAAS,CACrD,CAAC;AAEF,QAAA,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;AAC5B,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/B,QAAA,MAAM,SAAS,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;AACxD,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;AACvD,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;AACvD,QAAA,MAAM,WAAW,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;AAC1D,QAAA,MAAM,GAAG,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;AAClD,QAAA,MAAM,aAAa,GAAG,MAAM,CAAmC,SAAS,CAAC,CAAC;AAC1E,QAAA,MAAM,IAAI,GAAG,MAAM,CAAc,SAAS,CAAC,CAAC;QAE5C,MAAM,UAAU,GAAG,SAAS,EAAE,IAAK,SAAiB,CAAC,UAAU,CAAC;QAEhE,MAAM,wBAAwB,GAAG,MAAK;AACrC,YAAA,IAAI,CAAC,SAAS;gBAAE,OAAO;AAEvB,YAAA,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AACjD,YAAA,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;YAEhD,IAAI,UAAU,EAAE;AACf,gBAAA,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AAClC,gBAAA,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AACxC,gBAAA,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAC5C,gBAAA,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACxB,gBAAA,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AAClC,gBAAA,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;aAC1B;AACF,SAAC,CAAC;QAEF,IAAI,MAAM,EAAE;AACX,YAAA,KAAK,CACJ,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,EACjD,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CACnD;iBACC,IAAI,CAAC,kBAAkB,EAAE,CAAC;AAC1B,iBAAA,SAAS,CAAC,CAAC,QAAQ,KAAI;AACvB,gBAAA,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACrB,IAAI,QAAQ,EAAE;oBACb,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;iBACzB;qBAAM;oBACN,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;iBAC1B;AACF,aAAC,CAAC,CAAC;SACJ;QAED,IAAI,UAAU,EAAE;AACf,YAAA,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC;AAC7B,iBAAA,IAAI,CACJ,SAAS,CAAC,IAAI,CAAC;AACf,YAAA,kBAAkB,EAAE,CACpB;AACA,iBAAA,SAAS,CAAC,MAAM,wBAAwB,EAAE,CAAC,CAAC;SAC9C;QAED,OAAO;AACN,YAAA,SAAS,EAAE,SAAS,CAAC,UAAU,EAAE;AACjC,YAAA,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE;AAC3B,YAAA,QAAQ,EAAE,QAAQ,CAAC,UAAU,EAAE;AAC/B,YAAA,SAAS,EAAE,SAAS,CAAC,UAAU,EAAE;AACjC,YAAA,QAAQ,EAAE,QAAQ,CAAC,UAAU,EAAE;AAC/B,YAAA,QAAQ,EAAE,QAAQ,CAAC,UAAU,EAAE;AAC/B,YAAA,WAAW,EAAE,WAAW,CAAC,UAAU,EAAE;AACrC,YAAA,aAAa,EAAE,aAAa,CAAC,UAAU,EAAE;AACzC,YAAA,GAAG,EAAE,GAAG,CAAC,UAAU,EAAE;AACrB,YAAA,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE;SACvB,CAAC;AACH,KAAC,CAAC,CAAC;AACJ;;AChLA;;AAEG;;;;"}