@shamilovtim/react-native-nitro-sse 2.3.0 → 2.3.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.
- package/README.md +91 -83
- package/ios/NitroSse.swift +51 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrosse/SseConfig.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrosse/SseEvent.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrosse/SseMockConfig.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrosse/SseMockEvent.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrosse/SseStats.kt +1 -1
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# react-native-nitro-sse
|
|
2
2
|
|
|
3
|
-
High-performance Server-Sent Events (SSE) client for React Native, built on top of **Nitro Modules (JSI)**. Designed for mission-critical
|
|
3
|
+
High-performance Server-Sent Events (SSE) client for React Native, built on top of **Nitro Modules (JSI)**. Designed for mission-critical apps requiring high-throughput streaming, battery optimization, and extreme stability.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Why NitroSSE?
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Traditional EventSource libraries run on the JS thread or use the legacy React Native Bridge. NitroSSE moves the entire control logic down to the native layer:
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- **🛠️ Full Protocol Support**: Comprehensive support for GET/POST methods and dynamic header updates.
|
|
11
|
+
* **Zero-Latency JSI**: Instantaneous JS-Native communication bypassing the async bridge.
|
|
12
|
+
* **Advanced Backpressure**: Batches high-frequency events and employs tail-drop strategies to keep UI thread fluid under extreme load.
|
|
13
|
+
* **Intelligent Reconnect**: Automatic recovery using **Exponential Backoff** and **Jitter** to prevent server stampedes.
|
|
14
|
+
* **Lifecycles**: Auto-hibernates connections in background and resumes on foreground to preserve battery.
|
|
15
|
+
* **Heartbeat Watchdog**: Native detection of keep-alive/ping comments to auto-reconnect dead sockets.
|
|
16
|
+
* **RN DevTools Integration**: Plug-and-play network tracing in **React Native 0.83+ DevTools** (monitor streams directly).
|
|
17
|
+
* **Local Mocking Engine**: Simulates streams, connection drops, and delays entirely in JS without backend setup.
|
|
17
18
|
|
|
18
19
|
---
|
|
19
20
|
|
|
20
|
-
##
|
|
21
|
+
## Installation
|
|
21
22
|
|
|
22
23
|
```sh
|
|
23
24
|
yarn add @shamilovtim/react-native-nitro-sse react-native-nitro-modules
|
|
@@ -25,15 +26,18 @@ yarn add @shamilovtim/react-native-nitro-sse react-native-nitro-modules
|
|
|
25
26
|
npm install @shamilovtim/react-native-nitro-sse react-native-nitro-modules
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
>
|
|
29
|
+
> [!NOTE]
|
|
30
|
+
> `react-native-nitro-modules` is a peer dependency and must be installed in the host project.
|
|
29
31
|
|
|
30
32
|
---
|
|
31
33
|
|
|
32
|
-
##
|
|
34
|
+
## Compatibility
|
|
33
35
|
|
|
34
36
|
| react-native-nitro-sse | react-native-nitro-modules |
|
|
35
37
|
| :--------------------- | :------------------------- |
|
|
36
|
-
| **2.
|
|
38
|
+
| **2.3.1 - latest** | **0.35.9** |
|
|
39
|
+
| **2.3.0** | **0.35.6** |
|
|
40
|
+
| **2.2.0 - 2.2.3** | **0.35.4** |
|
|
37
41
|
| **2.0.0 - 2.1.1** | **0.35.2** |
|
|
38
42
|
| **1.6.2** | **0.35.2** |
|
|
39
43
|
| **1.4.0 - 1.6.1** | **0.35.0** |
|
|
@@ -42,103 +46,107 @@ npm install @shamilovtim/react-native-nitro-sse react-native-nitro-modules
|
|
|
42
46
|
| **1.1.0** | **0.33.9** |
|
|
43
47
|
| **1.0.0** | **0.33.8** |
|
|
44
48
|
|
|
45
|
-
|
|
46
49
|
---
|
|
47
50
|
|
|
48
|
-
##
|
|
49
|
-
|
|
50
|
-
### 1. Basic Initialization
|
|
51
|
-
|
|
52
|
-
Initialize the module with your endpoint configuration and an event listener.
|
|
51
|
+
## Usage
|
|
53
52
|
|
|
54
53
|
```tsx
|
|
55
54
|
import { createNitroSse } from '@shamilovtim/react-native-nitro-sse';
|
|
56
55
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
nitroSse.setup(
|
|
60
|
-
{
|
|
61
|
-
url: 'https://api.yourserver.com/stream',
|
|
62
|
-
method: 'get',
|
|
63
|
-
headers: {
|
|
64
|
-
'Authorization': 'Bearer active-token',
|
|
65
|
-
},
|
|
66
|
-
// Batch messages every 100ms to optimize UI rendering
|
|
67
|
-
batchingIntervalMs: 100,
|
|
68
|
-
// Maximum of 1000 messages in the native queue before forced flush
|
|
69
|
-
maxBufferSize: 1000,
|
|
70
|
-
// Optional: Auto-refresh tokens or dynamic headers
|
|
71
|
-
onBeforeRequest: async () => {
|
|
72
|
-
const token = await fetchNewToken();
|
|
73
|
-
return { 'Authorization': `Bearer ${token}` };
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
(events) => {
|
|
77
|
-
// events is an array of SseEvent objects
|
|
78
|
-
events.forEach((event) => {
|
|
79
|
-
console.log('Received:', event);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
);
|
|
56
|
+
const sse = createNitroSse();
|
|
83
57
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
58
|
+
sse.setup({
|
|
59
|
+
url: 'https://api.example.com/stream',
|
|
60
|
+
headers: { 'Authorization': 'Bearer TOKEN' }
|
|
61
|
+
});
|
|
87
62
|
|
|
88
|
-
|
|
63
|
+
// Listen to events
|
|
64
|
+
sse.addEventListener('message', (e) => console.log('Received:', e.data));
|
|
65
|
+
sse.addEventListener('error', (e) => console.error('Error:', e.message));
|
|
89
66
|
|
|
90
|
-
|
|
67
|
+
// Start streaming
|
|
68
|
+
sse.start();
|
|
91
69
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
console.log(`Downloaded: ${stats.totalBytesReceived / 1024} KB`);
|
|
95
|
-
console.log(`Reconnections: ${stats.reconnectCount}`);
|
|
70
|
+
// Cleanup when done
|
|
71
|
+
// sse.stop();
|
|
96
72
|
```
|
|
97
73
|
|
|
98
74
|
---
|
|
99
75
|
|
|
100
|
-
##
|
|
76
|
+
## Configuration Reference (`SseConfig`)
|
|
101
77
|
|
|
102
78
|
| Parameter | Type | Default | Description |
|
|
103
79
|
| :--- | :--- | :--- | :--- |
|
|
104
|
-
| `url` | `string` |
|
|
105
|
-
| `method` | `'get' \| 'post'` | `get` | HTTP method. |
|
|
106
|
-
| `headers` | `Record<string, string>` | `{}` | Custom
|
|
107
|
-
| `body` | `string` |
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
80
|
+
| `url` | `string` | — | **Required**. SSE endpoint target. |
|
|
81
|
+
| `method` | `'get' \| 'post'` | `'get'` | HTTP method. |
|
|
82
|
+
| `headers` | `Record<string, string>` | `{}` | Custom request headers. |
|
|
83
|
+
| `body` | `string` | — | Payload sent during POST requests. |
|
|
84
|
+
| `backgroundExecution` | `boolean` | `false` | (iOS) Keep background execution active when app is minimized. |
|
|
85
|
+
| `batchingIntervalMs` | `number` | `0` | Batch window (ms). `0` sends events instantly. |
|
|
86
|
+
| `maxBufferSize` | `number` | `1000` | Native memory safety threshold. |
|
|
87
|
+
| `connectionTimeoutMs`| `number` | `15000` | Handshake connect timeout threshold. |
|
|
88
|
+
| `readTimeoutMs` | `number` | `300000`| Socket inactivity limit triggers reconnect. |
|
|
89
|
+
| `retryIntervalMs` | `number` | `1000` | Backoff base delay (ms) for reconnect. |
|
|
90
|
+
| `maxRetryIntervalMs` | `number` | `30000` | Cap on backoff reconnect delay (ms). |
|
|
91
|
+
| `jitterFactor` | `number` | `0.5` | Randomization spread ratio (`0.0` to `1.0`). |
|
|
92
|
+
| `maxReconnectAttempts`| `number` | `-1` | Limit reconnections. `-1` = infinite. `0` = disabled. |
|
|
93
|
+
| `autoParseJSON` | `boolean` | `false` | Parses event `data` on native thread; outputs to `parsedData`. |
|
|
94
|
+
| `monitorNetwork` | `boolean` | `true` | Pauses/resumes connection on WiFi <-> Cell or link changes. |
|
|
95
|
+
| `onBeforeRequest` | `() => Promise<Record<string, string>>` | — | Async hook running immediately before every request. |
|
|
96
|
+
| `mock` | `SseMockConfig` | — | Injected mock stream settings (Dev environment only). |
|
|
116
97
|
|
|
117
98
|
---
|
|
118
99
|
|
|
119
|
-
##
|
|
100
|
+
## Mocking & Testing System (`v2.3.0+`)
|
|
120
101
|
|
|
121
|
-
|
|
122
|
-
- **Promise Safety**: The `onBeforeRequest` interceptor is wrapped in a native fallback timeout. Even if your JS token refresh hangs indefinitely, the native state machine will recover and retry safely.
|
|
123
|
-
- **Zero-Ghost Reloads**: Seamlessly handles React Native Hot Reloads. The native layer detects when the JS environment is being destroyed and synchronously kills active sockets to prevent duplicate connections.
|
|
124
|
-
- **Cumulative Logic**: Statistics (`totalBytesReceived`) are preserved across reconnections, giving you a true 360-degree view of the session's data usage.
|
|
102
|
+
NitroSSE includes a built-in mock streaming engine to test application responses without running live endpoints. Mocks are automatically disabled in production configurations.
|
|
125
103
|
|
|
126
|
-
|
|
104
|
+
### Configuration (`SseMockConfig`)
|
|
127
105
|
|
|
128
|
-
|
|
106
|
+
```tsx
|
|
107
|
+
sse.setup({
|
|
108
|
+
url: 'https://api.mocked-endpoint.com/stream',
|
|
109
|
+
mock: {
|
|
110
|
+
mode: 'replace', // 'replace' = Pure JS local simulation; 'inject' = Server + injected events
|
|
111
|
+
eventsPerSecond: 2,
|
|
112
|
+
loop: true,
|
|
113
|
+
errorRate: 0.1, // 10% chance to simulate connection drops and trigger reconnects
|
|
114
|
+
data: [
|
|
115
|
+
{ type: 'open', statusCode: 200 },
|
|
116
|
+
{ type: 'message', data: 'Initial greeting' },
|
|
117
|
+
{ event: 'user-updated', data: '{"id":123,"status":"online"}', delayMs: 1500 },
|
|
118
|
+
{ type: 'message', data: 'Periodic heartbeat comments' },
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Manual Injector
|
|
125
|
+
Inject custom testing events programmatically at runtime to mock specific app situations:
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
sse.injectMockEvent({
|
|
129
|
+
type: 'message',
|
|
130
|
+
event: 'alert',
|
|
131
|
+
data: 'System maintenance warning!'
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
129
136
|
|
|
130
|
-
|
|
137
|
+
## Advanced Operations
|
|
131
138
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
* **`updateHeaders(headers)`**: Change request headers (e.g., updating expired authentication tokens) without closing and opening the connection manually.
|
|
140
|
+
* **`setLastProcessedId(id)`**: Update the native parser's last processed event ID. Native uses this ID as the `Last-Event-ID` header on next reconnection.
|
|
141
|
+
* **`restart()`**: Immediately tears down the current network socket and initializes fresh handshake sequence.
|
|
142
|
+
* **`flush()`**: Explicitly forces dispatch of currently buffered events, ignoring `batchingIntervalMs`.
|
|
135
143
|
|
|
136
144
|
---
|
|
137
145
|
|
|
138
|
-
##
|
|
146
|
+
## License
|
|
139
147
|
|
|
140
148
|
MIT
|
|
141
149
|
|
|
142
150
|
---
|
|
143
151
|
|
|
144
|
-
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
152
|
+
*Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)*
|
package/ios/NitroSse.swift
CHANGED
|
@@ -60,6 +60,7 @@ class NitroSse: HybridNitroSseSpec {
|
|
|
60
60
|
private var connectionAttemptVersion: Int = 0
|
|
61
61
|
#if os(iOS)
|
|
62
62
|
private var backgroundTaskIdentifier: UIBackgroundTaskIdentifier = .invalid
|
|
63
|
+
private var isBackgroundTaskActive: Bool = false
|
|
63
64
|
#endif
|
|
64
65
|
private var wasRunningBeforeHibernation: Bool = false
|
|
65
66
|
private var isAppInBackground: Bool = false
|
|
@@ -174,12 +175,29 @@ class NitroSse: HybridNitroSseSpec {
|
|
|
174
175
|
if config.backgroundExecution == true {
|
|
175
176
|
print("[NitroSse] App backgrounded. backgroundExecution is true, keeping connection alive.")
|
|
176
177
|
#if os(iOS)
|
|
177
|
-
// Start a background task to tell the OS we want to keep running
|
|
178
178
|
self.cleanupBackgroundTask()
|
|
179
|
-
self.
|
|
179
|
+
self.isBackgroundTaskActive = true
|
|
180
|
+
|
|
181
|
+
DispatchQueue.main.async { [weak self] in
|
|
182
|
+
let taskId = UIApplication.shared.beginBackgroundTask(withName: "NitroSse-KeepAlive") {
|
|
183
|
+
self?.sseQueue.async {
|
|
184
|
+
print("[NitroSse] Background task expired. Hibernating now.")
|
|
185
|
+
self?.hibernateConnection()
|
|
186
|
+
}
|
|
187
|
+
}
|
|
180
188
|
self?.sseQueue.async {
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
if self?.isBackgroundTaskActive == true {
|
|
190
|
+
if let oldTaskId = self?.backgroundTaskIdentifier, oldTaskId != .invalid {
|
|
191
|
+
DispatchQueue.main.async {
|
|
192
|
+
UIApplication.shared.endBackgroundTask(oldTaskId)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
self?.backgroundTaskIdentifier = taskId
|
|
196
|
+
} else {
|
|
197
|
+
DispatchQueue.main.async {
|
|
198
|
+
UIApplication.shared.endBackgroundTask(taskId)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
183
201
|
}
|
|
184
202
|
}
|
|
185
203
|
#endif
|
|
@@ -225,9 +243,13 @@ class NitroSse: HybridNitroSseSpec {
|
|
|
225
243
|
private func cleanupBackgroundTask() {
|
|
226
244
|
dispatchPrecondition(condition: .onQueue(sseQueue))
|
|
227
245
|
#if os(iOS)
|
|
228
|
-
|
|
229
|
-
|
|
246
|
+
self.isBackgroundTaskActive = false
|
|
247
|
+
let taskId = self.backgroundTaskIdentifier
|
|
248
|
+
if taskId != .invalid {
|
|
230
249
|
self.backgroundTaskIdentifier = .invalid
|
|
250
|
+
DispatchQueue.main.async {
|
|
251
|
+
UIApplication.shared.endBackgroundTask(taskId)
|
|
252
|
+
}
|
|
231
253
|
}
|
|
232
254
|
#endif
|
|
233
255
|
}
|
|
@@ -646,6 +668,15 @@ class NitroSse: HybridNitroSseSpec {
|
|
|
646
668
|
parent.backoffCounter = 0
|
|
647
669
|
parent.currentReconnectAttempts = 0
|
|
648
670
|
parent.consecutiveAuthErrors = 0
|
|
671
|
+
|
|
672
|
+
NitroSseNetworkInspector.reportResponseStart(
|
|
673
|
+
parent.requestId,
|
|
674
|
+
url: parent.config?.url,
|
|
675
|
+
response: nil,
|
|
676
|
+
statusCode: 200,
|
|
677
|
+
headers: parent.config?.headers ?? [:]
|
|
678
|
+
)
|
|
679
|
+
|
|
649
680
|
parent.pushEventToBuffer(SseEvent(type: .open, data: nil, parsedData: nil, id: nil, event: nil, message: nil, statusCode: 200, retry: nil))
|
|
650
681
|
}
|
|
651
682
|
}
|
|
@@ -695,13 +726,26 @@ class NitroSse: HybridNitroSseSpec {
|
|
|
695
726
|
guard let parent = self.parent, source === parent.eventSource else { return }
|
|
696
727
|
parent.sseQueue.async { [weak parent] in
|
|
697
728
|
guard let parent = parent, parent.isRunning, self.attemptVersion == parent.connectionAttemptVersion else { return }
|
|
729
|
+
|
|
698
730
|
let nsError = error as NSError
|
|
699
|
-
|
|
731
|
+
var statusCode = nsError.code
|
|
732
|
+
if let responseError = error as? UnsuccessfulResponseError {
|
|
733
|
+
statusCode = responseError.responseCode
|
|
734
|
+
}
|
|
700
735
|
|
|
701
736
|
parent.reconnectCount += 1
|
|
702
737
|
parent.lastErrorTime = Date().timeIntervalSince1970 * 1000
|
|
703
738
|
parent.lastErrorCode = "\(nsError.domain)(\(statusCode))"
|
|
704
739
|
|
|
740
|
+
if statusCode >= 100 && statusCode < 600 {
|
|
741
|
+
NitroSseNetworkInspector.reportResponseStart(
|
|
742
|
+
parent.requestId,
|
|
743
|
+
url: parent.config?.url,
|
|
744
|
+
response: nil,
|
|
745
|
+
statusCode: statusCode,
|
|
746
|
+
headers: [:]
|
|
747
|
+
)
|
|
748
|
+
}
|
|
705
749
|
NitroSseNetworkInspector.reportRequestFailed(parent.requestId, cancelled: false)
|
|
706
750
|
parent.requestId = nil
|
|
707
751
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shamilovtim/react-native-nitro-sse",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "High-performance Server-Sent Events (SSE) for React Native, powered by Nitro Modules.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -43,8 +43,9 @@
|
|
|
43
43
|
"typecheck": "tsc",
|
|
44
44
|
"test": "jest",
|
|
45
45
|
"test:android": "cd example/android && ./gradlew :react-native-nitro-sse:testDebugUnitTest",
|
|
46
|
-
"test:ios": "cd example/ios && xcodebuild test -workspace NitroSseExample.xcworkspace -scheme NitroSse -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone
|
|
46
|
+
"test:ios": "cd example/ios && xcodebuild test -workspace NitroSseExample.xcworkspace -scheme NitroSse -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 16e'",
|
|
47
47
|
"test:native": "yarn test:android && yarn test:ios",
|
|
48
|
+
"ci": "yarn lint && yarn typecheck && yarn test && yarn prepare && yarn test:native && yarn turbo run build:android build:ios",
|
|
48
49
|
"release": "release-it --only-version",
|
|
49
50
|
"server": "node example/sse-server.js",
|
|
50
51
|
"lint": "eslint \"**/*.{js,ts,tsx}\""
|
|
@@ -78,8 +79,9 @@
|
|
|
78
79
|
"@eslint/compat": "^1.3.2",
|
|
79
80
|
"@eslint/eslintrc": "^3.3.1",
|
|
80
81
|
"@eslint/js": "^9.35.0",
|
|
81
|
-
"@react-native/babel-preset": "0.
|
|
82
|
-
"@react-native/eslint-config": "0.
|
|
82
|
+
"@react-native/babel-preset": "0.85.3",
|
|
83
|
+
"@react-native/eslint-config": "0.85.3",
|
|
84
|
+
"@react-native/jest-preset": "0.85.3",
|
|
83
85
|
"@release-it/conventional-changelog": "^10.0.1",
|
|
84
86
|
"@types/jest": "^29.5.14",
|
|
85
87
|
"@types/react": "^19.2.0",
|
|
@@ -90,12 +92,12 @@
|
|
|
90
92
|
"eslint-plugin-prettier": "^5.5.4",
|
|
91
93
|
"jest": "^29.7.0",
|
|
92
94
|
"lefthook": "^2.0.3",
|
|
93
|
-
"nitrogen": "0.35.
|
|
95
|
+
"nitrogen": "0.35.9",
|
|
94
96
|
"prettier": "^2.8.8",
|
|
95
|
-
"react": "19.2.
|
|
96
|
-
"react-native": "0.
|
|
97
|
+
"react": "19.2.3",
|
|
98
|
+
"react-native": "0.85.3",
|
|
97
99
|
"react-native-builder-bob": "^0.40.17",
|
|
98
|
-
"react-native-nitro-modules": "0.35.
|
|
100
|
+
"react-native-nitro-modules": "0.35.9",
|
|
99
101
|
"release-it": "^19.0.4",
|
|
100
102
|
"turbo": "^2.5.6",
|
|
101
103
|
"typescript": "^5.9.2"
|
|
@@ -103,7 +105,7 @@
|
|
|
103
105
|
"peerDependencies": {
|
|
104
106
|
"react": "*",
|
|
105
107
|
"react-native": "*",
|
|
106
|
-
"react-native-nitro-modules": ">= 0.35.
|
|
108
|
+
"react-native-nitro-modules": ">= 0.35.9"
|
|
107
109
|
},
|
|
108
110
|
"workspaces": [
|
|
109
111
|
"example"
|
|
@@ -135,7 +137,7 @@
|
|
|
135
137
|
]
|
|
136
138
|
},
|
|
137
139
|
"jest": {
|
|
138
|
-
"preset": "react-native",
|
|
140
|
+
"preset": "@react-native/jest-preset",
|
|
139
141
|
"modulePathIgnorePatterns": [
|
|
140
142
|
"<rootDir>/example/node_modules",
|
|
141
143
|
"<rootDir>/lib/"
|