@symbiote-native/network 0.0.1

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -0
  3. package/build/angular/index.d.ts +2 -0
  4. package/build/angular/index.js +4 -0
  5. package/build/angular/services/network-state.service/index.d.ts +6 -0
  6. package/build/angular/services/network-state.service/index.js +68 -0
  7. package/build/core/index.d.ts +3 -0
  8. package/build/core/index.js +2 -0
  9. package/build/core/native-module.d.ts +9 -0
  10. package/build/core/native-module.js +3 -0
  11. package/build/core/network.d.ts +13 -0
  12. package/build/core/network.js +34 -0
  13. package/build/core/types.d.ts +55 -0
  14. package/build/core/types.js +40 -0
  15. package/build/react/hooks/use-network-state/index.d.ts +2 -0
  16. package/build/react/hooks/use-network-state/index.js +14 -0
  17. package/build/react/index.d.ts +2 -0
  18. package/build/react/index.js +3 -0
  19. package/build/vue/composables/use-network-state/index.d.ts +3 -0
  20. package/build/vue/composables/use-network-state/index.js +21 -0
  21. package/build/vue/index.d.ts +2 -0
  22. package/build/vue/index.js +3 -0
  23. package/build-ngc/angular/index.d.ts +2 -0
  24. package/build-ngc/angular/index.js +5 -0
  25. package/build-ngc/angular/index.js.map +1 -0
  26. package/build-ngc/angular/services/network-state.service/index.d.ts +9 -0
  27. package/build-ngc/angular/services/network-state.service/index.js +27 -0
  28. package/build-ngc/angular/services/network-state.service/index.js.map +1 -0
  29. package/build-ngc/core/index.d.ts +3 -0
  30. package/build-ngc/core/index.js +3 -0
  31. package/build-ngc/core/index.js.map +1 -0
  32. package/build-ngc/core/native-module.d.ts +9 -0
  33. package/build-ngc/core/native-module.js +4 -0
  34. package/build-ngc/core/native-module.js.map +1 -0
  35. package/build-ngc/core/network.d.ts +13 -0
  36. package/build-ngc/core/network.js +35 -0
  37. package/build-ngc/core/network.js.map +1 -0
  38. package/build-ngc/core/types.d.ts +55 -0
  39. package/build-ngc/core/types.js +41 -0
  40. package/build-ngc/core/types.js.map +1 -0
  41. package/native-link.json +12 -0
  42. package/package.json +107 -0
  43. package/src/angular/index.ts +13 -0
  44. package/src/angular/services/network-state.service/index.ts +26 -0
  45. package/src/angular/services/network-state.service/network-state.service.test.ts +103 -0
  46. package/src/core/index.ts +8 -0
  47. package/src/core/native-module.ts +19 -0
  48. package/src/core/network.test.ts +103 -0
  49. package/src/core/network.ts +42 -0
  50. package/src/core/types.ts +60 -0
  51. package/src/react/hooks/use-network-state/index.ts +17 -0
  52. package/src/react/hooks/use-network-state/use-network-state.test.tsx +91 -0
  53. package/src/react/index.ts +13 -0
  54. package/src/vue/composables/use-network-state/index.ts +31 -0
  55. package/src/vue/composables/use-network-state/use-network-state.test.ts +100 -0
  56. package/src/vue/index.ts +13 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 A. Prokopenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # @symbiote-native/network
2
+
3
+ Port of [`expo-network`](https://docs.expo.dev/versions/latest/sdk/network/) for
4
+ [SymbioteNative](../../README.md) — network connection state (type/connected/internet-reachable)
5
+ with a change listener, device IP address, and airplane-mode detection, reachable from every
6
+ adapter (React, Vue, Angular), not just React.
7
+
8
+ Built the same way as [`@symbiote-native/battery`](../battery) and
9
+ [`@symbiote-native/local-auth`](../local-auth), an `expo-modules-core`-based wrapper (see the
10
+ `symbiote-expo-native-module` project skill for the full mechanism: why `expo-modules-core` is
11
+ depended on directly and never the `expo` meta-package, why the upstream JS is hand-ported into
12
+ `core/` rather than imported, and how autolinking picks up the native module).
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @symbiote-native/network
18
+ ```
19
+
20
+ Depends on `expo-network` and `expo-modules-core` directly (regular dependencies, pinned to exact
21
+ versions — never a caret range, since this package's `core/` is hand-ported against one specific
22
+ native API shape and a newer resolve could silently drift the two apart). Never install
23
+ `expo-network` yourself, and never add the `expo` package to this project — it bundles its own
24
+ Metro/Babel pipeline that conflicts with this project's own.
25
+
26
+ ### Required one-time step: native autolinking wiring
27
+
28
+ Unlike a plain RN native module, `expo-network`'s native code is discovered by
29
+ `expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism — this needs wiring
30
+ into the native host app **once**, covering this package and every other `expo-modules-core`
31
+ package (`@symbiote-native/battery`, `@symbiote-native/sensors`, `@symbiote-native/local-auth`)
32
+ with zero further changes:
33
+
34
+ | Platform | Touches |
35
+ |---|---|
36
+ | iOS | `ios/Podfile` — add `use_expo_modules!` |
37
+ | iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
38
+ | Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
39
+ | Android | `MainApplication.kt` — Expo's bootstrap hook, plus a hand-written native-module name map (there's no `expo` meta-package here to auto-generate one) |
40
+
41
+ Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
42
+ peer-dependency exclusion list — live in the `symbiote-expo-native-module` skill. Reference
43
+ implementation: `.examples/expo-react/ios/Podfile` and
44
+ `.examples/expo-react/android/app/src/main/java/com/canary/MainApplication.kt`.
45
+
46
+ No platform permission string is needed for network's surface — connection state, IP address, and
47
+ airplane-mode detection all read system state with no runtime permission prompt on either
48
+ platform.
49
+
50
+ ## Shape
51
+
52
+ ```
53
+ src/core/ network.ts — get*Async functions + addNetworkStateListener subscription.
54
+ native-module.ts resolves the native module through expo-modules-core's
55
+ requireNativeModule. types.ts — NetworkStateType enum, NetworkState,
56
+ NetworkStateEvent, hand-ported from Network.types.ts.
57
+ src/react/hooks/ @symbiote-native/network/react — useNetworkState
58
+ src/vue/composables/ @symbiote-native/network/vue — useNetworkState (same name)
59
+ src/angular/services/ @symbiote-native/network/angular — NetworkStateService (`.connect()`
60
+ returns a Signal)
61
+ ```
62
+
63
+ Each adapter's hook/composable/service is a thin lifecycle wrapper (seed from the one-shot
64
+ `getNetworkStateAsync()` call, subscribe to `addNetworkStateListener`, unsubscribe on unmount) over
65
+ the same `core` functions — the subscription logic is written once and shared by all three.
66
+
67
+ ## Use it
68
+
69
+ ```tsx
70
+ // React — examples/expo-react/screens/NetworkScreen.tsx
71
+ import { useEffect, useState } from 'react';
72
+ import { getIpAddressAsync, isAirplaneModeEnabledAsync } from '@symbiote-native/network';
73
+ import { useNetworkState } from '@symbiote-native/network/react';
74
+
75
+ function NetworkScreen() {
76
+ const networkState = useNetworkState(); // { type, isConnected, isInternetReachable }
77
+ const [ipAddress, setIpAddress] = useState<string | null>(null);
78
+ const [isAirplaneMode, setIsAirplaneMode] = useState<boolean | null>(null);
79
+
80
+ useEffect(() => {
81
+ Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(([ip, airplaneMode]) => {
82
+ setIpAddress(ip);
83
+ setIsAirplaneMode(airplaneMode);
84
+ });
85
+ }, [networkState]);
86
+
87
+ return (
88
+ <>
89
+ <Text>{networkState.isConnected ? `Connected via ${networkState.type}` : 'Offline'}</Text>
90
+ <Text>{ipAddress ?? 'checking…'}</Text>
91
+ <Text>{isAirplaneMode ? 'Airplane mode: On' : 'Airplane mode: Off'}</Text>
92
+ </>
93
+ );
94
+ }
95
+ ```
96
+
97
+ ```vue
98
+ <!-- Vue — examples/expo-vue-sfc/screens/NetworkScreen.vue -->
99
+ <script setup lang="ts">
100
+ import { ref, watch } from 'vue';
101
+ import { Text } from '@symbiote-native/vue';
102
+ import { getIpAddressAsync, isAirplaneModeEnabledAsync } from '@symbiote-native/network';
103
+ import { useNetworkState } from '@symbiote-native/network/vue';
104
+
105
+ const networkState = useNetworkState(); // Ref<NetworkState>
106
+ const ipAddress = ref<string | null>(null);
107
+ const isAirplaneMode = ref<boolean | null>(null);
108
+
109
+ watch(
110
+ networkState,
111
+ () => {
112
+ void Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(([ip, airplaneMode]) => {
113
+ ipAddress.value = ip;
114
+ isAirplaneMode.value = airplaneMode;
115
+ });
116
+ },
117
+ { immediate: true },
118
+ );
119
+ </script>
120
+ <template>
121
+ <Text>{{ networkState.isConnected ? `Connected via ${networkState.type}` : 'Offline' }}</Text>
122
+ <Text>{{ ipAddress ?? 'checking…' }}</Text>
123
+ </template>
124
+ ```
125
+
126
+ ```ts
127
+ // Angular — examples/expo-angular/src/screens/NetworkScreen.ts
128
+ import { Component, effect, inject, signal } from '@angular/core';
129
+ import { Text } from '@symbiote-native/angular';
130
+ import {
131
+ NetworkStateService,
132
+ getIpAddressAsync,
133
+ isAirplaneModeEnabledAsync,
134
+ } from '@symbiote-native/network/angular';
135
+
136
+ @Component({
137
+ standalone: true,
138
+ imports: [Text],
139
+ template: `<Text>{{ ipAddress() }}</Text>`,
140
+ })
141
+ export class NetworkScreen {
142
+ readonly networkState = inject(NetworkStateService).connect(); // Signal<NetworkState>
143
+ readonly ipAddress = signal<string | null>(null);
144
+
145
+ constructor() {
146
+ effect(() => {
147
+ this.networkState();
148
+ Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(([ip]) => {
149
+ this.ipAddress.set(ip);
150
+ });
151
+ });
152
+ }
153
+ }
154
+ ```
155
+
156
+ Each of the three demo screens above also re-fetches the IP address and airplane-mode card
157
+ whenever the live network state changes (toggling Wi-Fi/airplane mode on the device updates both
158
+ cards together) — see the linked files for the full version, including the connection-type label
159
+ switch and the layout around it.
160
+
161
+ ## API
162
+
163
+ A mix of stateless async functions and one listener-based subscription
164
+ (`addNetworkStateListener`), with its own adapter-level lifecycle hook.
165
+
166
+ ```ts
167
+ getNetworkStateAsync(): Promise<NetworkState> // { type, isConnected, isInternetReachable }
168
+ getIpAddressAsync(): Promise<string> // device's IPv4 address, "0.0.0.0" if unavailable
169
+ isAirplaneModeEnabledAsync(): Promise<boolean> // Android only
170
+ addNetworkStateListener(listener): EventSubscription // fires whenever the network state changes
171
+ ```
172
+
173
+ Plus `NetworkStateType` (enum: `NONE`/`UNKNOWN`/`CELLULAR`/`WIFI`/`BLUETOOTH`/`ETHERNET`/`WIMAX`/
174
+ `VPN`/`OTHER`), `NetworkState`, `NetworkStateEvent` — ported from upstream's `Network.types.ts`.
175
+
176
+ ```ts
177
+ import { getNetworkStateAsync, addNetworkStateListener } from '@symbiote-native/network';
178
+
179
+ // framework-scoped entry points re-export the same free functions, plus a lifecycle
180
+ // hook/composable/service:
181
+ import { useNetworkState } from '@symbiote-native/network/react';
182
+ import { useNetworkState } from '@symbiote-native/network/vue';
183
+ import { NetworkStateService } from '@symbiote-native/network/angular';
184
+ ```
185
+
186
+ `useNetworkState` seeds its initial value from a one-shot `getNetworkStateAsync()` call, then
187
+ subscribes to `addNetworkStateListener` for updates, and unsubscribes on unmount — mirroring
188
+ upstream's own `useNetworkState`.
189
+
190
+ ## Test it
191
+
192
+ No Fabric/Descriptor angle at all — network is a pure async-function + `EventEmitter` listener
193
+ surface, never a view. Tests inject a fake native-module object in place of the real
194
+ `requireNativeModule` resolution (`src/core/network.test.ts`,
195
+ `src/{react,vue,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
196
+ `@symbiote-native/battery`/`@symbiote-native/sensors`/`@symbiote-native/local-auth` use — no
197
+ `installFabric()`, no ViewConfig. Native rendering itself is verified on-device — see the parent
198
+ [README](../../README.md).
199
+
200
+ The Android/iOS native wiring is done across all four `examples/expo-*` canary apps
201
+ (`examples/expo-react`, `examples/expo-vue-sfc`, `examples/expo-vue-tsx`, `examples/expo-angular`);
202
+ this package isn't yet in the public, non-Expo `examples/react` canary.
@@ -0,0 +1,2 @@
1
+ export { NetworkStateService } from './services/network-state.service';
2
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, type NetworkState, type NetworkStateEvent, type EventSubscription, } from '../core';
@@ -0,0 +1,4 @@
1
+ // NetworkStateService is the Angular-only lifecycle half; the free functions and event
2
+ // subscription plumbing all live in core, shared with React/Vue.
3
+ export { NetworkStateService } from './services/network-state.service/index.js';
4
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, } from '../core/index.js';
@@ -0,0 +1,6 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type NetworkState } from '../../../core';
3
+ export declare class NetworkStateService {
4
+ private readonly injector;
5
+ connect(): Signal<NetworkState>;
6
+ }
@@ -0,0 +1,68 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { effect, inject, Injectable, Injector, signal } from '@angular/core';
36
+ import { addNetworkStateListener, getNetworkStateAsync } from '../../../core/index.js';
37
+ // Angular twin of React's `useNetworkState` hook and Vue's `useNetworkState` composable.
38
+ //
39
+ // readonly networkState = inject(NetworkStateService).connect();
40
+ // // template: {{ networkState().type }}
41
+ let NetworkStateService = (() => {
42
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
43
+ let _classDescriptor;
44
+ let _classExtraInitializers = [];
45
+ let _classThis;
46
+ var NetworkStateService = class {
47
+ static { _classThis = this; }
48
+ static {
49
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
50
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
51
+ NetworkStateService = _classThis = _classDescriptor.value;
52
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
53
+ __runInitializers(_classThis, _classExtraInitializers);
54
+ }
55
+ injector = inject(Injector);
56
+ connect() {
57
+ const networkState = signal({});
58
+ effect(onCleanup => {
59
+ getNetworkStateAsync().then(state => networkState.set(state));
60
+ const subscription = addNetworkStateListener(event => networkState.set(event));
61
+ onCleanup(() => subscription.remove());
62
+ }, { injector: this.injector });
63
+ return networkState.asReadonly();
64
+ }
65
+ };
66
+ return NetworkStateService = _classThis;
67
+ })();
68
+ export { NetworkStateService };
@@ -0,0 +1,3 @@
1
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, } from './network';
2
+ export { NetworkStateType, type NetworkState, type NetworkStateEvent } from './types';
3
+ export type { EventSubscription } from 'expo-modules-core';
@@ -0,0 +1,2 @@
1
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, } from './network.js';
2
+ export { NetworkStateType } from './types.js';
@@ -0,0 +1,9 @@
1
+ import type { EventSubscription } from 'expo-modules-core';
2
+ import type { NetworkStateEvent } from './types';
3
+ export type INativeNetworkModule = {
4
+ getNetworkStateAsync?(): Promise<NetworkStateEvent>;
5
+ getIpAddressAsync?(): Promise<string>;
6
+ isAirplaneModeEnabledAsync?(): Promise<boolean>;
7
+ addListener(eventName: 'onNetworkStateChanged', listener: (event: NetworkStateEvent) => void): EventSubscription;
8
+ };
9
+ export declare const expoNetwork: INativeNetworkModule;
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ const EXPO_NETWORK_MODULE_NAME = 'ExpoNetwork';
3
+ export const expoNetwork = requireNativeModule(EXPO_NETWORK_MODULE_NAME);
@@ -0,0 +1,13 @@
1
+ import { type EventSubscription } from 'expo-modules-core';
2
+ import type { NetworkState, NetworkStateEvent } from './types';
3
+ /** Gets the device's current network connection state. */
4
+ export declare function getNetworkStateAsync(): Promise<NetworkState>;
5
+ /** Gets the device's current IPv4 address. Returns `"0.0.0.0"` if it could not be retrieved. */
6
+ export declare function getIpAddressAsync(): Promise<string>;
7
+ /**
8
+ * Tells if the device is in airplane mode.
9
+ * @platform android
10
+ */
11
+ export declare function isAirplaneModeEnabledAsync(): Promise<boolean>;
12
+ /** Subscribe to network state changes (connection type, connected, internet reachable). */
13
+ export declare function addNetworkStateListener(listener: (event: NetworkStateEvent) => void): EventSubscription;
@@ -0,0 +1,34 @@
1
+ // Hand-ported from .vendors/expo/packages/expo-network/src/Network.ts (sdk-57). Unlike
2
+ // battery, upstream Network throws UnavailabilityError when the native method is absent —
3
+ // same convention as packages/haptics/src/core/haptics.ts.
4
+ import { UnavailabilityError } from 'expo-modules-core';
5
+ import { expoNetwork } from './native-module.js';
6
+ const NATIVE_MODULE_NAME = 'expo-network';
7
+ /** Gets the device's current network connection state. */
8
+ export async function getNetworkStateAsync() {
9
+ if (!expoNetwork.getNetworkStateAsync) {
10
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getNetworkStateAsync');
11
+ }
12
+ return expoNetwork.getNetworkStateAsync();
13
+ }
14
+ /** Gets the device's current IPv4 address. Returns `"0.0.0.0"` if it could not be retrieved. */
15
+ export async function getIpAddressAsync() {
16
+ if (!expoNetwork.getIpAddressAsync) {
17
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getIpAddressAsync');
18
+ }
19
+ return expoNetwork.getIpAddressAsync();
20
+ }
21
+ /**
22
+ * Tells if the device is in airplane mode.
23
+ * @platform android
24
+ */
25
+ export async function isAirplaneModeEnabledAsync() {
26
+ if (!expoNetwork.isAirplaneModeEnabledAsync) {
27
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'isAirplaneModeEnabledAsync');
28
+ }
29
+ return expoNetwork.isAirplaneModeEnabledAsync();
30
+ }
31
+ /** Subscribe to network state changes (connection type, connected, internet reachable). */
32
+ export function addNetworkStateListener(listener) {
33
+ return expoNetwork.addListener('onNetworkStateChanged', listener);
34
+ }
@@ -0,0 +1,55 @@
1
+ export declare enum NetworkStateType {
2
+ /** No active network connection detected. */
3
+ NONE = "NONE",
4
+ /** The connection type could not be determined. */
5
+ UNKNOWN = "UNKNOWN",
6
+ /** Active network connection over mobile data.
7
+ * @platform android
8
+ * @platform ios
9
+ */
10
+ CELLULAR = "CELLULAR",
11
+ /** Active network connection over Wi-Fi.
12
+ * @platform android
13
+ * @platform ios
14
+ */
15
+ WIFI = "WIFI",
16
+ /** Active network connection over Bluetooth.
17
+ * @platform android
18
+ */
19
+ BLUETOOTH = "BLUETOOTH",
20
+ /** Active network connection over Ethernet.
21
+ * @platform android
22
+ * @platform ios
23
+ */
24
+ ETHERNET = "ETHERNET",
25
+ /** Active network connection over WiMAX.
26
+ * @platform android
27
+ */
28
+ WIMAX = "WIMAX",
29
+ /** Active network connection over VPN.
30
+ * @platform android
31
+ */
32
+ VPN = "VPN",
33
+ /** Active network connection over other network connection types.
34
+ * @platform android
35
+ */
36
+ OTHER = "OTHER"
37
+ }
38
+ export type NetworkState = {
39
+ /** The current network connection type. */
40
+ type?: NetworkStateType;
41
+ /**
42
+ * If there is an active network connection. Note that this does not mean internet is
43
+ * reachable. `false` when `type` is `NONE` or `UNKNOWN`, `true` otherwise.
44
+ */
45
+ isConnected?: boolean;
46
+ /**
47
+ * If the internet is reachable with the currently active network connection. On Android this
48
+ * requires internet capability, confirmed internet access, and a usable connection state; VPN
49
+ * connections also require non-zero downstream bandwidth. On iOS this always matches
50
+ * `isConnected`.
51
+ */
52
+ isInternetReachable?: boolean;
53
+ };
54
+ /** Passed as the argument to listeners registered with `addNetworkStateListener()`. */
55
+ export type NetworkStateEvent = NetworkState;
@@ -0,0 +1,40 @@
1
+ // Hand-ported from .vendors/expo/packages/expo-network/src/Network.types.ts (sdk-57) — plain
2
+ // data shapes, no `expo` meta-package import to swap out (unlike local-auth's types.ts).
3
+ export var NetworkStateType;
4
+ (function (NetworkStateType) {
5
+ /** No active network connection detected. */
6
+ NetworkStateType["NONE"] = "NONE";
7
+ /** The connection type could not be determined. */
8
+ NetworkStateType["UNKNOWN"] = "UNKNOWN";
9
+ /** Active network connection over mobile data.
10
+ * @platform android
11
+ * @platform ios
12
+ */
13
+ NetworkStateType["CELLULAR"] = "CELLULAR";
14
+ /** Active network connection over Wi-Fi.
15
+ * @platform android
16
+ * @platform ios
17
+ */
18
+ NetworkStateType["WIFI"] = "WIFI";
19
+ /** Active network connection over Bluetooth.
20
+ * @platform android
21
+ */
22
+ NetworkStateType["BLUETOOTH"] = "BLUETOOTH";
23
+ /** Active network connection over Ethernet.
24
+ * @platform android
25
+ * @platform ios
26
+ */
27
+ NetworkStateType["ETHERNET"] = "ETHERNET";
28
+ /** Active network connection over WiMAX.
29
+ * @platform android
30
+ */
31
+ NetworkStateType["WIMAX"] = "WIMAX";
32
+ /** Active network connection over VPN.
33
+ * @platform android
34
+ */
35
+ NetworkStateType["VPN"] = "VPN";
36
+ /** Active network connection over other network connection types.
37
+ * @platform android
38
+ */
39
+ NetworkStateType["OTHER"] = "OTHER";
40
+ })(NetworkStateType || (NetworkStateType = {}));
@@ -0,0 +1,2 @@
1
+ import { type NetworkState } from '../../../core';
2
+ export declare function useNetworkState(): NetworkState;
@@ -0,0 +1,14 @@
1
+ // React lifecycle wiring over the framework-agnostic core (core/network.ts). Seeds the initial
2
+ // value with a one-shot getNetworkStateAsync() call before the first native event fires, matching
3
+ // upstream's own useNetworkState.
4
+ import { useEffect, useState } from 'react';
5
+ import { addNetworkStateListener, getNetworkStateAsync } from '../../../core/index.js';
6
+ export function useNetworkState() {
7
+ const [networkState, setNetworkState] = useState({});
8
+ useEffect(() => {
9
+ getNetworkStateAsync().then(setNetworkState);
10
+ const subscription = addNetworkStateListener(event => setNetworkState(event));
11
+ return () => subscription.remove();
12
+ }, []);
13
+ return networkState;
14
+ }
@@ -0,0 +1,2 @@
1
+ export { useNetworkState } from './hooks/use-network-state';
2
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, type NetworkState, type NetworkStateEvent, type EventSubscription, } from '../core';
@@ -0,0 +1,3 @@
1
+ // @symbiote-native/network/react: the React entry over the framework-agnostic core.
2
+ export { useNetworkState } from './hooks/use-network-state/index.js';
3
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, } from '../core/index.js';
@@ -0,0 +1,3 @@
1
+ import { type Ref } from '@vue/runtime-core';
2
+ import { type NetworkState } from '../../../core';
3
+ export declare function useNetworkState(): Ref<NetworkState>;
@@ -0,0 +1,21 @@
1
+ // Vue lifecycle wiring over the framework-agnostic core (core/network.ts). Seeds the initial
2
+ // value with a one-shot getNetworkStateAsync() call before the first native event fires, matching
3
+ // upstream's own useNetworkState.
4
+ import { onMounted, onUnmounted, ref } from '@vue/runtime-core';
5
+ import { addNetworkStateListener, getNetworkStateAsync, } from '../../../core/index.js';
6
+ export function useNetworkState() {
7
+ const networkState = ref({});
8
+ let subscription;
9
+ onMounted(() => {
10
+ getNetworkStateAsync().then(state => {
11
+ networkState.value = state;
12
+ });
13
+ subscription = addNetworkStateListener(event => {
14
+ networkState.value = event;
15
+ });
16
+ });
17
+ onUnmounted(() => {
18
+ subscription?.remove();
19
+ });
20
+ return networkState;
21
+ }
@@ -0,0 +1,2 @@
1
+ export { useNetworkState } from './composables/use-network-state';
2
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, type NetworkState, type NetworkStateEvent, type EventSubscription, } from '../core';
@@ -0,0 +1,3 @@
1
+ // @symbiote-native/network/vue: the Vue entry over the framework-agnostic core.
2
+ export { useNetworkState } from './composables/use-network-state/index.js';
3
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, } from '../core/index.js';
@@ -0,0 +1,2 @@
1
+ export { NetworkStateService } from './services/network-state.service';
2
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, type NetworkState, type NetworkStateEvent, type EventSubscription, } from '../core';
@@ -0,0 +1,5 @@
1
+ // NetworkStateService is the Angular-only lifecycle half; the free functions and event
2
+ // subscription plumbing all live in core, shared with React/Vue.
3
+ export { NetworkStateService } from './services/network-state.service';
4
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, NetworkStateType, } from '../core';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,iEAAiE;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,0BAA0B,EAC1B,uBAAuB,EACvB,gBAAgB,GAIjB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type NetworkState } from '../../../core';
3
+ import * as i0 from "@angular/core";
4
+ export declare class NetworkStateService {
5
+ private readonly injector;
6
+ connect(): Signal<NetworkState>;
7
+ static ɵfac: i0.ɵɵFactoryDeclaration<NetworkStateService, never>;
8
+ static ɵprov: i0.ɵɵInjectableDeclaration<NetworkStateService>;
9
+ }
@@ -0,0 +1,27 @@
1
+ import { effect, inject, Injectable, Injector, signal } from '@angular/core';
2
+ import { addNetworkStateListener, getNetworkStateAsync } from '../../../core';
3
+ import * as i0 from "@angular/core";
4
+ // Angular twin of React's `useNetworkState` hook and Vue's `useNetworkState` composable.
5
+ //
6
+ // readonly networkState = inject(NetworkStateService).connect();
7
+ // // template: {{ networkState().type }}
8
+ export class NetworkStateService {
9
+ injector = inject(Injector);
10
+ connect() {
11
+ const networkState = signal({}, /* @ts-ignore */
12
+ ...(ngDevMode ? [{ debugName: "networkState" }] : /* istanbul ignore next */ []));
13
+ effect(onCleanup => {
14
+ getNetworkStateAsync().then(state => networkState.set(state));
15
+ const subscription = addNetworkStateListener(event => networkState.set(event));
16
+ onCleanup(() => subscription.remove());
17
+ }, { injector: this.injector });
18
+ return networkState.asReadonly();
19
+ }
20
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NetworkStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
21
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NetworkStateService, providedIn: 'root' });
22
+ }
23
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NetworkStateService, decorators: [{
24
+ type: Injectable,
25
+ args: [{ providedIn: 'root' }]
26
+ }] });
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/network-state.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAe,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAqB,MAAM,eAAe,CAAC;;AAEjG,yFAAyF;AACzF,EAAE;AACF,mEAAmE;AACnE,2CAA2C;AAE3C,MAAM,OAAO,mBAAmB;IACb,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,MAAM,YAAY,GAAG,MAAM,CAAe,EAAE;yFAAC,CAAC;QAE9C,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,oBAAoB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YAC9D,MAAM,YAAY,GAAG,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/E,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;QAEF,OAAO,YAAY,CAAC,UAAU,EAAE,CAAC;IACnC,CAAC;uGAhBU,mBAAmB;2GAAnB,mBAAmB,cADN,MAAM;;2FACnB,mBAAmB;kBAD/B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
@@ -0,0 +1,3 @@
1
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, } from './network';
2
+ export { NetworkStateType, type NetworkState, type NetworkStateEvent } from './types';
3
+ export type { EventSubscription } from 'expo-modules-core';
@@ -0,0 +1,3 @@
1
+ export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, } from './network';
2
+ export { NetworkStateType } from './types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAA6C,MAAM,SAAS,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { EventSubscription } from 'expo-modules-core';
2
+ import type { NetworkStateEvent } from './types';
3
+ export type INativeNetworkModule = {
4
+ getNetworkStateAsync?(): Promise<NetworkStateEvent>;
5
+ getIpAddressAsync?(): Promise<string>;
6
+ isAirplaneModeEnabledAsync?(): Promise<boolean>;
7
+ addListener(eventName: 'onNetworkStateChanged', listener: (event: NetworkStateEvent) => void): EventSubscription;
8
+ };
9
+ export declare const expoNetwork: INativeNetworkModule;
@@ -0,0 +1,4 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ const EXPO_NETWORK_MODULE_NAME = 'ExpoNetwork';
3
+ export const expoNetwork = requireNativeModule(EXPO_NETWORK_MODULE_NAME);
4
+ //# sourceMappingURL=native-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAIxD,MAAM,wBAAwB,GAAG,aAAa,CAAC;AAc/C,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAuB,wBAAwB,CAAC,CAAC"}