@symbiote-native/network 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -32
- package/build/angular/index.d.ts +1 -1
- package/build/angular/index.js +1 -1
- package/build/angular/services/network-state.service/index.js +2 -2
- package/build/core/index.d.ts +1 -1
- package/build/core/index.js +1 -1
- package/build/react/hooks/use-network-state/index.js +1 -1
- package/build/react/index.d.ts +1 -1
- package/build/react/index.js +1 -1
- package/build/solid/index.d.ts +2 -0
- package/build/solid/index.js +5 -0
- package/build/solid/primitives/create-network-state.d.ts +3 -0
- package/build/solid/primitives/create-network-state.js +32 -0
- package/build/svelte/index.d.ts +2 -0
- package/build/svelte/index.js +5 -0
- package/build/svelte/runes/use-network-state.svelte.d.ts +4 -0
- package/build/svelte/runes/use-network-state.svelte.js +29 -0
- package/build/vue/index.d.ts +1 -1
- package/build/vue/index.js +1 -1
- package/build-ngc/angular/index.d.ts +1 -1
- package/build-ngc/angular/index.js +1 -1
- package/build-ngc/angular/index.js.map +1 -1
- package/build-ngc/angular/services/network-state.service/index.js +5 -5
- package/build-ngc/angular/services/network-state.service/index.js.map +1 -1
- package/build-ngc/core/index.d.ts +1 -1
- package/build-ngc/core/index.js +1 -1
- package/build-ngc/core/index.js.map +1 -1
- package/build-ngc/core/native-module.js.map +1 -1
- package/build-ngc/core/network.js.map +1 -1
- package/package.json +42 -14
- package/src/angular/index.ts +1 -10
- package/src/angular/services/network-state.service/index.ts +16 -3
- package/src/core/index.ts +5 -1
- package/src/core/native-module.ts +3 -1
- package/src/core/network.ts +4 -1
- package/src/react/hooks/use-network-state/index.ts +8 -2
- package/src/react/index.ts +1 -10
- package/src/solid/index.ts +6 -0
- package/src/solid/primitives/create-network-state.ts +43 -0
- package/src/svelte/index.ts +6 -0
- package/src/svelte/runes/use-network-state.svelte.ts +37 -0
- package/src/svelte/svelte-ambient.d.ts +6 -0
- package/src/vue/index.ts +1 -10
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Port of [`expo-network`](https://docs.expo.dev/versions/latest/sdk/network/) for
|
|
4
4
|
[SymbioteNative](../../README.md) — network connection state (type/connected/internet-reachable)
|
|
5
5
|
with a change listener, device IP address, and airplane-mode detection, reachable from every
|
|
6
|
-
adapter (React, Vue, Angular), not just React.
|
|
6
|
+
adapter (React, Vue, Svelte, Solid, Angular), not just React.
|
|
7
7
|
|
|
8
8
|
Built the same way as [`@symbiote-native/battery`](../battery) and
|
|
9
9
|
[`@symbiote-native/local-auth`](../local-auth), an `expo-modules-core`-based wrapper (see the
|
|
@@ -31,12 +31,12 @@ into the native host app **once**, covering this package and every other `expo-m
|
|
|
31
31
|
package (`@symbiote-native/battery`, `@symbiote-native/sensors`, `@symbiote-native/local-auth`)
|
|
32
32
|
with zero further changes:
|
|
33
33
|
|
|
34
|
-
| Platform | Touches
|
|
35
|
-
|
|
36
|
-
| iOS
|
|
37
|
-
| iOS
|
|
38
|
-
| Android
|
|
39
|
-
| Android
|
|
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
40
|
|
|
41
41
|
Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
|
|
42
42
|
peer-dependency exclusion list — live in the `symbiote-expo-native-module` skill. Reference
|
|
@@ -56,37 +56,50 @@ src/core/ network.ts — get*Async functions + addNetworkStateList
|
|
|
56
56
|
NetworkStateEvent, hand-ported from Network.types.ts.
|
|
57
57
|
src/react/hooks/ @symbiote-native/network/react — useNetworkState
|
|
58
58
|
src/vue/composables/ @symbiote-native/network/vue — useNetworkState (same name)
|
|
59
|
+
src/svelte/runes/ @symbiote-native/network/svelte — useNetworkState (same name)
|
|
60
|
+
src/solid/primitives/ @symbiote-native/network/solid — createNetworkState (returns an
|
|
61
|
+
Accessor; Solid reserves `use*` for consuming existing state)
|
|
59
62
|
src/angular/services/ @symbiote-native/network/angular — NetworkStateService (`.connect()`
|
|
60
63
|
returns a Signal)
|
|
61
64
|
```
|
|
62
65
|
|
|
63
|
-
Each adapter's hook/composable/service is a thin lifecycle wrapper (seed from the
|
|
64
|
-
`getNetworkStateAsync()` call, subscribe to `addNetworkStateListener`, unsubscribe on
|
|
65
|
-
the same `core` functions — the subscription logic is written once and shared by all
|
|
66
|
+
Each adapter's hook/composable/rune/primitive/service is a thin lifecycle wrapper (seed from the
|
|
67
|
+
one-shot `getNetworkStateAsync()` call, subscribe to `addNetworkStateListener`, unsubscribe on
|
|
68
|
+
unmount) over the same `core` functions — the subscription logic is written once and shared by all
|
|
69
|
+
of them.
|
|
66
70
|
|
|
67
71
|
## Use it
|
|
68
72
|
|
|
69
73
|
```tsx
|
|
70
74
|
// React — examples/expo-react/screens/NetworkScreen.tsx
|
|
71
75
|
import { useEffect, useState } from 'react';
|
|
72
|
-
import {
|
|
76
|
+
import {
|
|
77
|
+
getIpAddressAsync,
|
|
78
|
+
isAirplaneModeEnabledAsync,
|
|
79
|
+
} from '@symbiote-native/network';
|
|
73
80
|
import { useNetworkState } from '@symbiote-native/network/react';
|
|
74
81
|
|
|
75
82
|
function NetworkScreen() {
|
|
76
|
-
const networkState = useNetworkState();
|
|
83
|
+
const networkState = useNetworkState(); // { type, isConnected, isInternetReachable }
|
|
77
84
|
const [ipAddress, setIpAddress] = useState<string | null>(null);
|
|
78
85
|
const [isAirplaneMode, setIsAirplaneMode] = useState<boolean | null>(null);
|
|
79
86
|
|
|
80
87
|
useEffect(() => {
|
|
81
|
-
Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(
|
|
89
|
+
([ip, airplaneMode]) => {
|
|
90
|
+
setIpAddress(ip);
|
|
91
|
+
setIsAirplaneMode(airplaneMode);
|
|
92
|
+
},
|
|
93
|
+
);
|
|
85
94
|
}, [networkState]);
|
|
86
95
|
|
|
87
96
|
return (
|
|
88
97
|
<>
|
|
89
|
-
<Text>
|
|
98
|
+
<Text>
|
|
99
|
+
{networkState.isConnected
|
|
100
|
+
? `Connected via ${networkState.type}`
|
|
101
|
+
: 'Offline'}
|
|
102
|
+
</Text>
|
|
90
103
|
<Text>{ipAddress ?? 'checking…'}</Text>
|
|
91
104
|
<Text>{isAirplaneMode ? 'Airplane mode: On' : 'Airplane mode: Off'}</Text>
|
|
92
105
|
</>
|
|
@@ -99,26 +112,33 @@ function NetworkScreen() {
|
|
|
99
112
|
<script setup lang="ts">
|
|
100
113
|
import { ref, watch } from 'vue';
|
|
101
114
|
import { Text } from '@symbiote-native/vue';
|
|
102
|
-
import {
|
|
115
|
+
import {
|
|
116
|
+
getIpAddressAsync,
|
|
117
|
+
isAirplaneModeEnabledAsync,
|
|
118
|
+
} from '@symbiote-native/network';
|
|
103
119
|
import { useNetworkState } from '@symbiote-native/network/vue';
|
|
104
120
|
|
|
105
|
-
const networkState = useNetworkState();
|
|
121
|
+
const networkState = useNetworkState(); // Ref<NetworkState>
|
|
106
122
|
const ipAddress = ref<string | null>(null);
|
|
107
123
|
const isAirplaneMode = ref<boolean | null>(null);
|
|
108
124
|
|
|
109
125
|
watch(
|
|
110
126
|
networkState,
|
|
111
127
|
() => {
|
|
112
|
-
void Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
void Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(
|
|
129
|
+
([ip, airplaneMode]) => {
|
|
130
|
+
ipAddress.value = ip;
|
|
131
|
+
isAirplaneMode.value = airplaneMode;
|
|
132
|
+
},
|
|
133
|
+
);
|
|
116
134
|
},
|
|
117
135
|
{ immediate: true },
|
|
118
136
|
);
|
|
119
137
|
</script>
|
|
120
138
|
<template>
|
|
121
|
-
<Text>{{
|
|
139
|
+
<Text>{{
|
|
140
|
+
networkState.isConnected ? `Connected via ${networkState.type}` : 'Offline'
|
|
141
|
+
}}</Text>
|
|
122
142
|
<Text>{{ ipAddress ?? 'checking…' }}</Text>
|
|
123
143
|
</template>
|
|
124
144
|
```
|
|
@@ -145,15 +165,59 @@ export class NetworkScreen {
|
|
|
145
165
|
constructor() {
|
|
146
166
|
effect(() => {
|
|
147
167
|
this.networkState();
|
|
148
|
-
Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(
|
|
149
|
-
|
|
150
|
-
|
|
168
|
+
Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(
|
|
169
|
+
([ip]) => {
|
|
170
|
+
this.ipAddress.set(ip);
|
|
171
|
+
},
|
|
172
|
+
);
|
|
151
173
|
});
|
|
152
174
|
}
|
|
153
175
|
}
|
|
154
176
|
```
|
|
155
177
|
|
|
156
|
-
|
|
178
|
+
```tsx
|
|
179
|
+
// Solid — the accessor is CALLED; a Solid component body runs once, so a snapshot would freeze.
|
|
180
|
+
import { createSignal, onMount } from 'solid-js';
|
|
181
|
+
import { Text } from '@symbiote-native/solid';
|
|
182
|
+
import {
|
|
183
|
+
getIpAddressAsync,
|
|
184
|
+
isAirplaneModeEnabledAsync,
|
|
185
|
+
} from '@symbiote-native/network';
|
|
186
|
+
import { createNetworkState } from '@symbiote-native/network/solid';
|
|
187
|
+
|
|
188
|
+
function NetworkScreen() {
|
|
189
|
+
const networkState = createNetworkState(); // Accessor<NetworkState>
|
|
190
|
+
const [ipAddress, setIpAddress] = createSignal<string | null>(null);
|
|
191
|
+
const [isAirplaneMode, setIsAirplaneMode] = createSignal<boolean | null>(
|
|
192
|
+
null,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
onMount(() => {
|
|
196
|
+
void Promise.all([getIpAddressAsync(), isAirplaneModeEnabledAsync()]).then(
|
|
197
|
+
([ip, airplaneMode]) => {
|
|
198
|
+
setIpAddress(ip);
|
|
199
|
+
setIsAirplaneMode(airplaneMode);
|
|
200
|
+
},
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<>
|
|
206
|
+
<Text>
|
|
207
|
+
{networkState().isConnected
|
|
208
|
+
? `Connected via ${networkState().type}`
|
|
209
|
+
: 'Offline'}
|
|
210
|
+
</Text>
|
|
211
|
+
<Text>{ipAddress() ?? 'checking…'}</Text>
|
|
212
|
+
<Text>
|
|
213
|
+
{isAirplaneMode() ? 'Airplane mode: On' : 'Airplane mode: Off'}
|
|
214
|
+
</Text>
|
|
215
|
+
</>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Each of the demo screens above also re-fetches the IP address and airplane-mode card
|
|
157
221
|
whenever the live network state changes (toggling Wi-Fi/airplane mode on the device updates both
|
|
158
222
|
cards together) — see the linked files for the full version, including the connection-type label
|
|
159
223
|
switch and the layout around it.
|
|
@@ -174,18 +238,25 @@ Plus `NetworkStateType` (enum: `NONE`/`UNKNOWN`/`CELLULAR`/`WIFI`/`BLUETOOTH`/`E
|
|
|
174
238
|
`VPN`/`OTHER`), `NetworkState`, `NetworkStateEvent` — ported from upstream's `Network.types.ts`.
|
|
175
239
|
|
|
176
240
|
```ts
|
|
177
|
-
import {
|
|
241
|
+
import {
|
|
242
|
+
getNetworkStateAsync,
|
|
243
|
+
addNetworkStateListener,
|
|
244
|
+
} from '@symbiote-native/network';
|
|
178
245
|
|
|
179
246
|
// framework-scoped entry points re-export the same free functions, plus a lifecycle
|
|
180
247
|
// hook/composable/service:
|
|
181
248
|
import { useNetworkState } from '@symbiote-native/network/react';
|
|
182
249
|
import { useNetworkState } from '@symbiote-native/network/vue';
|
|
250
|
+
import { useNetworkState } from '@symbiote-native/network/svelte';
|
|
251
|
+
import { createNetworkState } from '@symbiote-native/network/solid';
|
|
183
252
|
import { NetworkStateService } from '@symbiote-native/network/angular';
|
|
184
253
|
```
|
|
185
254
|
|
|
186
|
-
`useNetworkState` seeds its initial value from a one-shot
|
|
187
|
-
subscribes to `addNetworkStateListener` for updates, and
|
|
188
|
-
upstream's own `useNetworkState`.
|
|
255
|
+
`useNetworkState` (Solid: `createNetworkState`) seeds its initial value from a one-shot
|
|
256
|
+
`getNetworkStateAsync()` call, then subscribes to `addNetworkStateListener` for updates, and
|
|
257
|
+
unsubscribes on unmount — mirroring upstream's own `useNetworkState`. The Solid primitive returns
|
|
258
|
+
an `Accessor<NetworkState>` and subscribes from its body rather than an effect, so nothing can slip
|
|
259
|
+
between the seed and the subscription.
|
|
189
260
|
|
|
190
261
|
## Test it
|
|
191
262
|
|
package/build/angular/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { NetworkStateService } from './services/network-state.service';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
package/build/angular/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// NetworkStateService is the Angular-only lifecycle half; the free functions and event
|
|
2
2
|
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
3
|
export { NetworkStateService } from './services/network-state.service/index.js';
|
|
4
|
-
export
|
|
4
|
+
export * from '../core/index.js';
|
|
@@ -32,8 +32,8 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
36
|
-
import { addNetworkStateListener, getNetworkStateAsync } from '../../../core/index.js';
|
|
35
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
36
|
+
import { addNetworkStateListener, getNetworkStateAsync, } from '../../../core/index.js';
|
|
37
37
|
// Angular twin of React's `useNetworkState` hook and Vue's `useNetworkState` composable.
|
|
38
38
|
//
|
|
39
39
|
// readonly networkState = inject(NetworkStateService).connect();
|
package/build/core/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, } from './network';
|
|
2
|
-
export { NetworkStateType, type NetworkState, type NetworkStateEvent } from './types';
|
|
2
|
+
export { NetworkStateType, type NetworkState, type NetworkStateEvent, } from './types';
|
|
3
3
|
export type { EventSubscription } from 'expo-modules-core';
|
package/build/core/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, } from './network.js';
|
|
2
|
-
export { NetworkStateType } from './types.js';
|
|
2
|
+
export { NetworkStateType, } from './types.js';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// value with a one-shot getNetworkStateAsync() call before the first native event fires, matching
|
|
3
3
|
// upstream's own useNetworkState.
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
|
-
import { addNetworkStateListener, getNetworkStateAsync } from '../../../core/index.js';
|
|
5
|
+
import { addNetworkStateListener, getNetworkStateAsync, } from '../../../core/index.js';
|
|
6
6
|
export function useNetworkState() {
|
|
7
7
|
const [networkState, setNetworkState] = useState({});
|
|
8
8
|
useEffect(() => {
|
package/build/react/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { useNetworkState } from './hooks/use-network-state';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
package/build/react/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @symbiote-native/network/react: the React entry over the framework-agnostic core.
|
|
2
2
|
export { useNetworkState } from './hooks/use-network-state/index.js';
|
|
3
|
-
export
|
|
3
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @symbiote-native/network/solid: the Solid entry over the framework-agnostic core — mirrors the
|
|
2
|
+
// lifecycle-bucket naming convention of adapters/solid/src/primitives (never `hooks`/`composables`/
|
|
3
|
+
// `runes`, those are React's, Vue's and Svelte's terms).
|
|
4
|
+
export { createNetworkState } from './primitives/create-network-state.js';
|
|
5
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// createNetworkState — the Solid twin of React's `useNetworkState` hook, Vue's composable and
|
|
2
|
+
// Svelte's rune, over the framework-agnostic core (core/network.ts). Seeds with a one-shot
|
|
3
|
+
// getNetworkStateAsync() call before the first native event fires, matching upstream's own
|
|
4
|
+
// useNetworkState.
|
|
5
|
+
//
|
|
6
|
+
// `primitives/` and `create*`, never `hooks/`+`use*`: Solid's ecosystem calls a composable
|
|
7
|
+
// reactive function a PRIMITIVE and reserves `use*` for consuming something that already exists.
|
|
8
|
+
// Full rationale in adapters/solid/src/primitives/create-color-scheme.ts.
|
|
9
|
+
//
|
|
10
|
+
// Returns an ACCESSOR, never a snapshot: a Solid component body runs ONCE, so a returned object
|
|
11
|
+
// would pin the caller to the empty seed forever.
|
|
12
|
+
//
|
|
13
|
+
// Outside a component or `createRoot` there is no owner for `onCleanup` — Solid warns and the
|
|
14
|
+
// native listener lives for the process. The accessor still tracks; only the teardown is lost.
|
|
15
|
+
import { createSignal, onCleanup } from 'solid-js';
|
|
16
|
+
import { addNetworkStateListener, getNetworkStateAsync, } from '../../core/index.js';
|
|
17
|
+
export function createNetworkState() {
|
|
18
|
+
const [networkState, setNetworkState] = createSignal({});
|
|
19
|
+
getNetworkStateAsync().then(state => {
|
|
20
|
+
setNetworkState(state);
|
|
21
|
+
});
|
|
22
|
+
// Subscribed from the primitive body, not from an effect: React/Vue/Svelte start listening a
|
|
23
|
+
// tick after their seed runs, so a change landing in that window is lost. Both statements here
|
|
24
|
+
// run in one synchronous tick and nothing can interleave.
|
|
25
|
+
const subscription = addNetworkStateListener(event => {
|
|
26
|
+
setNetworkState(event);
|
|
27
|
+
});
|
|
28
|
+
onCleanup(() => {
|
|
29
|
+
subscription.remove();
|
|
30
|
+
});
|
|
31
|
+
return networkState;
|
|
32
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @symbiote-native/network/svelte: the Svelte entry over the framework-agnostic core — mirrors the
|
|
2
|
+
// lifecycle-bucket naming convention of adapters/svelte/src/runes (never `hooks`/`composables`,
|
|
3
|
+
// those are React's and Vue's terms).
|
|
4
|
+
export { useNetworkState } from './runes/use-network-state.svelte';
|
|
5
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Svelte 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 and the Vue composable's onMounted half.
|
|
4
|
+
//
|
|
5
|
+
// `.svelte.ts` extension: runes ($state/$effect) only work there outside a `.svelte` component;
|
|
6
|
+
// `runes/` is Svelte's name for the lifecycle bucket (React's `hooks/`, Vue's `composables/`).
|
|
7
|
+
// Returns a boxed getter, not a bare `$state`: Svelte 5 reactivity is lexically scoped to the
|
|
8
|
+
// declaring module and doesn't survive being returned raw from a plain function, so the caller
|
|
9
|
+
// reads `.current` like unwrapping Vue's `Ref` via `.value`.
|
|
10
|
+
import { addNetworkStateListener, getNetworkStateAsync, } from '../../core/index.js';
|
|
11
|
+
export function useNetworkState() {
|
|
12
|
+
let networkState = $state({});
|
|
13
|
+
$effect(() => {
|
|
14
|
+
// Write-only touches of `networkState`, so the effect has no dependency on it and runs once
|
|
15
|
+
// per mount - the twin of Vue's onMounted/onUnmounted pair.
|
|
16
|
+
getNetworkStateAsync().then(state => {
|
|
17
|
+
networkState = state;
|
|
18
|
+
});
|
|
19
|
+
const subscription = addNetworkStateListener(event => {
|
|
20
|
+
networkState = event;
|
|
21
|
+
});
|
|
22
|
+
return () => subscription.remove();
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
get current() {
|
|
26
|
+
return networkState;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
package/build/vue/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { useNetworkState } from './composables/use-network-state';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
package/build/vue/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @symbiote-native/network/vue: the Vue entry over the framework-agnostic core.
|
|
2
2
|
export { useNetworkState } from './composables/use-network-state/index.js';
|
|
3
|
-
export
|
|
3
|
+
export * from '../core/index.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { NetworkStateService } from './services/network-state.service';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// NetworkStateService is the Angular-only lifecycle half; the free functions and event
|
|
2
2
|
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
3
|
export { NetworkStateService } from './services/network-state.service';
|
|
4
|
-
export
|
|
4
|
+
export * from '../core';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +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,
|
|
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,cAAc,SAAS,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
2
|
-
import { addNetworkStateListener, getNetworkStateAsync } from '../../../core';
|
|
1
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
2
|
+
import { addNetworkStateListener, getNetworkStateAsync, } from '../../../core';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
// Angular twin of React's `useNetworkState` hook and Vue's `useNetworkState` composable.
|
|
5
5
|
//
|
|
@@ -17,10 +17,10 @@ export class NetworkStateService {
|
|
|
17
17
|
}, { injector: this.injector });
|
|
18
18
|
return networkState.asReadonly();
|
|
19
19
|
}
|
|
20
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.
|
|
21
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.
|
|
20
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NetworkStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
21
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NetworkStateService, providedIn: 'root' });
|
|
22
22
|
}
|
|
23
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.
|
|
23
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NetworkStateService, decorators: [{
|
|
24
24
|
type: Injectable,
|
|
25
25
|
args: [{ providedIn: 'root' }]
|
|
26
26
|
}] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/network-state.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/network-state.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,UAAU,EACV,QAAQ,EACR,MAAM,GAEP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GAErB,MAAM,eAAe,CAAC;;AAEvB,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,CACnD,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CACxB,CAAC;YACF,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;uGAlBU,mBAAmB;2GAAnB,mBAAmB,cADN,MAAM;;2FACnB,mBAAmB;kBAD/B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { getNetworkStateAsync, getIpAddressAsync, isAirplaneModeEnabledAsync, addNetworkStateListener, } from './network';
|
|
2
|
-
export { NetworkStateType, type NetworkState, type NetworkStateEvent } from './types';
|
|
2
|
+
export { NetworkStateType, type NetworkState, type NetworkStateEvent, } from './types';
|
|
3
3
|
export type { EventSubscription } from 'expo-modules-core';
|
package/build-ngc/core/index.js
CHANGED
|
@@ -1 +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,
|
|
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,EACL,gBAAgB,GAGjB,MAAM,SAAS,CAAC"}
|
|
@@ -1 +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,
|
|
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,CAC5C,wBAAwB,CACzB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/core/network.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,0FAA0F;AAC1F,2DAA2D;AAC3D,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,MAAM,kBAAkB,GAAG,cAAc,CAAC;AAE1C,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,IAAI,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC;QACtC,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,WAAW,CAAC,oBAAoB,EAAE,CAAC;AAC5C,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC;QACnC,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,WAAW,CAAC,iBAAiB,EAAE,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAC;QAC5C,MAAM,IAAI,mBAAmB,
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/core/network.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,0FAA0F;AAC1F,2DAA2D;AAC3D,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,MAAM,kBAAkB,GAAG,cAAc,CAAC;AAE1C,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,IAAI,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC;QACtC,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,WAAW,CAAC,oBAAoB,EAAE,CAAC;AAC5C,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC;QACnC,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,WAAW,CAAC,iBAAiB,EAAE,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAC;QAC5C,MAAM,IAAI,mBAAmB,CAC3B,kBAAkB,EAClB,4BAA4B,CAC7B,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC,0BAA0B,EAAE,CAAC;AAClD,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,uBAAuB,CACrC,QAA4C;IAE5C,OAAO,WAAW,CAAC,WAAW,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AACpE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/network",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "expo-network wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. Network state (type/connected/internet-reachable) with a change listener, device IP address, and airplane-mode detection.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "expo-network wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Network state (type/connected/internet-reachable) with a change listener, device IP address, and airplane-mode detection.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -30,6 +30,14 @@
|
|
|
30
30
|
"types": "./build/react/index.d.ts",
|
|
31
31
|
"default": "./build/react/index.js"
|
|
32
32
|
},
|
|
33
|
+
"./svelte": {
|
|
34
|
+
"types": "./build/svelte/index.d.ts",
|
|
35
|
+
"default": "./build/svelte/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./solid": {
|
|
38
|
+
"types": "./build/solid/index.d.ts",
|
|
39
|
+
"default": "./build/solid/index.js"
|
|
40
|
+
},
|
|
33
41
|
"./angular": {
|
|
34
42
|
"types": "./build-ngc/angular/index.d.ts",
|
|
35
43
|
"react-native": "./build-ngc/angular/index.js",
|
|
@@ -53,15 +61,19 @@
|
|
|
53
61
|
"expo-modules-core": "57.0.5"
|
|
54
62
|
},
|
|
55
63
|
"peerDependencies": {
|
|
64
|
+
"@symbiote-native/angular": ">=0.6.2",
|
|
56
65
|
"@symbiote-native/engine": ">=0.1.7",
|
|
66
|
+
"@symbiote-native/react": ">=0.2.8",
|
|
67
|
+
"@symbiote-native/solid": ">=0.0.1",
|
|
68
|
+
"@symbiote-native/svelte": ">=0.1.0",
|
|
69
|
+
"@symbiote-native/vue": ">=0.3.8",
|
|
57
70
|
"@angular/core": ">=20",
|
|
58
71
|
"@vue/runtime-core": "^3.5.13",
|
|
59
72
|
"react": ">=19.0.0",
|
|
60
73
|
"react-native": ">=0.86",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"@symbiote-native/vue": "0.3.8"
|
|
74
|
+
"solid-js": ">=1.9.0",
|
|
75
|
+
"svelte": ">=5.56.0",
|
|
76
|
+
"vue": ">=3.5.0"
|
|
65
77
|
},
|
|
66
78
|
"peerDependenciesMeta": {
|
|
67
79
|
"@symbiote-native/angular": {
|
|
@@ -70,6 +82,12 @@
|
|
|
70
82
|
"@symbiote-native/react": {
|
|
71
83
|
"optional": true
|
|
72
84
|
},
|
|
85
|
+
"@symbiote-native/solid": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"@symbiote-native/svelte": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
73
91
|
"@symbiote-native/vue": {
|
|
74
92
|
"optional": true
|
|
75
93
|
},
|
|
@@ -82,24 +100,34 @@
|
|
|
82
100
|
"react": {
|
|
83
101
|
"optional": true
|
|
84
102
|
},
|
|
103
|
+
"solid-js": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"svelte": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
85
109
|
"vue": {
|
|
86
110
|
"optional": true
|
|
87
111
|
}
|
|
88
112
|
},
|
|
89
113
|
"devDependencies": {
|
|
90
|
-
"@angular/compiler": "
|
|
91
|
-
"@angular/compiler-cli": "
|
|
92
|
-
"@angular/core": "
|
|
114
|
+
"@angular/compiler": "~22.0.8",
|
|
115
|
+
"@angular/compiler-cli": "~22.0.8",
|
|
116
|
+
"@angular/core": "~22.0.8",
|
|
93
117
|
"@types/node": "^26.0.0",
|
|
94
118
|
"@types/react": "^19.2.0",
|
|
95
119
|
"@vue/runtime-core": "^3.5.13",
|
|
96
120
|
"react": "19.2.3",
|
|
121
|
+
"solid-js": "^1.9.14",
|
|
122
|
+
"svelte": "^5.56.0",
|
|
97
123
|
"typescript": "~6.0.0",
|
|
98
|
-
"@symbiote-native/angular": "0.
|
|
99
|
-
"@symbiote-native/engine": "0.
|
|
100
|
-
"@symbiote-native/react": "0.
|
|
101
|
-
"@symbiote-native/
|
|
102
|
-
"@symbiote-native/
|
|
124
|
+
"@symbiote-native/angular": "0.8.0",
|
|
125
|
+
"@symbiote-native/engine": "0.3.0",
|
|
126
|
+
"@symbiote-native/react": "0.4.0",
|
|
127
|
+
"@symbiote-native/solid": "0.1.0",
|
|
128
|
+
"@symbiote-native/svelte": "0.3.0",
|
|
129
|
+
"@symbiote-native/test-utils": "0.2.0",
|
|
130
|
+
"@symbiote-native/vue": "0.5.0"
|
|
103
131
|
},
|
|
104
132
|
"scripts": {
|
|
105
133
|
"typecheck": "tsc --build",
|
package/src/angular/index.ts
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
// NetworkStateService is the Angular-only lifecycle half; the free functions and event
|
|
2
2
|
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
3
|
export { NetworkStateService } from './services/network-state.service';
|
|
4
|
-
export
|
|
5
|
-
getNetworkStateAsync,
|
|
6
|
-
getIpAddressAsync,
|
|
7
|
-
isAirplaneModeEnabledAsync,
|
|
8
|
-
addNetworkStateListener,
|
|
9
|
-
NetworkStateType,
|
|
10
|
-
type NetworkState,
|
|
11
|
-
type NetworkStateEvent,
|
|
12
|
-
type EventSubscription,
|
|
13
|
-
} from '../core';
|
|
4
|
+
export * from '../core';
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
effect,
|
|
3
|
+
inject,
|
|
4
|
+
Injectable,
|
|
5
|
+
Injector,
|
|
6
|
+
signal,
|
|
7
|
+
type Signal,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
import {
|
|
10
|
+
addNetworkStateListener,
|
|
11
|
+
getNetworkStateAsync,
|
|
12
|
+
type NetworkState,
|
|
13
|
+
} from '../../../core';
|
|
3
14
|
|
|
4
15
|
// Angular twin of React's `useNetworkState` hook and Vue's `useNetworkState` composable.
|
|
5
16
|
//
|
|
@@ -15,7 +26,9 @@ export class NetworkStateService {
|
|
|
15
26
|
effect(
|
|
16
27
|
onCleanup => {
|
|
17
28
|
getNetworkStateAsync().then(state => networkState.set(state));
|
|
18
|
-
const subscription = addNetworkStateListener(event =>
|
|
29
|
+
const subscription = addNetworkStateListener(event =>
|
|
30
|
+
networkState.set(event),
|
|
31
|
+
);
|
|
19
32
|
onCleanup(() => subscription.remove());
|
|
20
33
|
},
|
|
21
34
|
{ injector: this.injector },
|
package/src/core/index.ts
CHANGED
|
@@ -4,5 +4,9 @@ export {
|
|
|
4
4
|
isAirplaneModeEnabledAsync,
|
|
5
5
|
addNetworkStateListener,
|
|
6
6
|
} from './network';
|
|
7
|
-
export {
|
|
7
|
+
export {
|
|
8
|
+
NetworkStateType,
|
|
9
|
+
type NetworkState,
|
|
10
|
+
type NetworkStateEvent,
|
|
11
|
+
} from './types';
|
|
8
12
|
export type { EventSubscription } from 'expo-modules-core';
|
|
@@ -16,4 +16,6 @@ export type INativeNetworkModule = {
|
|
|
16
16
|
): EventSubscription;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
export const expoNetwork = requireNativeModule<INativeNetworkModule>(
|
|
19
|
+
export const expoNetwork = requireNativeModule<INativeNetworkModule>(
|
|
20
|
+
EXPO_NETWORK_MODULE_NAME,
|
|
21
|
+
);
|
package/src/core/network.ts
CHANGED
|
@@ -29,7 +29,10 @@ export async function getIpAddressAsync(): Promise<string> {
|
|
|
29
29
|
*/
|
|
30
30
|
export async function isAirplaneModeEnabledAsync(): Promise<boolean> {
|
|
31
31
|
if (!expoNetwork.isAirplaneModeEnabledAsync) {
|
|
32
|
-
throw new UnavailabilityError(
|
|
32
|
+
throw new UnavailabilityError(
|
|
33
|
+
NATIVE_MODULE_NAME,
|
|
34
|
+
'isAirplaneModeEnabledAsync',
|
|
35
|
+
);
|
|
33
36
|
}
|
|
34
37
|
return expoNetwork.isAirplaneModeEnabledAsync();
|
|
35
38
|
}
|
|
@@ -2,14 +2,20 @@
|
|
|
2
2
|
// value with a one-shot getNetworkStateAsync() call before the first native event fires, matching
|
|
3
3
|
// upstream's own useNetworkState.
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
addNetworkStateListener,
|
|
7
|
+
getNetworkStateAsync,
|
|
8
|
+
type NetworkState,
|
|
9
|
+
} from '../../../core';
|
|
6
10
|
|
|
7
11
|
export function useNetworkState(): NetworkState {
|
|
8
12
|
const [networkState, setNetworkState] = useState<NetworkState>({});
|
|
9
13
|
|
|
10
14
|
useEffect(() => {
|
|
11
15
|
getNetworkStateAsync().then(setNetworkState);
|
|
12
|
-
const subscription = addNetworkStateListener(event =>
|
|
16
|
+
const subscription = addNetworkStateListener(event =>
|
|
17
|
+
setNetworkState(event),
|
|
18
|
+
);
|
|
13
19
|
return () => subscription.remove();
|
|
14
20
|
}, []);
|
|
15
21
|
|
package/src/react/index.ts
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
// @symbiote-native/network/react: the React entry over the framework-agnostic core.
|
|
2
2
|
|
|
3
3
|
export { useNetworkState } from './hooks/use-network-state';
|
|
4
|
-
export
|
|
5
|
-
getNetworkStateAsync,
|
|
6
|
-
getIpAddressAsync,
|
|
7
|
-
isAirplaneModeEnabledAsync,
|
|
8
|
-
addNetworkStateListener,
|
|
9
|
-
NetworkStateType,
|
|
10
|
-
type NetworkState,
|
|
11
|
-
type NetworkStateEvent,
|
|
12
|
-
type EventSubscription,
|
|
13
|
-
} from '../core';
|
|
4
|
+
export * from '../core';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @symbiote-native/network/solid: the Solid entry over the framework-agnostic core — mirrors the
|
|
2
|
+
// lifecycle-bucket naming convention of adapters/solid/src/primitives (never `hooks`/`composables`/
|
|
3
|
+
// `runes`, those are React's, Vue's and Svelte's terms).
|
|
4
|
+
|
|
5
|
+
export { createNetworkState } from './primitives/create-network-state';
|
|
6
|
+
export * from '../core';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// createNetworkState — the Solid twin of React's `useNetworkState` hook, Vue's composable and
|
|
2
|
+
// Svelte's rune, over the framework-agnostic core (core/network.ts). Seeds with a one-shot
|
|
3
|
+
// getNetworkStateAsync() call before the first native event fires, matching upstream's own
|
|
4
|
+
// useNetworkState.
|
|
5
|
+
//
|
|
6
|
+
// `primitives/` and `create*`, never `hooks/`+`use*`: Solid's ecosystem calls a composable
|
|
7
|
+
// reactive function a PRIMITIVE and reserves `use*` for consuming something that already exists.
|
|
8
|
+
// Full rationale in adapters/solid/src/primitives/create-color-scheme.ts.
|
|
9
|
+
//
|
|
10
|
+
// Returns an ACCESSOR, never a snapshot: a Solid component body runs ONCE, so a returned object
|
|
11
|
+
// would pin the caller to the empty seed forever.
|
|
12
|
+
//
|
|
13
|
+
// Outside a component or `createRoot` there is no owner for `onCleanup` — Solid warns and the
|
|
14
|
+
// native listener lives for the process. The accessor still tracks; only the teardown is lost.
|
|
15
|
+
|
|
16
|
+
import { createSignal, onCleanup, type Accessor } from 'solid-js';
|
|
17
|
+
import {
|
|
18
|
+
addNetworkStateListener,
|
|
19
|
+
getNetworkStateAsync,
|
|
20
|
+
type EventSubscription,
|
|
21
|
+
type NetworkState,
|
|
22
|
+
} from '../../core';
|
|
23
|
+
|
|
24
|
+
export function createNetworkState(): Accessor<NetworkState> {
|
|
25
|
+
const [networkState, setNetworkState] = createSignal<NetworkState>({});
|
|
26
|
+
|
|
27
|
+
getNetworkStateAsync().then(state => {
|
|
28
|
+
setNetworkState(state);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Subscribed from the primitive body, not from an effect: React/Vue/Svelte start listening a
|
|
32
|
+
// tick after their seed runs, so a change landing in that window is lost. Both statements here
|
|
33
|
+
// run in one synchronous tick and nothing can interleave.
|
|
34
|
+
const subscription: EventSubscription = addNetworkStateListener(event => {
|
|
35
|
+
setNetworkState(event);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
onCleanup(() => {
|
|
39
|
+
subscription.remove();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return networkState;
|
|
43
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @symbiote-native/network/svelte: the Svelte entry over the framework-agnostic core — mirrors the
|
|
2
|
+
// lifecycle-bucket naming convention of adapters/svelte/src/runes (never `hooks`/`composables`,
|
|
3
|
+
// those are React's and Vue's terms).
|
|
4
|
+
|
|
5
|
+
export { useNetworkState } from './runes/use-network-state.svelte';
|
|
6
|
+
export * from '../core';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Svelte 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 and the Vue composable's onMounted half.
|
|
4
|
+
//
|
|
5
|
+
// `.svelte.ts` extension: runes ($state/$effect) only work there outside a `.svelte` component;
|
|
6
|
+
// `runes/` is Svelte's name for the lifecycle bucket (React's `hooks/`, Vue's `composables/`).
|
|
7
|
+
// Returns a boxed getter, not a bare `$state`: Svelte 5 reactivity is lexically scoped to the
|
|
8
|
+
// declaring module and doesn't survive being returned raw from a plain function, so the caller
|
|
9
|
+
// reads `.current` like unwrapping Vue's `Ref` via `.value`.
|
|
10
|
+
import {
|
|
11
|
+
addNetworkStateListener,
|
|
12
|
+
getNetworkStateAsync,
|
|
13
|
+
type EventSubscription,
|
|
14
|
+
type NetworkState,
|
|
15
|
+
} from '../../core';
|
|
16
|
+
|
|
17
|
+
export function useNetworkState(): { readonly current: NetworkState } {
|
|
18
|
+
let networkState = $state<NetworkState>({});
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
// Write-only touches of `networkState`, so the effect has no dependency on it and runs once
|
|
22
|
+
// per mount - the twin of Vue's onMounted/onUnmounted pair.
|
|
23
|
+
getNetworkStateAsync().then(state => {
|
|
24
|
+
networkState = state;
|
|
25
|
+
});
|
|
26
|
+
const subscription: EventSubscription = addNetworkStateListener(event => {
|
|
27
|
+
networkState = event;
|
|
28
|
+
});
|
|
29
|
+
return () => subscription.remove();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
get current(): NetworkState {
|
|
34
|
+
return networkState;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Pulls in svelte's ambient global declarations ($state/$effect/...) for this package's tsc
|
|
2
|
+
// program. adapters/svelte gets these for free because render.ts does a real value import from
|
|
3
|
+
// 'svelte' (any file in a program importing a module loads its ambient globals for the whole
|
|
4
|
+
// program); this package has no such import, so a triple-slash reference does the same job
|
|
5
|
+
// explicitly rather than relying on an incidental side-effect.
|
|
6
|
+
/// <reference types="svelte" />
|
package/src/vue/index.ts
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
// @symbiote-native/network/vue: the Vue entry over the framework-agnostic core.
|
|
2
2
|
|
|
3
3
|
export { useNetworkState } from './composables/use-network-state';
|
|
4
|
-
export
|
|
5
|
-
getNetworkStateAsync,
|
|
6
|
-
getIpAddressAsync,
|
|
7
|
-
isAirplaneModeEnabledAsync,
|
|
8
|
-
addNetworkStateListener,
|
|
9
|
-
NetworkStateType,
|
|
10
|
-
type NetworkState,
|
|
11
|
-
type NetworkStateEvent,
|
|
12
|
-
type EventSubscription,
|
|
13
|
-
} from '../core';
|
|
4
|
+
export * from '../core';
|