@abihealth/goapp-react-native 1.20.3 → 1.22.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/CHANGELOG.md +16 -0
- package/README.md +272 -2
- package/dist/common/api/config.js +1 -2
- package/dist/common/api/partner.js +3 -1
- package/dist/common/api/sslPinning.d.ts +1 -0
- package/dist/common/api/sslPinning.js +61 -0
- package/dist/common/api/websocket.js +1 -2
- package/dist/common/components/ConsultationContainer.d.ts +2 -0
- package/dist/common/components/ConsultationContainer.js +12 -0
- package/dist/common/contexts/ConsultationContext.d.ts +3 -1
- package/dist/common/contexts/ConsultationContext.js +58 -36
- package/dist/common/hooks/useConsultation.d.ts +1 -0
- package/dist/common/hooks/useConsultation.js +3 -2
- package/dist/form-prescriptions/components/FormPrescription.js +4 -6
- package/dist/text-consultations/components/TextConsultation.js +3 -6
- package/dist/video-consultations/components/VideoConsultation.js +3 -5
- package/package.json +17 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.22.0](https://github.com/abiglobalhealth/react-native-sdk/compare/goapp-react-native-v1.21.0...goapp-react-native-v1.22.0) (2025-04-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add caret to svg dependency ([#172](https://github.com/abiglobalhealth/react-native-sdk/issues/172)) ([79b08fc](https://github.com/abiglobalhealth/react-native-sdk/commit/79b08fc3761e6d5005208eb1b90b4b6a054bf206))
|
|
9
|
+
* add SSL pinning ([#173](https://github.com/abiglobalhealth/react-native-sdk/issues/173)) ([07cbd47](https://github.com/abiglobalhealth/react-native-sdk/commit/07cbd47ef327a7c836d2671485963936ca2cf5f0))
|
|
10
|
+
|
|
11
|
+
## [1.21.0](https://github.com/abiglobalhealth/react-native-sdk/compare/goapp-react-native-v1.20.3...goapp-react-native-v1.21.0) (2025-04-14)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* create a styled ConsultationContainer component for cases ([#166](https://github.com/abiglobalhealth/react-native-sdk/issues/166)) ([528f6e5](https://github.com/abiglobalhealth/react-native-sdk/commit/528f6e5b9a96393a271100d0777463baa08281f9))
|
|
17
|
+
* use new domains ([#169](https://github.com/abiglobalhealth/react-native-sdk/issues/169)) ([ee64438](https://github.com/abiglobalhealth/react-native-sdk/commit/ee644381aa86b94344b0ca8a5f5126b16b7d8ea3))
|
|
18
|
+
|
|
3
19
|
## [1.20.3](https://github.com/abiglobalhealth/react-native-sdk/compare/goapp-react-native-v1.20.2...goapp-react-native-v1.20.3) (2025-03-27)
|
|
4
20
|
|
|
5
21
|
|
package/README.md
CHANGED
|
@@ -1,3 +1,273 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Abi GoApp SDK Installation Guide
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This guide explains how to install the `@abihealth/goapp-react-native` SDK and its peer dependencies. Correct installation and configuration are needed to use the SDK's features.
|
|
4
|
+
|
|
5
|
+
## Installation Requirements
|
|
6
|
+
|
|
7
|
+
Install the main package (`@abihealth/goapp-react-native`) and these essential peer dependencies:
|
|
8
|
+
|
|
9
|
+
- **react-native-agora** ([npm](https://www.npmjs.com/package/react-native-agora)): For video calls
|
|
10
|
+
- **react-native-svg** ([npm](https://www.npmjs.com/package/react-native-svg)): For rendering SVGs
|
|
11
|
+
- **react-native-ssl-public-key-pinning** ([npm](https://www.npmjs.com/package/react-native-ssl-public-key-pinning)): For security
|
|
12
|
+
|
|
13
|
+
Follow the instructions for your environment (Bare React Native or Expo). Always consult the official docs for each dependency for detailed information.
|
|
14
|
+
|
|
15
|
+
## Expo Projects (Managed Workflow)
|
|
16
|
+
|
|
17
|
+
Use these steps for Expo managed workflow (requires a development build).
|
|
18
|
+
|
|
19
|
+
### 1. Install using expo install
|
|
20
|
+
|
|
21
|
+
This command helps install compatible versions:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx expo install @abihealth/goapp-react-native react-native-agora react-native-svg react-native-ssl-public-key-pinning
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Configure Permissions and Plugins
|
|
28
|
+
|
|
29
|
+
Set up permissions and required Expo plugins in `app.json` or `app.config.js`:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"expo": {
|
|
34
|
+
"plugins": [
|
|
35
|
+
[
|
|
36
|
+
"react-native-agora",
|
|
37
|
+
{
|
|
38
|
+
"cameraPermission": "Allow $(PRODUCT_NAME) to access camera for video.",
|
|
39
|
+
"microphonePermission": "Allow $(PRODUCT_NAME) to access microphone for video."
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
],
|
|
43
|
+
"android": {
|
|
44
|
+
"permissions": ["android.permission.CAMERA", "android.permission.RECORD_AUDIO"]
|
|
45
|
+
},
|
|
46
|
+
"ios": {
|
|
47
|
+
"infoPlist": {
|
|
48
|
+
"NSCameraUsageDescription": "Allow $(PRODUCT_NAME) access for video calls.",
|
|
49
|
+
"NSMicrophoneUsageDescription": "Allow $(PRODUCT_NAME) access for video calls."
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> **Important**: Plugin configurations may change. Always check official react-native-agora docs. Verify Expo compatibility for react-native-ssl-public-key-pinning.
|
|
57
|
+
|
|
58
|
+
### 3. Create a Development Build
|
|
59
|
+
|
|
60
|
+
Standard Expo Go is insufficient. Create a development build:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx expo run:android
|
|
64
|
+
# or
|
|
65
|
+
npx expo run:ios
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Alternatively, use EAS Build:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
eas build --profile development --platform [android|ios]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Install the build, then run your project:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npx expo start --dev-client
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Bare React Native Projects
|
|
81
|
+
|
|
82
|
+
Use these steps for standard bare React Native projects.
|
|
83
|
+
|
|
84
|
+
### 1. Install SDK and dependencies
|
|
85
|
+
|
|
86
|
+
Using npm:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install @abihealth/goapp-react-native react-native-agora react-native-svg react-native-ssl-public-key-pinning
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Or using Yarn:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
yarn add @abihealth/goapp-react-native react-native-agora react-native-svg react-native-ssl-public-key-pinning
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 2. Link native dependencies (React Native < 0.60)
|
|
99
|
+
|
|
100
|
+
If using RN < 0.60, you might need manual linking:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx react-native link react-native-agora react-native-svg react-native-ssl-public-key-pinning
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
> Note: Autolinking should work for RN >= 0.60 (iOS/Android). Verify if issues arise.
|
|
107
|
+
|
|
108
|
+
### 3. Install Pods (iOS)
|
|
109
|
+
|
|
110
|
+
Install CocoaPods dependencies:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
cd ios && pod install && cd ..
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 4. Android Setup & Permissions
|
|
117
|
+
|
|
118
|
+
Add necessary permissions to `android/app/src/main/AndroidManifest.xml`:
|
|
119
|
+
|
|
120
|
+
```xml
|
|
121
|
+
<uses-permission android:name="android.permission.CAMERA" />
|
|
122
|
+
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Agora Specific: Ensure JitPack is in `android/build.gradle`:
|
|
126
|
+
|
|
127
|
+
```gradle
|
|
128
|
+
allprojects {
|
|
129
|
+
repositories {
|
|
130
|
+
// ... other repositories
|
|
131
|
+
maven { url 'https://www.jitpack.io' }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 5. iOS Setup & Permissions
|
|
137
|
+
|
|
138
|
+
Add privacy descriptions to `ios/<YourProjectName>/Info.plist`:
|
|
139
|
+
|
|
140
|
+
- **NSCameraUsageDescription**: Reason for camera access (e.g., "Enable video calls")
|
|
141
|
+
- **NSMicrophoneUsageDescription**: Reason for microphone access (e.g., "Enable audio in video calls")
|
|
142
|
+
|
|
143
|
+
## Post-Installation
|
|
144
|
+
|
|
145
|
+
After installing and configuring dependencies, import and use `@abihealth/goapp-react-native`. Remember `react-native-ssl-public-key-pinning` needs careful key/domain setup. Ensure your build environment (SDK/NDK versions, Xcode) is correct.
|
|
146
|
+
|
|
147
|
+
## Usage
|
|
148
|
+
|
|
149
|
+
Basic guide to integrating SDK components:
|
|
150
|
+
|
|
151
|
+
### 1. Import components and hooks
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { ConsultationsProvider, VideoConsultation, useConsultation } from '@abihealth/goapp-react-native'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 2. Wrap your app with ConsultationsProvider
|
|
158
|
+
|
|
159
|
+
Initializes SDK context with necessary configuration:
|
|
160
|
+
|
|
161
|
+
```jsx
|
|
162
|
+
// Example App.js
|
|
163
|
+
import React from 'react'
|
|
164
|
+
import { ConsultationsProvider } from '@abihealth/goapp-react-native'
|
|
165
|
+
import MainApp from './MainApp'
|
|
166
|
+
|
|
167
|
+
const user_access_token = 'YOUR_USER_ACCESS_TOKEN' // Get from your app logic
|
|
168
|
+
const region = 'YOUR_API_REGION' // Get from your app logic
|
|
169
|
+
// Optional props
|
|
170
|
+
const theme = {
|
|
171
|
+
/* Custom theme */
|
|
172
|
+
}
|
|
173
|
+
const components = {
|
|
174
|
+
/* Custom components */
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const App = () => {
|
|
178
|
+
const onError = (error) => {
|
|
179
|
+
console.error('SDK Error:', error)
|
|
180
|
+
/* Handle error */
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<ConsultationsProvider
|
|
185
|
+
region={region}
|
|
186
|
+
token={user_access_token}
|
|
187
|
+
theme={theme} // Optional
|
|
188
|
+
components={components} // Optional
|
|
189
|
+
onError={onError} // Optional
|
|
190
|
+
>
|
|
191
|
+
{/* Other components */}
|
|
192
|
+
</ConsultationsProvider>
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export default App
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### Provider Props:
|
|
200
|
+
|
|
201
|
+
- `region` (string, required): API region
|
|
202
|
+
- `token` (string, required): User authentication token
|
|
203
|
+
- `theme` (object, optional): Customize visual theme
|
|
204
|
+
- `components` (object, optional): Override default components
|
|
205
|
+
- `onError` (function, optional): Error callback
|
|
206
|
+
|
|
207
|
+
### 3. Use the VideoConsultation component
|
|
208
|
+
|
|
209
|
+
Renders the video consultation UI:
|
|
210
|
+
|
|
211
|
+
```jsx
|
|
212
|
+
// Example ConsultationScreen.js
|
|
213
|
+
import React from 'react'
|
|
214
|
+
import { View } from 'react-native'
|
|
215
|
+
import { VideoConsultation } from '@abihealth/goapp-react-native'
|
|
216
|
+
|
|
217
|
+
// Optional props
|
|
218
|
+
const options = {
|
|
219
|
+
/* Video call options */
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const ConsultationScreen = () => {
|
|
223
|
+
const eventHandlers = {
|
|
224
|
+
/* Callbacks for events */
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return <VideoConsultation options={options} eventHandlers={eventHandlers} />
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export default ConsultationScreen
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### VideoConsultation Props:
|
|
234
|
+
|
|
235
|
+
- `options` (object, optional): Video call appearance/behavior config
|
|
236
|
+
- `eventHandlers` (object, optional): Callbacks for video call events
|
|
237
|
+
|
|
238
|
+
### 4. Use the useConsultation hook
|
|
239
|
+
|
|
240
|
+
Access consultation state and control functions:
|
|
241
|
+
|
|
242
|
+
```jsx
|
|
243
|
+
// Example ConsultationControls.js
|
|
244
|
+
import React from 'react'
|
|
245
|
+
import { View, Button, Text } from 'react-native'
|
|
246
|
+
import { useConsultation } from '@abihealth/goapp-react-native'
|
|
247
|
+
|
|
248
|
+
const ConsultationControls = () => {
|
|
249
|
+
const { consultation, start, cancel } = useConsultation()
|
|
250
|
+
|
|
251
|
+
const handleStart = () => start(/* params if needed */)
|
|
252
|
+
const handleCancel = () => cancel(/* params if needed */)
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<View>
|
|
256
|
+
{consultation && <Text>Consultation Info: {/* Details */}</Text>}
|
|
257
|
+
<Button title="Start" onPress={handleStart} />
|
|
258
|
+
<Button title="Cancel" onPress={handleCancel} />
|
|
259
|
+
</View>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export default ConsultationControls
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### useConsultation Hook returns:
|
|
267
|
+
|
|
268
|
+
- `consultation` (object | null): Current/last consultation info
|
|
269
|
+
- `start` (function): Initiates consultation
|
|
270
|
+
- `cancel` (function): Cancels consultation
|
|
271
|
+
- Other values may be available; check SDK docs
|
|
272
|
+
|
|
273
|
+
Always consult the specific `@abihealth/goapp-react-native` documentation for details on props, events, hooks, parameters, and advanced configuration.
|
|
@@ -6,10 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.axios = exports.configureAxios = void 0;
|
|
7
7
|
var axios_1 = __importDefault(require("axios"));
|
|
8
8
|
exports.axios = axios_1.default;
|
|
9
|
-
var BASE_URL = { ape1: 'https://m10bzqot97.execute-api.ap-east-1.amazonaws.com/prod' };
|
|
10
9
|
var configureAxios = function (_a) {
|
|
11
10
|
var token = _a.token, region = _a.region;
|
|
12
|
-
axios_1.default.defaults.baseURL =
|
|
11
|
+
axios_1.default.defaults.baseURL = "https://".concat(region, ".sdk.abi.ai");
|
|
13
12
|
axios_1.default.defaults.headers.common.Authorization = "Bearer ".concat(token);
|
|
14
13
|
};
|
|
15
14
|
exports.configureAxios = configureAxios;
|
|
@@ -6,5 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.getPartnerInfo = void 0;
|
|
7
7
|
var axios_1 = __importDefault(require("axios"));
|
|
8
8
|
var PARTNER_URL = 'partner';
|
|
9
|
-
var getPartnerInfo = function () {
|
|
9
|
+
var getPartnerInfo = function () {
|
|
10
|
+
return axios_1.default.get(PARTNER_URL).then(function (response) { return response === null || response === void 0 ? void 0 : response.data; });
|
|
11
|
+
};
|
|
10
12
|
exports.getPartnerInfo = getPartnerInfo;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const initializeSslPinning: (disableSslPinning: boolean) => Promise<void>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.initializeSslPinning = void 0;
|
|
40
|
+
var react_native_ssl_public_key_pinning_1 = require("react-native-ssl-public-key-pinning");
|
|
41
|
+
var initializeSslPinning = function (disableSslPinning) { return __awaiter(void 0, void 0, void 0, function () {
|
|
42
|
+
return __generator(this, function (_a) {
|
|
43
|
+
switch (_a.label) {
|
|
44
|
+
case 0:
|
|
45
|
+
if (!disableSslPinning) return [3 /*break*/, 2];
|
|
46
|
+
return [4 /*yield*/, (0, react_native_ssl_public_key_pinning_1.disableSslPinning)()];
|
|
47
|
+
case 1:
|
|
48
|
+
_a.sent();
|
|
49
|
+
return [2 /*return*/, console.log('🔒🚫 SSL pinning disabled')];
|
|
50
|
+
case 2: return [4 /*yield*/, (0, react_native_ssl_public_key_pinning_1.initializeSslPinning)({
|
|
51
|
+
'ape1.sdk.abi.ai': {
|
|
52
|
+
publicKeyHashes: ['95kHJrJXD1L/WORHTc5rh99KvZ10Ipd9m7eW0JUsLnA=', 'b+nnCNzPN8D2jN0srTRwMXqLUjmnZODZ0k28NZFFrkc=']
|
|
53
|
+
}
|
|
54
|
+
})];
|
|
55
|
+
case 3:
|
|
56
|
+
_a.sent();
|
|
57
|
+
return [2 /*return*/, console.log('🔒 SSL pinning initialized')];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}); };
|
|
61
|
+
exports.initializeSslPinning = initializeSslPinning;
|
|
@@ -37,14 +37,13 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.connectWebsocket = void 0;
|
|
40
|
-
var WS_URL = { ape1: 'wss://yrmfk5amqg.execute-api.ap-east-1.amazonaws.com/prod' };
|
|
41
40
|
var connectWebsocket = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
|
|
42
41
|
var token = _b.token, userId = _b.userId, region = _b.region;
|
|
43
42
|
return __generator(this, function (_c) {
|
|
44
43
|
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
45
44
|
console.log('❔ Connecting to WS...', { token: token, userId: userId, region: region });
|
|
46
45
|
try {
|
|
47
|
-
var websocket_1 = new WebSocket("".concat(
|
|
46
|
+
var websocket_1 = new WebSocket("wss://".concat(region, ".sdk-ws.abi.ai?eventType=CONNECT"), null);
|
|
48
47
|
websocket_1.onopen = function () {
|
|
49
48
|
console.log('🟢 WS connected');
|
|
50
49
|
websocket_1.send(JSON.stringify({ action: 'connect', payload: { userId: userId, token: "Bearer ".concat(token) } }));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsultationContainer = void 0;
|
|
4
|
+
var react_native_1 = require("react-native");
|
|
5
|
+
var ConsultationContainer = function (_a) {
|
|
6
|
+
var children = _a.children;
|
|
7
|
+
return <react_native_1.View style={styles.container}>{children}</react_native_1.View>;
|
|
8
|
+
};
|
|
9
|
+
exports.ConsultationContainer = ConsultationContainer;
|
|
10
|
+
var styles = react_native_1.StyleSheet.create({
|
|
11
|
+
container: { flex: 1, width: '100%', minWidth: '100%' }
|
|
12
|
+
});
|
|
@@ -11,6 +11,7 @@ interface ConsultationProviderProps {
|
|
|
11
11
|
theme?: RecursivePartial<Theme>;
|
|
12
12
|
components?: (theme: Theme) => Components;
|
|
13
13
|
onError?: ErrorCallback;
|
|
14
|
+
disableSslPinning?: boolean;
|
|
14
15
|
}
|
|
15
16
|
export type ConsultationContextProps = ConsultationProviderProps & {
|
|
16
17
|
consultation: Consultation | null;
|
|
@@ -20,7 +21,8 @@ export type ConsultationContextProps = ConsultationProviderProps & {
|
|
|
20
21
|
user: User;
|
|
21
22
|
setUser: Dispatch<SetStateAction<User>>;
|
|
22
23
|
slug: string | null;
|
|
24
|
+
initialised: boolean;
|
|
23
25
|
};
|
|
24
26
|
export declare const ConsultationContext: import("react").Context<ConsultationContextProps>;
|
|
25
|
-
export declare const ConsultationProvider: ({ children, token, region, theme, components, onError }: PropsWithChildren<ConsultationProviderProps>) => import("react").JSX.Element;
|
|
27
|
+
export declare const ConsultationProvider: ({ children, token, region, theme, components, onError, disableSslPinning }: PropsWithChildren<ConsultationProviderProps>) => import("react").JSX.Element;
|
|
26
28
|
export {};
|
|
@@ -42,6 +42,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
42
42
|
exports.ConsultationProvider = exports.ConsultationContext = void 0;
|
|
43
43
|
var config_1 = require("../api/config");
|
|
44
44
|
var partner_1 = require("../api/partner");
|
|
45
|
+
var sslPinning_1 = require("../api/sslPinning");
|
|
45
46
|
var user_1 = require("../api/user");
|
|
46
47
|
var websocket_1 = require("../api/websocket");
|
|
47
48
|
var i18n_1 = __importDefault(require("../locale/i18n"));
|
|
@@ -49,6 +50,7 @@ var theme_1 = require("../types/theme");
|
|
|
49
50
|
var axios_1 = require("axios");
|
|
50
51
|
var react_1 = require("react");
|
|
51
52
|
var react_i18next_1 = require("react-i18next");
|
|
53
|
+
var react_native_ssl_public_key_pinning_1 = require("react-native-ssl-public-key-pinning");
|
|
52
54
|
var ThemeContext_1 = require("./ThemeContext");
|
|
53
55
|
// eslint-disable-next-line react-refresh/only-export-components
|
|
54
56
|
exports.ConsultationContext = (0, react_1.createContext)({
|
|
@@ -62,75 +64,87 @@ exports.ConsultationContext = (0, react_1.createContext)({
|
|
|
62
64
|
userId: '',
|
|
63
65
|
setUserId: function () { },
|
|
64
66
|
components: function () { return ({}); },
|
|
65
|
-
slug: null
|
|
67
|
+
slug: null,
|
|
68
|
+
initialised: false
|
|
66
69
|
});
|
|
67
70
|
var ConsultationProvider = function (_a) {
|
|
68
|
-
var children = _a.children, token = _a.token, region = _a.region, theme = _a.theme, components = _a.components, _b = _a.onError, onError = _b === void 0 ? function () { } : _b;
|
|
69
|
-
var
|
|
70
|
-
var
|
|
71
|
-
var
|
|
72
|
-
var
|
|
73
|
-
var
|
|
71
|
+
var children = _a.children, token = _a.token, region = _a.region, theme = _a.theme, components = _a.components, _b = _a.onError, onError = _b === void 0 ? function () { } : _b, _c = _a.disableSslPinning, disableSslPinning = _c === void 0 ? false : _c;
|
|
72
|
+
var _d = (0, react_1.useState)(null), consultation = _d[0], setConsultation = _d[1];
|
|
73
|
+
var _e = (0, react_1.useState)(null), userId = _e[0], setUserId = _e[1];
|
|
74
|
+
var _f = (0, react_1.useState)(null), user = _f[0], setUser = _f[1];
|
|
75
|
+
var _g = (0, react_1.useState)(null), websocket = _g[0], setWebsocket = _g[1];
|
|
76
|
+
var _h = (0, react_1.useState)(null), slug = _h[0], setSlug = _h[1];
|
|
77
|
+
var _j = (0, react_1.useState)(false), initialised = _j[0], setInitialised = _j[1];
|
|
74
78
|
var handleError = function (e) {
|
|
75
79
|
console.error('🚨 Error caught on handler', e);
|
|
76
80
|
onError(e);
|
|
77
81
|
};
|
|
78
82
|
var initialise = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
79
|
-
var partnerInfo,
|
|
83
|
+
var e_1, partnerInfo, e_2, userResponse, e_3, activeConsultation, e_4, ws, e_5;
|
|
80
84
|
return __generator(this, function (_a) {
|
|
81
85
|
switch (_a.label) {
|
|
82
86
|
case 0:
|
|
83
87
|
_a.trys.push([0, 2, , 3]);
|
|
84
|
-
return [4 /*yield*/, (0,
|
|
88
|
+
return [4 /*yield*/, (0, sslPinning_1.initializeSslPinning)(disableSslPinning)];
|
|
85
89
|
case 1:
|
|
86
|
-
|
|
87
|
-
setSlug(partnerInfo.slug);
|
|
90
|
+
_a.sent();
|
|
88
91
|
return [3 /*break*/, 3];
|
|
89
92
|
case 2:
|
|
90
93
|
e_1 = _a.sent();
|
|
91
|
-
console.error('Error
|
|
94
|
+
console.error('Error initializing SSL pinning', e_1);
|
|
92
95
|
throw e_1;
|
|
93
96
|
case 3:
|
|
94
97
|
_a.trys.push([3, 5, , 6]);
|
|
95
|
-
return [4 /*yield*/, (0,
|
|
98
|
+
return [4 /*yield*/, (0, partner_1.getPartnerInfo)()];
|
|
96
99
|
case 4:
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
partnerInfo = _a.sent();
|
|
101
|
+
setSlug(partnerInfo.slug);
|
|
99
102
|
return [3 /*break*/, 6];
|
|
100
103
|
case 5:
|
|
101
104
|
e_2 = _a.sent();
|
|
102
|
-
console.error('Error getting
|
|
105
|
+
console.error('Error getting partner info', e_2);
|
|
103
106
|
throw e_2;
|
|
104
107
|
case 6:
|
|
105
108
|
_a.trys.push([6, 8, , 9]);
|
|
106
|
-
return [4 /*yield*/, (0, user_1.
|
|
109
|
+
return [4 /*yield*/, (0, user_1.getUser)({ userId: userId })];
|
|
107
110
|
case 7:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
setConsultation(activeConsultation === null || activeConsultation === void 0 ? void 0 : activeConsultation.consultation);
|
|
111
|
+
userResponse = _a.sent();
|
|
112
|
+
setUser(userResponse);
|
|
111
113
|
return [3 /*break*/, 9];
|
|
112
114
|
case 8:
|
|
113
115
|
e_3 = _a.sent();
|
|
114
|
-
|
|
116
|
+
console.error('Error getting user', e_3);
|
|
117
|
+
throw e_3;
|
|
118
|
+
case 9:
|
|
119
|
+
_a.trys.push([9, 11, , 12]);
|
|
120
|
+
return [4 /*yield*/, (0, user_1.getActiveConsultation)({ userId: userId })];
|
|
121
|
+
case 10:
|
|
122
|
+
activeConsultation = _a.sent();
|
|
123
|
+
console.log('⏮️ Active:', activeConsultation.consultation);
|
|
124
|
+
setConsultation(activeConsultation === null || activeConsultation === void 0 ? void 0 : activeConsultation.consultation);
|
|
125
|
+
return [3 /*break*/, 12];
|
|
126
|
+
case 11:
|
|
127
|
+
e_4 = _a.sent();
|
|
128
|
+
if ((0, axios_1.isAxiosError)(e_4) && e_4.status === 404) {
|
|
115
129
|
setConsultation(null);
|
|
116
130
|
}
|
|
117
131
|
else {
|
|
118
|
-
console.error('Error getting active consultation',
|
|
119
|
-
throw
|
|
132
|
+
console.error('Error getting active consultation', e_4);
|
|
133
|
+
throw e_4;
|
|
120
134
|
}
|
|
121
|
-
return [3 /*break*/,
|
|
122
|
-
case
|
|
123
|
-
_a.trys.push([
|
|
135
|
+
return [3 /*break*/, 12];
|
|
136
|
+
case 12:
|
|
137
|
+
_a.trys.push([12, 14, , 15]);
|
|
124
138
|
return [4 /*yield*/, (0, websocket_1.connectWebsocket)({ token: token, userId: userId, region: region })];
|
|
125
|
-
case
|
|
139
|
+
case 13:
|
|
126
140
|
ws = _a.sent();
|
|
127
141
|
setWebsocket(ws);
|
|
128
|
-
return [3 /*break*/,
|
|
129
|
-
case
|
|
130
|
-
|
|
131
|
-
console.error('Error connecting to websocket',
|
|
132
|
-
throw
|
|
133
|
-
case
|
|
142
|
+
return [3 /*break*/, 15];
|
|
143
|
+
case 14:
|
|
144
|
+
e_5 = _a.sent();
|
|
145
|
+
console.error('Error connecting to websocket', e_5);
|
|
146
|
+
throw e_5;
|
|
147
|
+
case 15: return [2 /*return*/];
|
|
134
148
|
}
|
|
135
149
|
});
|
|
136
150
|
}); };
|
|
@@ -143,7 +157,8 @@ var ConsultationProvider = function (_a) {
|
|
|
143
157
|
var method = config.method, url = config.url, data = config.data;
|
|
144
158
|
console.log({
|
|
145
159
|
service: 'API Rest',
|
|
146
|
-
message: "".concat(method === null || method === void 0 ? void 0 : method.toUpperCase(), " ").concat(url, " ").concat(data !== undefined ? "- body: ".concat(JSON.stringify(data)) : ' ')
|
|
160
|
+
message: "".concat(method === null || method === void 0 ? void 0 : method.toUpperCase(), " ").concat(url, " ").concat(data !== undefined ? "- body: ".concat(JSON.stringify(data)) : ' '),
|
|
161
|
+
headers: config.headers
|
|
147
162
|
});
|
|
148
163
|
return config;
|
|
149
164
|
});
|
|
@@ -177,8 +192,10 @@ var ConsultationProvider = function (_a) {
|
|
|
177
192
|
setConsultation(data.consultation);
|
|
178
193
|
if (data.event === 'websocketError')
|
|
179
194
|
handleError(new Error('Websocket error'));
|
|
180
|
-
if (data.event === 'websocketConnected')
|
|
195
|
+
if (data.event === 'websocketConnected') {
|
|
181
196
|
console.log('🟢🟢 Websocket connected');
|
|
197
|
+
setInitialised(true);
|
|
198
|
+
}
|
|
182
199
|
};
|
|
183
200
|
websocket.onclose = function (e) {
|
|
184
201
|
console.log('❌ WS closed', JSON.stringify(e, null, 2));
|
|
@@ -186,6 +203,10 @@ var ConsultationProvider = function (_a) {
|
|
|
186
203
|
(0, websocket_1.connectWebsocket)({ token: token, userId: userId, region: region }).then(setWebsocket).catch(handleError);
|
|
187
204
|
};
|
|
188
205
|
}, [websocket]);
|
|
206
|
+
(0, react_1.useEffect)(function () {
|
|
207
|
+
var subscription = (0, react_native_ssl_public_key_pinning_1.addSslPinningErrorListener)(console.error);
|
|
208
|
+
return function () { return subscription.remove(); };
|
|
209
|
+
}, []);
|
|
189
210
|
var value = {
|
|
190
211
|
token: token,
|
|
191
212
|
region: region,
|
|
@@ -197,7 +218,8 @@ var ConsultationProvider = function (_a) {
|
|
|
197
218
|
onError: handleError,
|
|
198
219
|
user: user,
|
|
199
220
|
setUser: setUser,
|
|
200
|
-
slug: slug
|
|
221
|
+
slug: slug,
|
|
222
|
+
initialised: initialised
|
|
201
223
|
};
|
|
202
224
|
return (<exports.ConsultationContext.Provider value={value}>
|
|
203
225
|
<react_i18next_1.I18nextProvider i18n={i18n_1.default}>
|
|
@@ -3,6 +3,7 @@ import { ConsultationContextProps } from '../contexts/ConsultationContext';
|
|
|
3
3
|
import { CASE_TYPE, Consultation } from '../types/consultation';
|
|
4
4
|
interface UseConsultationProps {
|
|
5
5
|
consultation: ConsultationContextProps['consultation'];
|
|
6
|
+
initialised: ConsultationContextProps['initialised'];
|
|
6
7
|
updateConsultation: (_: Consultation) => void;
|
|
7
8
|
start: (caseType: CASE_TYPE, payload: CreateConsultationRequest) => Promise<Consultation>;
|
|
8
9
|
cancel: () => Promise<Consultation>;
|
|
@@ -50,7 +50,7 @@ var react_1 = require("react");
|
|
|
50
50
|
var useUser_1 = require("./useUser");
|
|
51
51
|
var useConsultation = function () {
|
|
52
52
|
var _a;
|
|
53
|
-
var _b = (0, react_1.useContext)(ConsultationContext_1.ConsultationContext), consultation = _b.consultation, setConsultation = _b.setConsultation, onError = _b.onError;
|
|
53
|
+
var _b = (0, react_1.useContext)(ConsultationContext_1.ConsultationContext), consultation = _b.consultation, setConsultation = _b.setConsultation, onError = _b.onError, initialised = _b.initialised;
|
|
54
54
|
var user = (0, useUser_1.useUser)().user;
|
|
55
55
|
var minLength = (0, react_1.useMemo)(function () {
|
|
56
56
|
switch (user === null || user === void 0 ? void 0 : user.language) {
|
|
@@ -176,7 +176,8 @@ var useConsultation = function () {
|
|
|
176
176
|
start: start,
|
|
177
177
|
cancel: cancel,
|
|
178
178
|
close: close,
|
|
179
|
-
rate: rate
|
|
179
|
+
rate: rate,
|
|
180
|
+
initialised: initialised
|
|
180
181
|
};
|
|
181
182
|
};
|
|
182
183
|
exports.useConsultation = useConsultation;
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.FormPrescription = void 0;
|
|
5
|
+
var ConsultationContainer_1 = require("../../common/components/ConsultationContainer");
|
|
5
6
|
var eventHandler_1 = require("../../common/helpers/eventHandler");
|
|
6
7
|
var useConsultation_1 = require("../../common/hooks/useConsultation");
|
|
7
8
|
var useUser_1 = require("../../common/hooks/useUser");
|
|
8
|
-
var utils_1 = require("../../common/screens/utils");
|
|
9
9
|
var NotValidActiveTypeScreen_1 = require("../../common/screens/NotValidActiveTypeScreen");
|
|
10
|
+
var utils_1 = require("../../common/screens/utils");
|
|
10
11
|
var consultation_1 = require("../../common/types/consultation");
|
|
11
12
|
var valid_active_type_1 = require("../../common/utils/valid-active-type");
|
|
12
13
|
var IndicationSurveyContext_1 = require("../contexts/IndicationSurveyContext");
|
|
@@ -55,12 +56,9 @@ var FormPrescription = function (_a) {
|
|
|
55
56
|
setUserId(userId);
|
|
56
57
|
}, [userId]);
|
|
57
58
|
return (<IndicationSurveyContext_1.IndicationSurveyProvider>
|
|
58
|
-
<
|
|
59
|
+
<ConsultationContainer_1.ConsultationContainer>
|
|
59
60
|
<ConsultationScreen />
|
|
60
|
-
</
|
|
61
|
+
</ConsultationContainer_1.ConsultationContainer>
|
|
61
62
|
</IndicationSurveyContext_1.IndicationSurveyProvider>);
|
|
62
63
|
};
|
|
63
64
|
exports.FormPrescription = FormPrescription;
|
|
64
|
-
var styles = react_native_1.StyleSheet.create({
|
|
65
|
-
container: { flex: 1 }
|
|
66
|
-
});
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TextConsultation = void 0;
|
|
4
|
+
var ConsultationContainer_1 = require("../../common/components/ConsultationContainer");
|
|
4
5
|
var eventHandler_1 = require("../../common/helpers/eventHandler");
|
|
5
6
|
var useConsultation_1 = require("../../common/hooks/useConsultation");
|
|
6
7
|
var useUser_1 = require("../../common/hooks/useUser");
|
|
7
|
-
var utils_1 = require("../../common/screens/utils");
|
|
8
8
|
var NoConsultationFoundScreen_1 = require("../../common/screens/NoConsultationFoundScreen");
|
|
9
9
|
var NotValidActiveTypeScreen_1 = require("../../common/screens/NotValidActiveTypeScreen");
|
|
10
|
+
var utils_1 = require("../../common/screens/utils");
|
|
10
11
|
var consultation_1 = require("../../common/types/consultation");
|
|
11
12
|
var valid_active_type_1 = require("../../common/utils/valid-active-type");
|
|
12
13
|
var HomeScreen_1 = require("../screens/HomeScreen");
|
|
13
14
|
var react_1 = require("react");
|
|
14
|
-
var react_native_1 = require("react-native");
|
|
15
15
|
var TextConsultation = function (_a) {
|
|
16
16
|
var eventHandlers = _a.eventHandlers, userId = _a.userId;
|
|
17
17
|
var consultation = (0, useConsultation_1.useConsultation)().consultation;
|
|
@@ -33,9 +33,6 @@ var TextConsultation = function (_a) {
|
|
|
33
33
|
return <NoConsultationFoundScreen_1.NoConsultationFoundScreen />;
|
|
34
34
|
return <HomeScreen_1.HomeScreen />;
|
|
35
35
|
}, [consultation]);
|
|
36
|
-
return <
|
|
36
|
+
return <ConsultationContainer_1.ConsultationContainer>{getConsultationScreen(consultation)}</ConsultationContainer_1.ConsultationContainer>;
|
|
37
37
|
};
|
|
38
38
|
exports.TextConsultation = TextConsultation;
|
|
39
|
-
var styles = react_native_1.StyleSheet.create({
|
|
40
|
-
container: { flex: 1 }
|
|
41
|
-
});
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.VideoConsultation = void 0;
|
|
4
|
+
var ConsultationContainer_1 = require("../../common/components/ConsultationContainer");
|
|
4
5
|
var eventHandler_1 = require("../../common/helpers/eventHandler");
|
|
5
6
|
var useConsultation_1 = require("../../common/hooks/useConsultation");
|
|
6
7
|
var useUser_1 = require("../../common/hooks/useUser");
|
|
7
|
-
var utils_1 = require("../../common/screens/utils");
|
|
8
8
|
var NoConsultationFoundScreen_1 = require("../../common/screens/NoConsultationFoundScreen");
|
|
9
9
|
var NotValidActiveTypeScreen_1 = require("../../common/screens/NotValidActiveTypeScreen");
|
|
10
10
|
var PreparingSummaryScreen_1 = require("../../common/screens/PreparingSummaryScreen");
|
|
11
|
+
var utils_1 = require("../../common/screens/utils");
|
|
11
12
|
var consultation_1 = require("../../common/types/consultation");
|
|
12
13
|
var valid_active_type_1 = require("../../common/utils/valid-active-type");
|
|
13
14
|
var DeliveryAddressScreen_1 = require("../screens/DeliveryAddressScreen");
|
|
@@ -49,9 +50,6 @@ var VideoConsultation = function (_a) {
|
|
|
49
50
|
throw new Error("Screen not found ".concat(status));
|
|
50
51
|
}
|
|
51
52
|
}, [consultation]);
|
|
52
|
-
return <
|
|
53
|
+
return <ConsultationContainer_1.ConsultationContainer>{getConsultationScreen(consultation)}</ConsultationContainer_1.ConsultationContainer>;
|
|
53
54
|
};
|
|
54
55
|
exports.VideoConsultation = VideoConsultation;
|
|
55
|
-
var styles = react_native_1.StyleSheet.create({
|
|
56
|
-
container: { flex: 1 }
|
|
57
|
-
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abihealth/goapp-react-native",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -15,26 +15,27 @@
|
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"axios": "
|
|
19
|
-
"i18next": "
|
|
20
|
-
"phone": "
|
|
21
|
-
"react-i18next": "
|
|
22
|
-
"react-native-agora": "
|
|
23
|
-
"react-native-bouncy-checkbox": "
|
|
18
|
+
"axios": "1.7.9",
|
|
19
|
+
"i18next": "23.16.8",
|
|
20
|
+
"phone": "3.1.58",
|
|
21
|
+
"react-i18next": "14.1.3",
|
|
22
|
+
"react-native-agora": "4.5.2",
|
|
23
|
+
"react-native-bouncy-checkbox": "4.1.2",
|
|
24
24
|
"react-native-date-picker": "5.0.1",
|
|
25
|
-
"react-native-phone-input": "
|
|
25
|
+
"react-native-phone-input": "1.3.7",
|
|
26
26
|
"react-native-svg": "^15.11.1",
|
|
27
|
-
"
|
|
27
|
+
"react-native-ssl-public-key-pinning": "^1.2.5",
|
|
28
|
+
"zod": "3.24.1"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@abiglobalhealth/ts-config": "1.3.0",
|
|
31
|
-
"@tsconfig/react-native": "
|
|
32
|
-
"@types/jest": "
|
|
33
|
-
"@types/react": "
|
|
34
|
-
"@types/react-native": "
|
|
35
|
-
"concurrently": "
|
|
36
|
-
"tsc-alias": "
|
|
37
|
-
"typescript": "
|
|
32
|
+
"@tsconfig/react-native": "3.0.5",
|
|
33
|
+
"@types/jest": "29.5.12",
|
|
34
|
+
"@types/react": "18.3.12",
|
|
35
|
+
"@types/react-native": "0.73.0",
|
|
36
|
+
"concurrently": "9.1.2",
|
|
37
|
+
"tsc-alias": "1.8.10",
|
|
38
|
+
"typescript": "5.7.3"
|
|
38
39
|
},
|
|
39
40
|
"peerDependencies": {
|
|
40
41
|
"react": ">=18.0.0",
|