Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | 1x 147x 81x 1x 80x 80x 2x 64x 1x 63x 63x 59x | import type { NetworkInformationLike, NetworkState } from "./types";
/**
* The inert network state returned during server-side rendering and in any
* environment without a `navigator`. `online` is optimistically `true`; every
* Network Information field is `undefined`.
*
* Frozen and shared so the server snapshot keeps a stable identity across
* renders (important for `useSyncExternalStore`).
*/
export const SERVER_NETWORK_STATE: NetworkState = Object.freeze({
online: true,
});
/**
* Whether a `navigator` object is available (i.e. running in a browser-like
* environment rather than SSR).
*
* @returns `true` when `navigator` is defined.
*
* @example
* ```ts
* if (isNavigatorAvailable()) {
* // Safe to read navigator.onLine
* }
* ```
*/
export function isNavigatorAvailable(): boolean {
return typeof navigator !== "undefined";
}
/**
* Resolve the `NetworkInformation` object from `navigator`, checking the
* standard `connection` property first and then the vendor-prefixed
* `mozConnection` / `webkitConnection` fallbacks.
*
* @returns The connection object, or `undefined` when the Network Information
* API is unsupported (Firefox, Safari) or running under SSR.
*
* @example
* ```ts
* const connection = getConnection();
* const effectiveType = connection?.effectiveType; // "4g" | undefined
* ```
*/
export function getConnection(): NetworkInformationLike | undefined {
if (!isNavigatorAvailable()) {
return undefined;
}
const nav = navigator as Navigator & {
connection?: NetworkInformationLike;
mozConnection?: NetworkInformationLike;
webkitConnection?: NetworkInformationLike;
};
return nav.connection ?? nav.mozConnection ?? nav.webkitConnection;
}
/**
* Whether the Network Information API is available in the current environment.
*
* @returns `true` when a `navigator.connection` (or a vendor-prefixed variant)
* exists.
*
* @example
* ```ts
* const showsEffectiveType = isNetworkInformationSupported();
* ```
*/
export function isNetworkInformationSupported(): boolean {
return getConnection() !== undefined;
}
/**
* Read the current {@link NetworkState} from `navigator`, merging
* `navigator.onLine` with the Network Information API fields (when available).
*
* Degrades gracefully: returns {@link SERVER_NETWORK_STATE} under SSR, and
* leaves every Network Information field `undefined` when the API is
* unsupported.
*
* @param since - Timestamp of the last online/offline transition to carry into
* the snapshot. Pass the value tracked by the caller; defaults to `undefined`.
* @returns The current network state.
*
* @example
* ```ts
* const state = getNetworkState();
* console.log(state.online, state.effectiveType);
* ```
*/
export function getNetworkState(since?: Date): NetworkState {
if (!isNavigatorAvailable()) {
return SERVER_NETWORK_STATE;
}
const connection = getConnection();
return {
online: navigator.onLine,
since,
downlink: connection?.downlink,
downlinkMax: connection?.downlinkMax,
effectiveType: connection?.effectiveType,
rtt: connection?.rtt,
saveData: connection?.saveData,
type: connection?.type,
};
}
/**
* Compare two {@link NetworkState} snapshots field-by-field.
*
* Used to keep the `useSyncExternalStore` snapshot identity stable: when a
* `change` event fires but no observed value actually changed, returning the
* previous object avoids a needless re-render.
*
* @param a - First snapshot.
* @param b - Second snapshot.
* @returns `true` when every field is equal (`since` is compared by reference).
*
* @example
* ```ts
* areNetworkStatesEqual(prev, next); // true -> reuse prev, skip re-render
* ```
*/
export function areNetworkStatesEqual(
a: NetworkState,
b: NetworkState
): boolean {
return (
a.online === b.online &&
a.since === b.since &&
a.downlink === b.downlink &&
a.downlinkMax === b.downlinkMax &&
a.effectiveType === b.effectiveType &&
a.rtt === b.rtt &&
a.saveData === b.saveData &&
a.type === b.type
);
}
|