@symbiote-native/cellular 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 +232 -0
  3. package/build/angular/index.d.ts +2 -0
  4. package/build/angular/index.js +4 -0
  5. package/build/angular/services/permissions.service/index.d.ts +8 -0
  6. package/build/angular/services/permissions.service/index.js +76 -0
  7. package/build/core/cellular.d.ts +40 -0
  8. package/build/core/cellular.js +116 -0
  9. package/build/core/index.d.ts +2 -0
  10. package/build/core/index.js +2 -0
  11. package/build/core/native-module.d.ts +13 -0
  12. package/build/core/native-module.js +3 -0
  13. package/build/core/types.d.ts +14 -0
  14. package/build/core/types.js +19 -0
  15. package/build/react/hooks/use-permissions/index.d.ts +6 -0
  16. package/build/react/hooks/use-permissions/index.js +28 -0
  17. package/build/react/index.d.ts +2 -0
  18. package/build/react/index.js +4 -0
  19. package/build/vue/composables/use-permissions/index.d.ts +7 -0
  20. package/build/vue/composables/use-permissions/index.js +21 -0
  21. package/build/vue/index.d.ts +2 -0
  22. package/build/vue/index.js +4 -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/permissions.service/index.d.ts +11 -0
  27. package/build-ngc/angular/services/permissions.service/index.js +35 -0
  28. package/build-ngc/angular/services/permissions.service/index.js.map +1 -0
  29. package/build-ngc/core/cellular.d.ts +40 -0
  30. package/build-ngc/core/cellular.js +117 -0
  31. package/build-ngc/core/cellular.js.map +1 -0
  32. package/build-ngc/core/index.d.ts +2 -0
  33. package/build-ngc/core/index.js +3 -0
  34. package/build-ngc/core/index.js.map +1 -0
  35. package/build-ngc/core/native-module.d.ts +13 -0
  36. package/build-ngc/core/native-module.js +4 -0
  37. package/build-ngc/core/native-module.js.map +1 -0
  38. package/build-ngc/core/types.d.ts +14 -0
  39. package/build-ngc/core/types.js +20 -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 +4 -0
  44. package/src/angular/services/permissions.service/index.ts +35 -0
  45. package/src/angular/services/permissions.service/permissions.service.test.ts +109 -0
  46. package/src/core/cellular.test.ts +193 -0
  47. package/src/core/cellular.ts +131 -0
  48. package/src/core/index.ts +16 -0
  49. package/src/core/native-module.ts +24 -0
  50. package/src/core/types.ts +23 -0
  51. package/src/react/hooks/use-permissions/index.ts +39 -0
  52. package/src/react/hooks/use-permissions/use-permissions.test.tsx +115 -0
  53. package/src/react/index.ts +4 -0
  54. package/src/vue/composables/use-permissions/index.ts +34 -0
  55. package/src/vue/composables/use-permissions/use-permissions.test.ts +103 -0
  56. package/src/vue/index.ts +4 -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,232 @@
1
+ # @symbiote-native/cellular
2
+
3
+ A wrapper package for [SymbioteNative](../../README.md) that makes
4
+ [`expo-cellular`](https://docs.expo.dev/versions/latest/sdk/cellular/) — cellular connection
5
+ generation, carrier/SIM info, and VoIP-support detection — reachable from **every** adapter,
6
+ React, Vue, and Angular, not just React. Like [`@symbiote-native/sensors`](../sensors) and
7
+ unlike this repo's plain-RN-module/view wrappers ([`@symbiote-native/slider`](../slider),
8
+ [`@symbiote-native/splash-screen`](../splash-screen)), `expo-cellular` is built on
9
+ `expo-modules-core`, so its native code autolinks straight out of `node_modules` via
10
+ `expo-modules-autolinking` — no proxy `react-native.config.cjs`/podspec to ship. `expo-cellular`'s
11
+ own JS is never imported (it hard-imports the full `expo` meta-package, which this project never
12
+ depends on) — every function is hand-ported into this package's own `core/`.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @symbiote-native/cellular
18
+ ```
19
+
20
+ Depends on `expo-cellular` and `expo-modules-core` directly (regular dependencies, pinned to
21
+ exact versions — never a caret range, since this package's `core/` is hand-ported against one
22
+ specific native API shape and a newer resolve could silently drift the two apart). Never install
23
+ `expo-cellular` yourself, and never add the `expo` meta-package to this project — it bundles its
24
+ own 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-cellular`'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 with zero further changes:
32
+
33
+ | Platform | Touches |
34
+ |---|---|
35
+ | iOS | `ios/Podfile` — add `use_expo_modules!` |
36
+ | iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
37
+ | Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
38
+ | 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) |
39
+ | Android | `AndroidManifest.xml` — the `READ_PHONE_STATE` permission, needed to read carrier/SIM info |
40
+
41
+ Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
42
+ peer-dependency exclusion list, per-module permission strings — live in the
43
+ `symbiote-expo-native-module` project skill. This wiring is already done for all four
44
+ `examples/expo-*` canary apps (React, Vue SFC, Vue TSX, Angular).
45
+
46
+ ## Shape
47
+
48
+ ```
49
+ src/core/ cellular.ts (the free functions) + types.ts (CellularGeneration enum) +
50
+ native-module.ts, which resolves the native module by name through
51
+ expo-modules-core's requireNativeModule.
52
+ src/react/hooks/ @symbiote-native/cellular/react — usePermissions
53
+ src/vue/composables/ @symbiote-native/cellular/vue — usePermissions
54
+ src/angular/services/ @symbiote-native/cellular/angular — PermissionsService
55
+ ```
56
+
57
+ Each adapter's `usePermissions` hook/composable/service is a thin lifecycle wrapper (fetch on
58
+ mount, expose `request`/`get` to re-check imperatively) over the same `core` functions — the
59
+ permission-fetch logic is written once and shared by all three.
60
+
61
+ ## Use it
62
+
63
+ ```tsx
64
+ // React
65
+ import { useEffect, useState } from 'react';
66
+ import { CellularGeneration, getCarrierNameAsync, getCellularGenerationAsync } from '@symbiote-native/cellular';
67
+ import { usePermissions } from '@symbiote-native/cellular/react';
68
+
69
+ function CellularScreen() {
70
+ const [generation, setGeneration] = useState<CellularGeneration | null>(null);
71
+ const [carrierName, setCarrierName] = useState<string | null>(null);
72
+ const [status, requestPermission] = usePermissions();
73
+
74
+ useEffect(() => {
75
+ Promise.all([getCellularGenerationAsync(), getCarrierNameAsync()]).then(([gen, carrier]) => {
76
+ setGeneration(gen);
77
+ setCarrierName(carrier);
78
+ });
79
+ }, []);
80
+
81
+ return (
82
+ <>
83
+ <Text>{generation === null ? 'checking…' : CellularGeneration[generation]}</Text>
84
+ <Text>{carrierName ?? 'checking…'}</Text>
85
+ <Text>{status === null ? 'checking…' : status.status}</Text>
86
+ <Button title="Request permission" onPress={() => requestPermission()} />
87
+ </>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ```vue
93
+ <!-- Vue -->
94
+ <script setup lang="ts">
95
+ import { onMounted, ref } from 'vue';
96
+ import { CellularGeneration, getCarrierNameAsync, getCellularGenerationAsync } from '@symbiote-native/cellular';
97
+ import { usePermissions } from '@symbiote-native/cellular/vue';
98
+
99
+ const generation = ref<CellularGeneration | null>(null);
100
+ const carrierName = ref<string | null>(null);
101
+ const { status, request: requestPermission } = usePermissions();
102
+
103
+ onMounted(() => {
104
+ Promise.all([getCellularGenerationAsync(), getCarrierNameAsync()]).then(([gen, carrier]) => {
105
+ generation.value = gen;
106
+ carrierName.value = carrier;
107
+ });
108
+ });
109
+ </script>
110
+ <template>
111
+ <Text>{{ generation === null ? 'checking…' : CellularGeneration[generation] }}</Text>
112
+ <Text>{{ carrierName ?? 'checking…' }}</Text>
113
+ <Text>{{ status === null ? 'checking…' : status.status }}</Text>
114
+ <Button title="Request permission" :onPress="() => requestPermission()" />
115
+ </template>
116
+ ```
117
+
118
+ ```ts
119
+ // Angular
120
+ import { Component, inject, signal } from '@angular/core';
121
+ import { CellularGeneration, PermissionsService, getCarrierNameAsync, getCellularGenerationAsync } from '@symbiote-native/cellular/angular';
122
+
123
+ @Component({
124
+ selector: 'CellularScreen',
125
+ template: `
126
+ <Text>{{ generation() === null ? 'checking…' : CellularGeneration[generation()!] }}</Text>
127
+ <Text>{{ carrierName() ?? 'checking…' }}</Text>
128
+ <Text>{{ permissionStatus()?.status ?? 'checking…' }}</Text>
129
+ <Button title="Request permission" (press)="permissionsService.request()"></Button>
130
+ `,
131
+ })
132
+ export class CellularScreen {
133
+ readonly CellularGeneration = CellularGeneration;
134
+ private readonly permissionsService = inject(PermissionsService);
135
+ readonly permissionStatus = this.permissionsService.connect();
136
+
137
+ readonly generation = signal<CellularGeneration | null>(null);
138
+ readonly carrierName = signal<string | null>(null);
139
+
140
+ constructor() {
141
+ Promise.all([getCellularGenerationAsync(), getCarrierNameAsync()]).then(([generation, carrier]) => {
142
+ this.generation.set(generation);
143
+ this.carrierName.set(carrier);
144
+ });
145
+ }
146
+ }
147
+ ```
148
+
149
+ Trimmed from the real demo screens — `examples/expo-react/screens/CellularScreen.tsx` and its
150
+ Vue SFC, Vue TSX, and Angular twins (`examples/expo-vue-sfc/screens/CellularScreen.vue`,
151
+ `examples/expo-vue-tsx/screens/CellularScreen.tsx`, `examples/expo-angular/src/screens/CellularScreen.ts`),
152
+ which also cover `allowsVoipAsync`/`getIsoCountryCodeAsync`/`getMobileCountryCodeAsync`/
153
+ `getMobileNetworkCodeAsync` and gate the Android-only fields behind `Platform.OS === 'android'`.
154
+
155
+ ## API
156
+
157
+ Mostly stateless async functions, no event stream — plus one stateful pair,
158
+ `getPermissionsAsync`/`requestPermissionsAsync`, which gets its own lifecycle
159
+ hook/composable/service (`usePermissions`) so a component can re-check permission status
160
+ imperatively without re-wiring the fetch itself.
161
+
162
+ Carrier/SIM info and VoIP support are **Android only** — every one of those functions resolves
163
+ `null` on iOS without touching the native module at all, since iOS doesn't expose this
164
+ information. `getPermissionsAsync`/`requestPermissionsAsync` need no real permission grant on
165
+ iOS either (cellular info requires none there), so they resolve a plain `GRANTED` response
166
+ without a native call.
167
+
168
+ ```ts
169
+ getCellularGenerationAsync(): Promise<CellularGeneration>
170
+ // UNKNOWN/CELLULAR_2G/CELLULAR_3G/CELLULAR_4G/CELLULAR_5G. Delegates to the native module on
171
+ // every platform — no iOS gate, unlike every other function below.
172
+
173
+ allowsVoipAsync(): Promise<boolean | null>
174
+ // @deprecated (upstream is deprecating this). null on iOS, native call on Android.
175
+
176
+ getIsoCountryCodeAsync(): Promise<string | null> // Android only — null on iOS.
177
+ getCarrierNameAsync(): Promise<string | null> // Android only — null on iOS.
178
+ getMobileCountryCodeAsync(): Promise<string | null> // Android only — null on iOS.
179
+ getMobileNetworkCodeAsync(): Promise<string | null> // Android only — null on iOS.
180
+
181
+ getPermissionsAsync(): Promise<PermissionResponse>
182
+ // Android delegates to the native module; every other platform resolves a plain GRANTED
183
+ // literal — no permission is needed there for cellular info.
184
+
185
+ requestPermissionsAsync(): Promise<PermissionResponse>
186
+ // Same split as getPermissionsAsync.
187
+ ```
188
+
189
+ Plus `CellularGeneration` (enum) and `PermissionResponse`/`PermissionStatus`/
190
+ `PermissionExpiration` — the latter three re-exported straight from `expo-modules-core`, not
191
+ ported by hand.
192
+
193
+ ```ts
194
+ import { getCellularGenerationAsync, getCarrierNameAsync } from '@symbiote-native/cellular';
195
+
196
+ // framework-scoped entry points re-export the same free functions, plus usePermissions:
197
+ import { usePermissions } from '@symbiote-native/cellular/react';
198
+ import { usePermissions } from '@symbiote-native/cellular/vue';
199
+ import { PermissionsService } from '@symbiote-native/cellular/angular';
200
+ ```
201
+
202
+ ### `usePermissions`
203
+
204
+ Fetches the current permission status on mount, then exposes `request`/`get` to re-check it
205
+ imperatively — every adapter follows the same shape as its sibling `PermissionsService`/
206
+ composable in `@symbiote-native/brightness`, the other package in this repo needing the same
207
+ get/request permission pair.
208
+
209
+ ```tsx
210
+ // React — a [status, request, get] tuple, mirroring upstream's own usePermissions hooks
211
+ const [status, requestPermission, getPermission] = usePermissions();
212
+ ```
213
+
214
+ ```ts
215
+ // Vue — a { status, request, get } object; status is a Ref
216
+ const { status, request, get } = usePermissions();
217
+ ```
218
+
219
+ ```ts
220
+ // Angular — connect() returns a readonly Signal; request()/get() live on the service itself
221
+ readonly status = inject(PermissionsService).connect();
222
+ // later: inject(PermissionsService).request()
223
+ ```
224
+
225
+ ## Test it
226
+
227
+ No Fabric/Descriptor angle at all — cellular info is a pure async-function + permission surface,
228
+ never a view. Tests inject a fake native-module object in place of the real
229
+ `requireNativeModule` resolution (`src/core/cellular.test.ts`,
230
+ `src/{react,vue,angular}/**/*.test.{ts,tsx}`, run via `vitest`) — no `installFabric()`, no
231
+ ViewConfig. Native rendering itself is verified on-device (see the parent
232
+ [README](../../README.md)).
@@ -0,0 +1,2 @@
1
+ export { PermissionsService } from './services/permissions.service';
2
+ export * from '../core';
@@ -0,0 +1,4 @@
1
+ // @symbiote-native/cellular/angular: the Angular entry over the framework-agnostic core, plus
2
+ // PermissionsService — the only stateful surface this package needs a lifecycle wrapper for.
3
+ export { PermissionsService } from './services/permissions.service/index.js';
4
+ export * from '../core/index.js';
@@ -0,0 +1,8 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type PermissionResponse } from '../../../core';
3
+ export declare class PermissionsService {
4
+ private readonly status;
5
+ connect(): Signal<PermissionResponse | null>;
6
+ get(): Promise<PermissionResponse>;
7
+ request(): Promise<PermissionResponse>;
8
+ }
@@ -0,0 +1,76 @@
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
+ // Angular twin of React's `usePermissions` hook and Vue's `usePermissions` composable —
36
+ // see BatteryStateService's connect() pattern for the shape rationale.
37
+ //
38
+ // readonly status = inject(PermissionsService).connect();
39
+ // // template: {{ status()?.granted }}
40
+ import { Injectable, signal } from '@angular/core';
41
+ import { getPermissionsAsync, requestPermissionsAsync, } from '../../../core';
42
+ let PermissionsService = (() => {
43
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
44
+ let _classDescriptor;
45
+ let _classExtraInitializers = [];
46
+ let _classThis;
47
+ var PermissionsService = class {
48
+ static { _classThis = this; }
49
+ static {
50
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
51
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
52
+ PermissionsService = _classThis = _classDescriptor.value;
53
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
54
+ __runInitializers(_classThis, _classExtraInitializers);
55
+ }
56
+ status = signal(null);
57
+ connect() {
58
+ if (this.status() === null) {
59
+ void this.get();
60
+ }
61
+ return this.status.asReadonly();
62
+ }
63
+ async get() {
64
+ const response = await getPermissionsAsync();
65
+ this.status.set(response);
66
+ return response;
67
+ }
68
+ async request() {
69
+ const response = await requestPermissionsAsync();
70
+ this.status.set(response);
71
+ return response;
72
+ }
73
+ };
74
+ return PermissionsService = _classThis;
75
+ })();
76
+ export { PermissionsService };
@@ -0,0 +1,40 @@
1
+ import { type PermissionResponse } from 'expo-modules-core';
2
+ import { CellularGeneration } from './types';
3
+ /** Gets the generation of the device's current connection. */
4
+ export declare function getCellularGenerationAsync(): Promise<CellularGeneration>;
5
+ /**
6
+ * Tells if the carrier of the SIM card allows to make VoIP calls on its network.
7
+ * @deprecated This method is deprecated and will be removed in a future SDK version.
8
+ * @platform android
9
+ */
10
+ export declare function allowsVoipAsync(): Promise<boolean | null>;
11
+ /**
12
+ * Gets the ISO country code of the current registered operator's MCC (Mobile Country Code).
13
+ * @platform android
14
+ */
15
+ export declare function getIsoCountryCodeAsync(): Promise<string | null>;
16
+ /**
17
+ * Gets the name of the user's cellular service provider.
18
+ * @platform android
19
+ */
20
+ export declare function getCarrierNameAsync(): Promise<string | null>;
21
+ /**
22
+ * Gets the mobile country code (MCC) of the device's current registered operator.
23
+ * @platform android
24
+ */
25
+ export declare function getMobileCountryCodeAsync(): Promise<string | null>;
26
+ /**
27
+ * Gets the mobile network code (MNC) of the device's current registered operator.
28
+ * @platform android
29
+ */
30
+ export declare function getMobileNetworkCodeAsync(): Promise<string | null>;
31
+ /**
32
+ * Checks user's permissions for accessing cellular information. Android only — iOS/web need no
33
+ * permission for cellular info, so this always resolves granted there.
34
+ */
35
+ export declare function getPermissionsAsync(): Promise<PermissionResponse>;
36
+ /**
37
+ * Asks the user to grant permissions for accessing cellular information. Android only — iOS/web
38
+ * need no permission for cellular info, so this always resolves granted there.
39
+ */
40
+ export declare function requestPermissionsAsync(): Promise<PermissionResponse>;
@@ -0,0 +1,116 @@
1
+ // Hand-ported from .vendors/expo/packages/expo-cellular/src/Cellular.ts (sdk-57). Carrier/SIM
2
+ // info (ISO country code, carrier name, MCC/MNC) and allowsVoipAsync are Android-only upstream —
3
+ // each short-circuits to `null` on iOS before ever reaching the native module, since iOS exposes
4
+ // none of this. getPermissionsAsync/requestPermissionsAsync mirror that same split: Android
5
+ // delegates to the native module, every other platform needs no permission for cellular info at
6
+ // all and resolves a plain GRANTED literal. Upstream's web branch (navigator.connection) is out
7
+ // of scope — this repo has no web target for this package's native-module resolution path.
8
+ import { Platform, PermissionStatus, UnavailabilityError, } from 'expo-modules-core';
9
+ import { expoCellular } from './native-module';
10
+ import { CellularGeneration } from './types';
11
+ const NATIVE_MODULE_NAME = 'expo-cellular';
12
+ const GRANTED_PERMISSION_RESPONSE = {
13
+ status: PermissionStatus.GRANTED,
14
+ expires: 'never',
15
+ granted: true,
16
+ canAskAgain: true,
17
+ };
18
+ /** Gets the generation of the device's current connection. */
19
+ export async function getCellularGenerationAsync() {
20
+ if (!expoCellular.getCellularGenerationAsync) {
21
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getCellularGenerationAsync');
22
+ }
23
+ return expoCellular.getCellularGenerationAsync();
24
+ }
25
+ /**
26
+ * Tells if the carrier of the SIM card allows to make VoIP calls on its network.
27
+ * @deprecated This method is deprecated and will be removed in a future SDK version.
28
+ * @platform android
29
+ */
30
+ export async function allowsVoipAsync() {
31
+ if (Platform.OS === 'ios') {
32
+ return null;
33
+ }
34
+ if (!expoCellular.allowsVoipAsync) {
35
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'allowsVoipAsync');
36
+ }
37
+ return expoCellular.allowsVoipAsync();
38
+ }
39
+ /**
40
+ * Gets the ISO country code of the current registered operator's MCC (Mobile Country Code).
41
+ * @platform android
42
+ */
43
+ export async function getIsoCountryCodeAsync() {
44
+ if (Platform.OS === 'ios') {
45
+ return null;
46
+ }
47
+ if (!expoCellular.getIsoCountryCodeAsync) {
48
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getIsoCountryCodeAsync');
49
+ }
50
+ return expoCellular.getIsoCountryCodeAsync();
51
+ }
52
+ /**
53
+ * Gets the name of the user's cellular service provider.
54
+ * @platform android
55
+ */
56
+ export async function getCarrierNameAsync() {
57
+ if (Platform.OS === 'ios') {
58
+ return null;
59
+ }
60
+ if (!expoCellular.getCarrierNameAsync) {
61
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getCarrierNameAsync');
62
+ }
63
+ return expoCellular.getCarrierNameAsync();
64
+ }
65
+ /**
66
+ * Gets the mobile country code (MCC) of the device's current registered operator.
67
+ * @platform android
68
+ */
69
+ export async function getMobileCountryCodeAsync() {
70
+ if (Platform.OS === 'ios') {
71
+ return null;
72
+ }
73
+ if (!expoCellular.getMobileCountryCodeAsync) {
74
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getMobileCountryCodeAsync');
75
+ }
76
+ return expoCellular.getMobileCountryCodeAsync();
77
+ }
78
+ /**
79
+ * Gets the mobile network code (MNC) of the device's current registered operator.
80
+ * @platform android
81
+ */
82
+ export async function getMobileNetworkCodeAsync() {
83
+ if (Platform.OS === 'ios') {
84
+ return null;
85
+ }
86
+ if (!expoCellular.getMobileNetworkCodeAsync) {
87
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getMobileNetworkCodeAsync');
88
+ }
89
+ return expoCellular.getMobileNetworkCodeAsync();
90
+ }
91
+ /**
92
+ * Checks user's permissions for accessing cellular information. Android only — iOS/web need no
93
+ * permission for cellular info, so this always resolves granted there.
94
+ */
95
+ export async function getPermissionsAsync() {
96
+ if (Platform.OS === 'android') {
97
+ if (!expoCellular.getPermissionsAsync) {
98
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getPermissionsAsync');
99
+ }
100
+ return expoCellular.getPermissionsAsync();
101
+ }
102
+ return GRANTED_PERMISSION_RESPONSE;
103
+ }
104
+ /**
105
+ * Asks the user to grant permissions for accessing cellular information. Android only — iOS/web
106
+ * need no permission for cellular info, so this always resolves granted there.
107
+ */
108
+ export async function requestPermissionsAsync() {
109
+ if (Platform.OS === 'android') {
110
+ if (!expoCellular.requestPermissionsAsync) {
111
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'requestPermissionsAsync');
112
+ }
113
+ return expoCellular.requestPermissionsAsync();
114
+ }
115
+ return GRANTED_PERMISSION_RESPONSE;
116
+ }
@@ -0,0 +1,2 @@
1
+ export { getCellularGenerationAsync, allowsVoipAsync, getIsoCountryCodeAsync, getCarrierNameAsync, getMobileCountryCodeAsync, getMobileNetworkCodeAsync, getPermissionsAsync, requestPermissionsAsync, } from './cellular';
2
+ export { CellularGeneration, PermissionStatus, type PermissionResponse, type PermissionExpiration, } from './types';
@@ -0,0 +1,2 @@
1
+ export { getCellularGenerationAsync, allowsVoipAsync, getIsoCountryCodeAsync, getCarrierNameAsync, getMobileCountryCodeAsync, getMobileNetworkCodeAsync, getPermissionsAsync, requestPermissionsAsync, } from './cellular.js';
2
+ export { CellularGeneration, PermissionStatus, } from './types.js';
@@ -0,0 +1,13 @@
1
+ import type { PermissionResponse } from 'expo-modules-core';
2
+ import type { CellularGeneration } from './types';
3
+ export type INativeCellularModule = {
4
+ getCellularGenerationAsync?(): Promise<CellularGeneration>;
5
+ allowsVoipAsync?(): Promise<boolean>;
6
+ getIsoCountryCodeAsync?(): Promise<string | null>;
7
+ getCarrierNameAsync?(): Promise<string | null>;
8
+ getMobileCountryCodeAsync?(): Promise<string | null>;
9
+ getMobileNetworkCodeAsync?(): Promise<string | null>;
10
+ getPermissionsAsync?(): Promise<PermissionResponse>;
11
+ requestPermissionsAsync?(): Promise<PermissionResponse>;
12
+ };
13
+ export declare const expoCellular: INativeCellularModule;
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ const EXPO_CELLULAR_MODULE_NAME = 'ExpoCellular';
3
+ export const expoCellular = requireNativeModule(EXPO_CELLULAR_MODULE_NAME);
@@ -0,0 +1,14 @@
1
+ export { PermissionStatus, type PermissionResponse, type PermissionExpiration, } from 'expo-modules-core';
2
+ /** Telecommunication technology used to establish a cellular connection. */
3
+ export declare enum CellularGeneration {
4
+ /** The device's connection generation could not be determined. */
5
+ UNKNOWN = 0,
6
+ /** 2nd generation (GPRS/EDGE-class) connection. */
7
+ CELLULAR_2G = 1,
8
+ /** 3rd generation (UMTS/HSPA-class) connection. */
9
+ CELLULAR_3G = 2,
10
+ /** 4th generation (LTE-class) connection. */
11
+ CELLULAR_4G = 3,
12
+ /** 5th generation (NR-class) connection. */
13
+ CELLULAR_5G = 4
14
+ }
@@ -0,0 +1,19 @@
1
+ // Hand-ported from .vendors/expo/packages/expo-cellular/src/Cellular.types.ts (sdk-57).
2
+ // PermissionResponse/PermissionStatus/PermissionExpiration come straight from
3
+ // expo-modules-core (which re-exports PermissionsInterface) — never from the `expo`
4
+ // meta-package, unlike upstream's own Cellular.ts.
5
+ export { PermissionStatus, } from 'expo-modules-core';
6
+ /** Telecommunication technology used to establish a cellular connection. */
7
+ export var CellularGeneration;
8
+ (function (CellularGeneration) {
9
+ /** The device's connection generation could not be determined. */
10
+ CellularGeneration[CellularGeneration["UNKNOWN"] = 0] = "UNKNOWN";
11
+ /** 2nd generation (GPRS/EDGE-class) connection. */
12
+ CellularGeneration[CellularGeneration["CELLULAR_2G"] = 1] = "CELLULAR_2G";
13
+ /** 3rd generation (UMTS/HSPA-class) connection. */
14
+ CellularGeneration[CellularGeneration["CELLULAR_3G"] = 2] = "CELLULAR_3G";
15
+ /** 4th generation (LTE-class) connection. */
16
+ CellularGeneration[CellularGeneration["CELLULAR_4G"] = 3] = "CELLULAR_4G";
17
+ /** 5th generation (NR-class) connection. */
18
+ CellularGeneration[CellularGeneration["CELLULAR_5G"] = 4] = "CELLULAR_5G";
19
+ })(CellularGeneration || (CellularGeneration = {}));
@@ -0,0 +1,6 @@
1
+ import { type PermissionResponse } from '../../../core';
2
+ export declare function usePermissions(): [
3
+ PermissionResponse | null,
4
+ () => Promise<PermissionResponse>,
5
+ () => Promise<PermissionResponse>
6
+ ];
@@ -0,0 +1,28 @@
1
+ // React lifecycle wiring over the framework-agnostic core (core/cellular.ts) — fetches the
2
+ // current permission status on mount, then exposes request/get to re-check imperatively.
3
+ import { useCallback, useEffect, useRef, useState } from 'react';
4
+ import { getPermissionsAsync, requestPermissionsAsync, } from '../../../core';
5
+ export function usePermissions() {
6
+ const isMounted = useRef(true);
7
+ const [status, setStatus] = useState(null);
8
+ const getPermission = useCallback(async () => {
9
+ const response = await getPermissionsAsync();
10
+ if (isMounted.current)
11
+ setStatus(response);
12
+ return response;
13
+ }, []);
14
+ const requestPermission = useCallback(async () => {
15
+ const response = await requestPermissionsAsync();
16
+ if (isMounted.current)
17
+ setStatus(response);
18
+ return response;
19
+ }, []);
20
+ useEffect(() => {
21
+ isMounted.current = true;
22
+ void getPermission();
23
+ return () => {
24
+ isMounted.current = false;
25
+ };
26
+ }, [getPermission]);
27
+ return [status, requestPermission, getPermission];
28
+ }
@@ -0,0 +1,2 @@
1
+ export { usePermissions } from './hooks/use-permissions';
2
+ export * from '../core';
@@ -0,0 +1,4 @@
1
+ // @symbiote-native/cellular/react: the React entry over the framework-agnostic core, plus
2
+ // usePermissions — the only stateful surface this package needs a lifecycle wrapper for.
3
+ export { usePermissions } from './hooks/use-permissions/index.js';
4
+ export * from '../core/index.js';
@@ -0,0 +1,7 @@
1
+ import { type Ref } from '@vue/runtime-core';
2
+ import { type PermissionResponse } from '../../../core';
3
+ export declare function usePermissions(): {
4
+ status: Ref<PermissionResponse | null>;
5
+ request: () => Promise<PermissionResponse>;
6
+ get: () => Promise<PermissionResponse>;
7
+ };
@@ -0,0 +1,21 @@
1
+ // Vue lifecycle wiring over the framework-agnostic core (core/cellular.ts) — fetches the
2
+ // current permission status on mount, then exposes request/get to re-check imperatively.
3
+ import { onMounted, ref } from '@vue/runtime-core';
4
+ import { getPermissionsAsync, requestPermissionsAsync, } from '../../../core';
5
+ export function usePermissions() {
6
+ const status = ref(null);
7
+ const get = async () => {
8
+ const response = await getPermissionsAsync();
9
+ status.value = response;
10
+ return response;
11
+ };
12
+ const request = async () => {
13
+ const response = await requestPermissionsAsync();
14
+ status.value = response;
15
+ return response;
16
+ };
17
+ onMounted(() => {
18
+ void get();
19
+ });
20
+ return { status, request, get };
21
+ }
@@ -0,0 +1,2 @@
1
+ export { usePermissions } from './composables/use-permissions';
2
+ export * from '../core';