relay-ota-react-native 0.1.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 +376 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +16 -0
- package/dist/client.js.map +1 -0
- package/dist/downloader.d.ts +6 -0
- package/dist/downloader.d.ts.map +1 -0
- package/dist/downloader.js +65 -0
- package/dist/downloader.js.map +1 -0
- package/dist/filesystem.d.ts +4 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +63 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/hooks.d.ts +15 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +34 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/installer.d.ts +6 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +46 -0
- package/dist/installer.js.map +1 -0
- package/dist/provider.d.ts +18 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +82 -0
- package/dist/provider.js.map +1 -0
- package/dist/storage.d.ts +12 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +44 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/updater.d.ts +17 -0
- package/dist/updater.d.ts.map +1 -0
- package/dist/updater.js +98 -0
- package/dist/updater.js.map +1 -0
- package/package.json +60 -0
- package/src/client.ts +19 -0
- package/src/downloader.ts +79 -0
- package/src/filesystem.ts +62 -0
- package/src/hooks.ts +46 -0
- package/src/index.ts +21 -0
- package/src/installer.ts +42 -0
- package/src/native/OtaBundleUpdater.h +5 -0
- package/src/native/OtaBundleUpdater.m +56 -0
- package/src/native/OtaBundleUpdaterModule.kt +73 -0
- package/src/native/OtaBundleUpdaterPackage.kt +14 -0
- package/src/provider.tsx +77 -0
- package/src/storage.ts +42 -0
- package/src/types.ts +68 -0
- package/src/updater.ts +115 -0
package/README.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# relay-ota-react-native
|
|
2
|
+
|
|
3
|
+
**Over-the-air updates for React Native — ship JS bundle changes instantly, without App Store review.**
|
|
4
|
+
|
|
5
|
+
Open-source drop-in replacement for the retired Microsoft CodePush and a self-hosted alternative to Expo EAS Updates.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/relay-ota-react-native)
|
|
8
|
+
[](https://www.npmjs.com/package/relay-ota-react-native)
|
|
9
|
+
[](https://github.com/aglaonematech/relay-ota-react-native/blob/main/LICENSE)
|
|
10
|
+
[](https://github.com/aglaonematech/relay-ota-react-native)
|
|
11
|
+
|
|
12
|
+
**Website:** [relayota.com](https://relayota.com) · **Docs:** [relayota.com/docs](https://relayota.com/docs) · **GitHub:** [aglaonematech/relay-ota-react-native](https://github.com/aglaonematech/relay-ota-react-native)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## What is Relay OTA?
|
|
17
|
+
|
|
18
|
+
Relay OTA lets you push JavaScript bundle updates directly to your users' devices — no App Store or Play Store review needed. It's a fully open-source, self-hosted platform: you own the server, you own the data, and you pay nothing.
|
|
19
|
+
|
|
20
|
+
- **Zero review wait** — critical fixes reach users in seconds
|
|
21
|
+
- **One-click rollback** — bad update? revert instantly from the dashboard
|
|
22
|
+
- **Channels** — separate `production` and `staging` environments
|
|
23
|
+
- **Staged rollouts** — release to a percentage of users before going 100%
|
|
24
|
+
- **Mandatory updates** — auto-apply security patches without user interaction
|
|
25
|
+
- **Analytics** — track check, download, and apply rates per release
|
|
26
|
+
|
|
27
|
+
Works with **Expo managed workflow** and **bare React Native** (0.72+).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install relay-ota-react-native @react-native-async-storage/async-storage
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Expo projects
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
npx expo install expo-file-system
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Bare React Native projects
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm install react-native-fs
|
|
47
|
+
cd ios && pod install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Quick start — Expo
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { OtaProvider, useOtaUpdate, createExpoFileSystemAdapter } from 'relay-ota-react-native';
|
|
56
|
+
|
|
57
|
+
const fs = createExpoFileSystemAdapter();
|
|
58
|
+
|
|
59
|
+
export default function App() {
|
|
60
|
+
return (
|
|
61
|
+
<OtaProvider
|
|
62
|
+
fileSystem={fs}
|
|
63
|
+
config={{
|
|
64
|
+
serverUrl: 'https://ota.yourcompany.com', // your self-hosted server
|
|
65
|
+
appId: 'YOUR_APP_ID',
|
|
66
|
+
channel: 'production',
|
|
67
|
+
platform: 'IOS', // or 'ANDROID'
|
|
68
|
+
currentVersion: '1.0.0',
|
|
69
|
+
runtimeVersion: '1.0.0',
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
<YourNavigator />
|
|
73
|
+
</OtaProvider>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Show an update prompt anywhere in your app:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { useOtaUpdate } from 'relay-ota-react-native';
|
|
82
|
+
import { View, Text, Button } from 'react-native';
|
|
83
|
+
|
|
84
|
+
export function UpdateBanner() {
|
|
85
|
+
const { hasUpdate, isReady, isLoading, progress, downloadUpdate, applyUpdate } = useOtaUpdate();
|
|
86
|
+
|
|
87
|
+
if (hasUpdate) return (
|
|
88
|
+
<View>
|
|
89
|
+
<Text>New version available</Text>
|
|
90
|
+
<Button title="Download" onPress={downloadUpdate} />
|
|
91
|
+
</View>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (isLoading) return <Text>Downloading… {Math.round(progress * 100)}%</Text>;
|
|
95
|
+
|
|
96
|
+
if (isReady) return (
|
|
97
|
+
<View>
|
|
98
|
+
<Text>Update ready</Text>
|
|
99
|
+
<Button title="Restart now" onPress={applyUpdate} />
|
|
100
|
+
</View>
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Quick start — Bare React Native
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import { OtaProvider, createRNFSFileSystemAdapter } from 'relay-ota-react-native';
|
|
113
|
+
|
|
114
|
+
const fs = createRNFSFileSystemAdapter();
|
|
115
|
+
|
|
116
|
+
export default function App() {
|
|
117
|
+
return (
|
|
118
|
+
<OtaProvider
|
|
119
|
+
fileSystem={fs}
|
|
120
|
+
config={{
|
|
121
|
+
serverUrl: 'https://ota.yourcompany.com',
|
|
122
|
+
appId: 'YOUR_APP_ID',
|
|
123
|
+
channel: 'production',
|
|
124
|
+
platform: 'ANDROID',
|
|
125
|
+
currentVersion: '1.0.0',
|
|
126
|
+
runtimeVersion: '1.0.0',
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<YourNavigator />
|
|
130
|
+
</OtaProvider>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Bare React Native requires the `OtaBundleUpdater` native module — see [Native module setup](#native-module-setup) below.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Self-hosting the server
|
|
140
|
+
|
|
141
|
+
This SDK connects to a **Relay OTA server** you run yourself. Getting the server up takes about 5 minutes:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
git clone https://github.com/aglaonematech/relay-ota.git
|
|
145
|
+
cd relay-ota
|
|
146
|
+
docker compose up -d # starts Postgres, Redis, MinIO
|
|
147
|
+
npm install
|
|
148
|
+
npm run dev
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Full setup guide → [relayota.com/docs](https://relayota.com/docs)
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## OtaProvider config
|
|
156
|
+
|
|
157
|
+
| Prop | Type | Required | Description |
|
|
158
|
+
|------|------|----------|-------------|
|
|
159
|
+
| `serverUrl` | `string` | ✅ | Base URL of your OTA server |
|
|
160
|
+
| `appId` | `string` | ✅ | App ID from the OTA dashboard |
|
|
161
|
+
| `channel` | `string` | ✅ | Release channel — e.g. `'production'`, `'staging'` |
|
|
162
|
+
| `platform` | `'IOS' \| 'ANDROID'` | ✅ | Target platform |
|
|
163
|
+
| `currentVersion` | `string` | ✅ | Current JS bundle version |
|
|
164
|
+
| `runtimeVersion` | `string` | ✅ | Native runtime version — must match the release |
|
|
165
|
+
| `checkOnForeground` | `boolean` | — | Auto-check when app returns to foreground (default: `true`) |
|
|
166
|
+
| `onUpdate` | `(release) => void` | — | Called when a new update is found |
|
|
167
|
+
| `onError` | `(error: Error) => void` | — | Called on check/download errors |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Hooks
|
|
172
|
+
|
|
173
|
+
### `useOtaUpdate`
|
|
174
|
+
|
|
175
|
+
Full update state and actions:
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
const {
|
|
179
|
+
status, // UpdateStatus
|
|
180
|
+
progress, // number 0–100 during download
|
|
181
|
+
release, // release metadata or null
|
|
182
|
+
error, // Error | null
|
|
183
|
+
localBundlePath, // path to downloaded bundle or null
|
|
184
|
+
|
|
185
|
+
isLoading, // checking or downloading
|
|
186
|
+
hasUpdate, // status === 'update_available'
|
|
187
|
+
isReady, // status === 'ready'
|
|
188
|
+
|
|
189
|
+
checkForUpdates, // () => Promise<void>
|
|
190
|
+
downloadUpdate, // () => Promise<void>
|
|
191
|
+
applyUpdate, // () => Promise<void> — reloads the app
|
|
192
|
+
rollback, // () => Promise<void> — removes staged bundle, reloads
|
|
193
|
+
} = useOtaUpdate();
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**`UpdateStatus` values**
|
|
197
|
+
|
|
198
|
+
| Status | Meaning |
|
|
199
|
+
|--------|---------|
|
|
200
|
+
| `idle` | No check has run yet |
|
|
201
|
+
| `checking` | Checking for an update |
|
|
202
|
+
| `up_to_date` | No update available |
|
|
203
|
+
| `update_available` | Update found, not downloaded |
|
|
204
|
+
| `downloading` | Download in progress |
|
|
205
|
+
| `ready` | Downloaded, waiting for `applyUpdate()` |
|
|
206
|
+
| `error` | Last operation failed — see `error` |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### `useAutoUpdate`
|
|
211
|
+
|
|
212
|
+
Automatically downloads mandatory updates. Optionally applies on next foreground.
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
import { useAutoUpdate } from 'relay-ota-react-native';
|
|
216
|
+
|
|
217
|
+
const { isReady, applyUpdate } = useAutoUpdate({ applyImmediately: false });
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
| Option | Type | Default | Description |
|
|
221
|
+
|--------|------|---------|-------------|
|
|
222
|
+
| `applyImmediately` | `boolean` | `false` | Auto-call `applyUpdate()` when bundle is ready |
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Rollback
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
const { rollback } = useOtaUpdate();
|
|
230
|
+
|
|
231
|
+
// Clears staged bundle and reloads — app falls back to bundled JS
|
|
232
|
+
<Button title="Rollback" onPress={rollback} />
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Channels
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
// Staging builds
|
|
241
|
+
config={{ ..., channel: 'staging' }}
|
|
242
|
+
|
|
243
|
+
// Production builds
|
|
244
|
+
config={{ ..., channel: 'production' }}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Releases are scoped per-channel on the server — staging users never receive production releases.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Push a release (CLI)
|
|
252
|
+
|
|
253
|
+
```sh
|
|
254
|
+
# Build the JS bundle
|
|
255
|
+
npx react-native bundle \
|
|
256
|
+
--platform ios \
|
|
257
|
+
--dev false \
|
|
258
|
+
--bundle-output ./main.jsbundle
|
|
259
|
+
|
|
260
|
+
# Push to your OTA server
|
|
261
|
+
ota release push \
|
|
262
|
+
--channel production \
|
|
263
|
+
--bundle ./main.jsbundle
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Native module setup (bare React Native only)
|
|
269
|
+
|
|
270
|
+
> **Expo managed workflow**: skip — the Expo filesystem adapter handles everything.
|
|
271
|
+
|
|
272
|
+
### iOS
|
|
273
|
+
|
|
274
|
+
1. Copy `OtaBundleUpdater.h` and `OtaBundleUpdater.m` from `node_modules/relay-ota-react-native/src/native/` into your Xcode project
|
|
275
|
+
2. Run `pod install`
|
|
276
|
+
|
|
277
|
+
### Android
|
|
278
|
+
|
|
279
|
+
1. Copy `OtaBundleUpdaterModule.kt` and `OtaBundleUpdaterPackage.kt` into `android/app/src/main/java/<your-package>/`
|
|
280
|
+
2. Register in `MainApplication.kt`:
|
|
281
|
+
|
|
282
|
+
```kotlin
|
|
283
|
+
override fun getPackages(): List<ReactPackage> =
|
|
284
|
+
PackageList(this).packages.apply {
|
|
285
|
+
add(OtaBundleUpdaterPackage())
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## TypeScript types
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
import type {
|
|
295
|
+
OtaConfig,
|
|
296
|
+
UpdateStatus,
|
|
297
|
+
UpdateState,
|
|
298
|
+
IFileSystemAdapter,
|
|
299
|
+
INativeBundleUpdater,
|
|
300
|
+
Platform,
|
|
301
|
+
} from 'relay-ota-react-native';
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### `OtaConfig`
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
interface OtaConfig {
|
|
308
|
+
serverUrl: string;
|
|
309
|
+
appId: string;
|
|
310
|
+
channel: string;
|
|
311
|
+
platform: 'IOS' | 'ANDROID';
|
|
312
|
+
currentVersion: string;
|
|
313
|
+
runtimeVersion: string;
|
|
314
|
+
checkOnForeground?: boolean;
|
|
315
|
+
onUpdate?: (release: Release) => void;
|
|
316
|
+
onError?: (error: Error) => void;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### `IFileSystemAdapter`
|
|
321
|
+
|
|
322
|
+
Implement this to bring your own filesystem layer:
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
interface IFileSystemAdapter {
|
|
326
|
+
getDocumentDirectory(): string;
|
|
327
|
+
exists(path: string): Promise<boolean>;
|
|
328
|
+
readAsString(path: string, encoding: 'utf8' | 'base64'): Promise<string>;
|
|
329
|
+
writeAsString(path: string, content: string, encoding: 'utf8' | 'base64'): Promise<void>;
|
|
330
|
+
deleteFile(path: string): Promise<void>;
|
|
331
|
+
makeDirectory(path: string): Promise<void>;
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Low-level API
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
import {
|
|
341
|
+
checkForUpdate, // (serverUrl, request) => Promise<OtaCheckResponse>
|
|
342
|
+
downloadBundle, // (release, fs, onProgress) => Promise<string>
|
|
343
|
+
OtaUpdater, // Class — manages the full state machine
|
|
344
|
+
} from 'relay-ota-react-native';
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Migrating from CodePush
|
|
350
|
+
|
|
351
|
+
Microsoft retired CodePush in 2025. Relay OTA uses the same update model and a compatible SDK surface. Key differences:
|
|
352
|
+
|
|
353
|
+
| | CodePush | Relay OTA |
|
|
354
|
+
|---|---|---|
|
|
355
|
+
| Hosting | Vendor (shut down) | Self-hosted, you own it |
|
|
356
|
+
| Source | Closed | Open source (MIT) |
|
|
357
|
+
| Cost | Was paid | Free forever |
|
|
358
|
+
| Rollback | Yes | Yes |
|
|
359
|
+
| Analytics | Basic | Built-in, detailed |
|
|
360
|
+
| Staged rollouts | Yes | Yes |
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Links
|
|
365
|
+
|
|
366
|
+
- **Website:** [relayota.com](https://relayota.com)
|
|
367
|
+
- **Docs:** [relayota.com/docs](https://relayota.com/docs)
|
|
368
|
+
- **GitHub:** [github.com/aglaonematech/relay-ota-react-native](https://github.com/aglaonematech/relay-ota-react-native)
|
|
369
|
+
- **npm:** [relay-ota-react-native](https://www.npmjs.com/package/relay-ota-react-native)
|
|
370
|
+
- **Issues:** [github.com/aglaonematech/relay-ota-react-native/issues](https://github.com/aglaonematech/relay-ota-react-native/issues)
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## License
|
|
375
|
+
|
|
376
|
+
MIT — see [LICENSE](https://github.com/aglaonematech/relay-ota-react-native/blob/main/LICENSE)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEjE,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAa3B"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkForUpdate = checkForUpdate;
|
|
4
|
+
async function checkForUpdate(serverUrl, request) {
|
|
5
|
+
const url = `${serverUrl.replace(/\/$/, '')}/api/v1/ota/check`;
|
|
6
|
+
const response = await fetch(url, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: { 'Content-Type': 'application/json' },
|
|
9
|
+
body: JSON.stringify(request),
|
|
10
|
+
});
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
throw new Error(`OTA check failed: HTTP ${response.status}`);
|
|
13
|
+
}
|
|
14
|
+
return response.json();
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;AAEA,wCAgBC;AAhBM,KAAK,UAAU,cAAc,CAClC,SAAiB,EACjB,OAAwB;IAExB,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC;IAC/D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAA+B,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IFileSystemAdapter } from './types';
|
|
2
|
+
import type { OtaCheckResponse } from './types';
|
|
3
|
+
type Release = NonNullable<OtaCheckResponse['release']>;
|
|
4
|
+
export declare function downloadBundle(release: Release, fs: IFileSystemAdapter, onProgress?: (progress: number) => void): Promise<string>;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=downloader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloader.d.ts","sourceRoot":"","sources":["../src/downloader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,KAAK,OAAO,GAAG,WAAW,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;AAExD,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,kBAAkB,EACtB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACtC,OAAO,CAAC,MAAM,CAAC,CAsDjB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.downloadBundle = downloadBundle;
|
|
4
|
+
async function downloadBundle(release, fs, onProgress) {
|
|
5
|
+
const bundleDir = `${fs.getDocumentDirectory()}ota-bundles/${release.id}`;
|
|
6
|
+
const bundlePath = `${bundleDir}/bundle.js`;
|
|
7
|
+
await fs.makeDirectory(bundleDir);
|
|
8
|
+
const response = await fetch(release.downloadUrl);
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new Error(`Download failed: HTTP ${response.status}`);
|
|
11
|
+
}
|
|
12
|
+
const contentLength = parseInt(response.headers.get('content-length') ?? '0', 10);
|
|
13
|
+
const reader = response.body?.getReader();
|
|
14
|
+
if (!reader) {
|
|
15
|
+
// Fallback: read entire body at once (no streaming progress)
|
|
16
|
+
const buffer = await response.arrayBuffer();
|
|
17
|
+
const bytes = new Uint8Array(buffer);
|
|
18
|
+
const b64 = uint8ArrayToBase64(bytes);
|
|
19
|
+
await fs.writeAsString(bundlePath, b64, 'base64');
|
|
20
|
+
onProgress?.(100);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const chunks = [];
|
|
24
|
+
let received = 0;
|
|
25
|
+
while (true) {
|
|
26
|
+
const { done, value } = await reader.read();
|
|
27
|
+
if (done)
|
|
28
|
+
break;
|
|
29
|
+
chunks.push(value);
|
|
30
|
+
received += value.length;
|
|
31
|
+
if (contentLength > 0) {
|
|
32
|
+
onProgress?.(Math.round((received / contentLength) * 100));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const total = chunks.reduce((acc, c) => acc + c.length, 0);
|
|
36
|
+
const merged = new Uint8Array(total);
|
|
37
|
+
let offset = 0;
|
|
38
|
+
for (const chunk of chunks) {
|
|
39
|
+
merged.set(chunk, offset);
|
|
40
|
+
offset += chunk.length;
|
|
41
|
+
}
|
|
42
|
+
const checksum = await sha256Hex(merged);
|
|
43
|
+
if (checksum !== release.checksum) {
|
|
44
|
+
throw new Error(`Checksum mismatch: expected ${release.checksum}, got ${checksum}`);
|
|
45
|
+
}
|
|
46
|
+
const b64 = uint8ArrayToBase64(merged);
|
|
47
|
+
await fs.writeAsString(bundlePath, b64, 'base64');
|
|
48
|
+
onProgress?.(100);
|
|
49
|
+
}
|
|
50
|
+
return bundlePath;
|
|
51
|
+
}
|
|
52
|
+
async function sha256Hex(data) {
|
|
53
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
54
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
55
|
+
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
56
|
+
}
|
|
57
|
+
function uint8ArrayToBase64(bytes) {
|
|
58
|
+
let binary = '';
|
|
59
|
+
const len = bytes.byteLength;
|
|
60
|
+
for (let i = 0; i < len; i++) {
|
|
61
|
+
binary += String.fromCharCode(bytes[i]);
|
|
62
|
+
}
|
|
63
|
+
return btoa(binary);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=downloader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloader.js","sourceRoot":"","sources":["../src/downloader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD,wBAAgB,2BAA2B,IAAI,kBAAkB,CA8BhE;AAGD,wBAAgB,2BAA2B,IAAI,kBAAkB,CAyBhE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createExpoFileSystemAdapter = createExpoFileSystemAdapter;
|
|
4
|
+
exports.createRNFSFileSystemAdapter = createRNFSFileSystemAdapter;
|
|
5
|
+
// Expo adapter — requires expo-file-system
|
|
6
|
+
function createExpoFileSystemAdapter() {
|
|
7
|
+
// Lazily require so non-Expo projects don't fail at import time
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
9
|
+
const ExpoFS = require('expo-file-system');
|
|
10
|
+
return {
|
|
11
|
+
getDocumentDirectory() {
|
|
12
|
+
return ExpoFS.documentDirectory ?? '';
|
|
13
|
+
},
|
|
14
|
+
async exists(path) {
|
|
15
|
+
const info = await ExpoFS.getInfoAsync(path);
|
|
16
|
+
return info.exists;
|
|
17
|
+
},
|
|
18
|
+
async readAsString(path, encoding) {
|
|
19
|
+
return ExpoFS.readAsStringAsync(path, {
|
|
20
|
+
encoding: encoding === 'base64' ? ExpoFS.EncodingType.Base64 : ExpoFS.EncodingType.UTF8,
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
async writeAsString(path, content, encoding) {
|
|
24
|
+
await ExpoFS.writeAsStringAsync(path, content, {
|
|
25
|
+
encoding: encoding === 'base64' ? ExpoFS.EncodingType.Base64 : ExpoFS.EncodingType.UTF8,
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
async deleteFile(path) {
|
|
29
|
+
await ExpoFS.deleteAsync(path, { idempotent: true });
|
|
30
|
+
},
|
|
31
|
+
async makeDirectory(path) {
|
|
32
|
+
await ExpoFS.makeDirectoryAsync(path, { intermediates: true });
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Bare React Native adapter — requires react-native-fs
|
|
37
|
+
function createRNFSFileSystemAdapter() {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
39
|
+
const RNFS = require('react-native-fs');
|
|
40
|
+
return {
|
|
41
|
+
getDocumentDirectory() {
|
|
42
|
+
return `${RNFS.DocumentDirectoryPath}/`;
|
|
43
|
+
},
|
|
44
|
+
async exists(path) {
|
|
45
|
+
return RNFS.exists(path);
|
|
46
|
+
},
|
|
47
|
+
async readAsString(path, encoding) {
|
|
48
|
+
return RNFS.readFile(path, encoding);
|
|
49
|
+
},
|
|
50
|
+
async writeAsString(path, content, encoding) {
|
|
51
|
+
await RNFS.writeFile(path, content, encoding);
|
|
52
|
+
},
|
|
53
|
+
async deleteFile(path) {
|
|
54
|
+
const exists = await RNFS.exists(path);
|
|
55
|
+
if (exists)
|
|
56
|
+
await RNFS.unlink(path);
|
|
57
|
+
},
|
|
58
|
+
async makeDirectory(path) {
|
|
59
|
+
await RNFS.mkdir(path);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=filesystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":";;AAGA,kEA8BC;AAGD,kEAyBC;AA3DD,2CAA2C;AAC3C,SAAgB,2BAA2B;IACzC,gEAAgE;IAChE,8DAA8D;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAQ,CAAC;IAElD,OAAO;QACL,oBAAoB;YAClB,OAAO,MAAM,CAAC,iBAAiB,IAAI,EAAE,CAAC;QACxC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,IAAI;YACf,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YAC7C,OAAO,IAAI,CAAC,MAAM,CAAC;QACrB,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ;YAC/B,OAAO,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE;gBACpC,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI;aACxF,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ;YACzC,MAAM,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE;gBAC7C,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI;aACxF,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,IAAI;YACnB,MAAM,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,IAAI;YACtB,MAAM,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,uDAAuD;AACvD,SAAgB,2BAA2B;IACzC,8DAA8D;IAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAQ,CAAC;IAE/C,OAAO;QACL,oBAAoB;YAClB,OAAO,GAAG,IAAI,CAAC,qBAAqB,GAAG,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,IAAI;YACf,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ;YAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ;YACzC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAChD,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,IAAI;YACnB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,MAAM;gBAAE,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,IAAI;YACtB,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { UpdateState } from './types';
|
|
2
|
+
export interface UseOtaUpdateReturn extends UpdateState {
|
|
3
|
+
checkForUpdates: () => Promise<void>;
|
|
4
|
+
downloadUpdate: () => Promise<void>;
|
|
5
|
+
applyUpdate: () => Promise<void>;
|
|
6
|
+
rollback: () => Promise<void>;
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
hasUpdate: boolean;
|
|
9
|
+
isReady: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function useOtaUpdate(): UseOtaUpdateReturn;
|
|
12
|
+
export declare function useAutoUpdate(options?: {
|
|
13
|
+
applyImmediately?: boolean;
|
|
14
|
+
}): UseOtaUpdateReturn;
|
|
15
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,YAAY,IAAI,kBAAkB,CAajD;AAGD,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,sBAerE"}
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useOtaUpdate = useOtaUpdate;
|
|
4
|
+
exports.useAutoUpdate = useAutoUpdate;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const provider_1 = require("./provider");
|
|
7
|
+
function useOtaUpdate() {
|
|
8
|
+
const { state, checkForUpdates, downloadUpdate, applyUpdate, rollback } = (0, provider_1.useOtaContext)();
|
|
9
|
+
return {
|
|
10
|
+
...state,
|
|
11
|
+
checkForUpdates: (0, react_1.useCallback)(checkForUpdates, [checkForUpdates]),
|
|
12
|
+
downloadUpdate: (0, react_1.useCallback)(downloadUpdate, [downloadUpdate]),
|
|
13
|
+
applyUpdate: (0, react_1.useCallback)(applyUpdate, [applyUpdate]),
|
|
14
|
+
rollback: (0, react_1.useCallback)(rollback, [rollback]),
|
|
15
|
+
isLoading: state.status === 'checking' || state.status === 'downloading',
|
|
16
|
+
hasUpdate: state.status === 'update_available',
|
|
17
|
+
isReady: state.status === 'ready',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
// Hook that auto-downloads and applies mandatory updates
|
|
21
|
+
function useAutoUpdate(options) {
|
|
22
|
+
const ota = useOtaUpdate();
|
|
23
|
+
const applyImmediately = options?.applyImmediately ?? false;
|
|
24
|
+
// Auto-download when update is detected
|
|
25
|
+
if (ota.hasUpdate && ota.release?.isMandatory) {
|
|
26
|
+
ota.downloadUpdate();
|
|
27
|
+
}
|
|
28
|
+
// Auto-apply when ready and applyImmediately is set
|
|
29
|
+
if (ota.isReady && applyImmediately) {
|
|
30
|
+
ota.applyUpdate();
|
|
31
|
+
}
|
|
32
|
+
return ota;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":";;AAcA,oCAaC;AAGD,sCAeC;AA7CD,iCAAoC;AACpC,yCAA2C;AAa3C,SAAgB,YAAY;IAC1B,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,IAAA,wBAAa,GAAE,CAAC;IAE1F,OAAO;QACL,GAAG,KAAK;QACR,eAAe,EAAE,IAAA,mBAAW,EAAC,eAAe,EAAE,CAAC,eAAe,CAAC,CAAC;QAChE,cAAc,EAAE,IAAA,mBAAW,EAAC,cAAc,EAAE,CAAC,cAAc,CAAC,CAAC;QAC7D,WAAW,EAAE,IAAA,mBAAW,EAAC,WAAW,EAAE,CAAC,WAAW,CAAC,CAAC;QACpD,QAAQ,EAAE,IAAA,mBAAW,EAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;QAC3C,SAAS,EAAE,KAAK,CAAC,MAAM,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa;QACxE,SAAS,EAAE,KAAK,CAAC,MAAM,KAAK,kBAAkB;QAC9C,OAAO,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO;KAClC,CAAC;AACJ,CAAC;AAED,yDAAyD;AACzD,SAAgB,aAAa,CAAC,OAAwC;IACpE,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,MAAM,gBAAgB,GAAG,OAAO,EAAE,gBAAgB,IAAI,KAAK,CAAC;IAE5D,wCAAwC;IACxC,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;QAC9C,GAAG,CAAC,cAAc,EAAE,CAAC;IACvB,CAAC;IAED,oDAAoD;IACpD,IAAI,GAAG,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAC;QACpC,GAAG,CAAC,WAAW,EAAE,CAAC;IACpB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { OtaProvider, useOtaContext } from './provider';
|
|
2
|
+
export { useOtaUpdate, useAutoUpdate } from './hooks';
|
|
3
|
+
export { OtaUpdater } from './updater';
|
|
4
|
+
export { checkForUpdate } from './client';
|
|
5
|
+
export { downloadBundle } from './downloader';
|
|
6
|
+
export { createExpoFileSystemAdapter, createRNFSFileSystemAdapter } from './filesystem';
|
|
7
|
+
export { isNativeModuleAvailable, setStagedBundlePath, getStagedBundlePath, clearStagedBundlePath, reload, } from './installer';
|
|
8
|
+
export type { OtaConfig, UpdateStatus, UpdateState, IFileSystemAdapter, INativeBundleUpdater, Platform, } from './types';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,MAAM,GACP,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,oBAAoB,EACpB,QAAQ,GACT,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reload = exports.clearStagedBundlePath = exports.getStagedBundlePath = exports.setStagedBundlePath = exports.isNativeModuleAvailable = exports.createRNFSFileSystemAdapter = exports.createExpoFileSystemAdapter = exports.downloadBundle = exports.checkForUpdate = exports.OtaUpdater = exports.useAutoUpdate = exports.useOtaUpdate = exports.useOtaContext = exports.OtaProvider = void 0;
|
|
4
|
+
var provider_1 = require("./provider");
|
|
5
|
+
Object.defineProperty(exports, "OtaProvider", { enumerable: true, get: function () { return provider_1.OtaProvider; } });
|
|
6
|
+
Object.defineProperty(exports, "useOtaContext", { enumerable: true, get: function () { return provider_1.useOtaContext; } });
|
|
7
|
+
var hooks_1 = require("./hooks");
|
|
8
|
+
Object.defineProperty(exports, "useOtaUpdate", { enumerable: true, get: function () { return hooks_1.useOtaUpdate; } });
|
|
9
|
+
Object.defineProperty(exports, "useAutoUpdate", { enumerable: true, get: function () { return hooks_1.useAutoUpdate; } });
|
|
10
|
+
var updater_1 = require("./updater");
|
|
11
|
+
Object.defineProperty(exports, "OtaUpdater", { enumerable: true, get: function () { return updater_1.OtaUpdater; } });
|
|
12
|
+
var client_1 = require("./client");
|
|
13
|
+
Object.defineProperty(exports, "checkForUpdate", { enumerable: true, get: function () { return client_1.checkForUpdate; } });
|
|
14
|
+
var downloader_1 = require("./downloader");
|
|
15
|
+
Object.defineProperty(exports, "downloadBundle", { enumerable: true, get: function () { return downloader_1.downloadBundle; } });
|
|
16
|
+
var filesystem_1 = require("./filesystem");
|
|
17
|
+
Object.defineProperty(exports, "createExpoFileSystemAdapter", { enumerable: true, get: function () { return filesystem_1.createExpoFileSystemAdapter; } });
|
|
18
|
+
Object.defineProperty(exports, "createRNFSFileSystemAdapter", { enumerable: true, get: function () { return filesystem_1.createRNFSFileSystemAdapter; } });
|
|
19
|
+
var installer_1 = require("./installer");
|
|
20
|
+
Object.defineProperty(exports, "isNativeModuleAvailable", { enumerable: true, get: function () { return installer_1.isNativeModuleAvailable; } });
|
|
21
|
+
Object.defineProperty(exports, "setStagedBundlePath", { enumerable: true, get: function () { return installer_1.setStagedBundlePath; } });
|
|
22
|
+
Object.defineProperty(exports, "getStagedBundlePath", { enumerable: true, get: function () { return installer_1.getStagedBundlePath; } });
|
|
23
|
+
Object.defineProperty(exports, "clearStagedBundlePath", { enumerable: true, get: function () { return installer_1.clearStagedBundlePath; } });
|
|
24
|
+
Object.defineProperty(exports, "reload", { enumerable: true, get: function () { return installer_1.reload; } });
|
|
25
|
+
//# sourceMappingURL=index.js.map
|