@vanikya/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 +223 -0
- package/android/build.gradle +58 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/com/otaupdate/OTAUpdateModule.kt +185 -0
- package/android/src/main/java/com/otaupdate/OTAUpdatePackage.kt +16 -0
- package/ios/OTAUpdate.m +61 -0
- package/ios/OTAUpdate.swift +194 -0
- package/lib/commonjs/OTAProvider.js +113 -0
- package/lib/commonjs/OTAProvider.js.map +1 -0
- package/lib/commonjs/hooks/useOTAUpdate.js +272 -0
- package/lib/commonjs/hooks/useOTAUpdate.js.map +1 -0
- package/lib/commonjs/index.js +98 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/utils/api.js +60 -0
- package/lib/commonjs/utils/api.js.map +1 -0
- package/lib/commonjs/utils/storage.js +209 -0
- package/lib/commonjs/utils/storage.js.map +1 -0
- package/lib/commonjs/utils/verification.js +145 -0
- package/lib/commonjs/utils/verification.js.map +1 -0
- package/lib/module/OTAProvider.js +104 -0
- package/lib/module/OTAProvider.js.map +1 -0
- package/lib/module/hooks/useOTAUpdate.js +266 -0
- package/lib/module/hooks/useOTAUpdate.js.map +1 -0
- package/lib/module/index.js +11 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/utils/api.js +52 -0
- package/lib/module/utils/api.js.map +1 -0
- package/lib/module/utils/storage.js +202 -0
- package/lib/module/utils/storage.js.map +1 -0
- package/lib/module/utils/verification.js +137 -0
- package/lib/module/utils/verification.js.map +1 -0
- package/lib/typescript/OTAProvider.d.ts +28 -0
- package/lib/typescript/OTAProvider.d.ts.map +1 -0
- package/lib/typescript/hooks/useOTAUpdate.d.ts +35 -0
- package/lib/typescript/hooks/useOTAUpdate.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +12 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/utils/api.d.ts +47 -0
- package/lib/typescript/utils/api.d.ts.map +1 -0
- package/lib/typescript/utils/storage.d.ts +32 -0
- package/lib/typescript/utils/storage.d.ts.map +1 -0
- package/lib/typescript/utils/verification.d.ts +11 -0
- package/lib/typescript/utils/verification.d.ts.map +1 -0
- package/ota-update.podspec +21 -0
- package/package.json +83 -0
- package/src/OTAProvider.tsx +160 -0
- package/src/hooks/useOTAUpdate.ts +344 -0
- package/src/index.ts +36 -0
- package/src/utils/api.ts +99 -0
- package/src/utils/storage.ts +249 -0
- package/src/utils/verification.ts +167 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { AppState, NativeModules, Platform } from 'react-native';
|
|
3
|
+
import { OTAApiClient, getDeviceInfo } from '../utils/api';
|
|
4
|
+
import { UpdateStorage } from '../utils/storage';
|
|
5
|
+
import { verifyBundle } from '../utils/verification';
|
|
6
|
+
const OTAUpdateNative = NativeModules.OTAUpdate;
|
|
7
|
+
// Generate or get device ID
|
|
8
|
+
async function getDeviceId() {
|
|
9
|
+
// Try to get from native module or AsyncStorage
|
|
10
|
+
// For simplicity, we generate a random one and ideally persist it
|
|
11
|
+
// In production, use a proper device ID solution
|
|
12
|
+
const id = `device_${Math.random().toString(36).substring(2, 15)}`;
|
|
13
|
+
return id;
|
|
14
|
+
}
|
|
15
|
+
export function useOTAUpdate(config) {
|
|
16
|
+
const {
|
|
17
|
+
serverUrl,
|
|
18
|
+
appSlug,
|
|
19
|
+
channel = 'production',
|
|
20
|
+
appVersion,
|
|
21
|
+
publicKey,
|
|
22
|
+
checkOnMount = true,
|
|
23
|
+
checkOnForeground = true
|
|
24
|
+
} = config;
|
|
25
|
+
const [status, setStatus] = useState('idle');
|
|
26
|
+
const [updateInfo, setUpdateInfo] = useState(null);
|
|
27
|
+
const [downloadProgress, setDownloadProgress] = useState(null);
|
|
28
|
+
const [error, setError] = useState(null);
|
|
29
|
+
const [currentVersion, setCurrentVersion] = useState(null);
|
|
30
|
+
const apiClient = useRef(new OTAApiClient(serverUrl));
|
|
31
|
+
const storage = useRef(new UpdateStorage());
|
|
32
|
+
const deviceIdRef = useRef(null);
|
|
33
|
+
const releaseRef = useRef(null);
|
|
34
|
+
|
|
35
|
+
// Load current version on mount
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const loadCurrentVersion = async () => {
|
|
38
|
+
const metadata = await storage.current.getMetadata();
|
|
39
|
+
if (metadata) {
|
|
40
|
+
setCurrentVersion(metadata.version);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
loadCurrentVersion();
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
46
|
+
// Get device ID
|
|
47
|
+
const getDeviceIdCached = useCallback(async () => {
|
|
48
|
+
if (!deviceIdRef.current) {
|
|
49
|
+
deviceIdRef.current = await getDeviceId();
|
|
50
|
+
}
|
|
51
|
+
return deviceIdRef.current;
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
// Check for updates
|
|
55
|
+
const checkForUpdate = useCallback(async () => {
|
|
56
|
+
try {
|
|
57
|
+
setStatus('checking');
|
|
58
|
+
setError(null);
|
|
59
|
+
const deviceId = await getDeviceIdCached();
|
|
60
|
+
const currentMetadata = await storage.current.getMetadata();
|
|
61
|
+
const response = await apiClient.current.checkUpdate({
|
|
62
|
+
appSlug,
|
|
63
|
+
channel,
|
|
64
|
+
platform: Platform.OS,
|
|
65
|
+
currentVersion: currentMetadata?.version || null,
|
|
66
|
+
appVersion,
|
|
67
|
+
deviceId
|
|
68
|
+
});
|
|
69
|
+
if (!response.updateAvailable || !response.release) {
|
|
70
|
+
setStatus('up-to-date');
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
releaseRef.current = response.release;
|
|
74
|
+
const info = {
|
|
75
|
+
version: response.release.version,
|
|
76
|
+
releaseId: response.release.id,
|
|
77
|
+
bundleSize: response.release.bundleSize,
|
|
78
|
+
isMandatory: response.release.isMandatory,
|
|
79
|
+
releaseNotes: response.release.releaseNotes
|
|
80
|
+
};
|
|
81
|
+
setUpdateInfo(info);
|
|
82
|
+
setStatus('available');
|
|
83
|
+
return info;
|
|
84
|
+
} catch (err) {
|
|
85
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
86
|
+
setError(error);
|
|
87
|
+
setStatus('error');
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}, [appSlug, channel, appVersion, getDeviceIdCached]);
|
|
91
|
+
|
|
92
|
+
// Download update
|
|
93
|
+
const downloadUpdate = useCallback(async () => {
|
|
94
|
+
if (!releaseRef.current) {
|
|
95
|
+
throw new Error('No update available to download');
|
|
96
|
+
}
|
|
97
|
+
const release = releaseRef.current;
|
|
98
|
+
const deviceId = await getDeviceIdCached();
|
|
99
|
+
try {
|
|
100
|
+
setStatus('downloading');
|
|
101
|
+
setDownloadProgress({
|
|
102
|
+
downloadedBytes: 0,
|
|
103
|
+
totalBytes: release.bundleSize,
|
|
104
|
+
percentage: 0
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Report download start
|
|
108
|
+
apiClient.current.reportEvent({
|
|
109
|
+
appSlug,
|
|
110
|
+
releaseId: release.id,
|
|
111
|
+
deviceId,
|
|
112
|
+
eventType: 'download',
|
|
113
|
+
appVersion,
|
|
114
|
+
deviceInfo: getDeviceInfo()
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Download bundle
|
|
118
|
+
const bundleData = await apiClient.current.downloadBundle(release.bundleUrl);
|
|
119
|
+
setDownloadProgress({
|
|
120
|
+
downloadedBytes: bundleData.byteLength,
|
|
121
|
+
totalBytes: release.bundleSize,
|
|
122
|
+
percentage: 100
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Verify bundle
|
|
126
|
+
setStatus('verifying');
|
|
127
|
+
const verification = await verifyBundle(bundleData, release.bundleHash, release.bundleSignature, publicKey || null);
|
|
128
|
+
if (!verification.valid) {
|
|
129
|
+
throw new Error(verification.error || 'Bundle verification failed');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Save bundle
|
|
133
|
+
const bundlePath = await storage.current.saveBundle(release.id, bundleData);
|
|
134
|
+
|
|
135
|
+
// Save metadata
|
|
136
|
+
await storage.current.saveMetadata({
|
|
137
|
+
releaseId: release.id,
|
|
138
|
+
version: release.version,
|
|
139
|
+
bundlePath,
|
|
140
|
+
bundleHash: release.bundleHash,
|
|
141
|
+
downloadedAt: Date.now()
|
|
142
|
+
});
|
|
143
|
+
setStatus('ready');
|
|
144
|
+
} catch (err) {
|
|
145
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
146
|
+
|
|
147
|
+
// Report failure
|
|
148
|
+
apiClient.current.reportEvent({
|
|
149
|
+
appSlug,
|
|
150
|
+
releaseId: release.id,
|
|
151
|
+
deviceId,
|
|
152
|
+
eventType: 'failure',
|
|
153
|
+
errorMessage: error.message,
|
|
154
|
+
appVersion,
|
|
155
|
+
deviceInfo: getDeviceInfo()
|
|
156
|
+
});
|
|
157
|
+
setError(error);
|
|
158
|
+
setStatus('error');
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
}, [appSlug, appVersion, publicKey, getDeviceIdCached]);
|
|
162
|
+
|
|
163
|
+
// Apply update
|
|
164
|
+
const applyUpdate = useCallback(async (restartApp = true) => {
|
|
165
|
+
const metadata = await storage.current.getMetadata();
|
|
166
|
+
if (!metadata) {
|
|
167
|
+
throw new Error('No update available to apply');
|
|
168
|
+
}
|
|
169
|
+
const deviceId = await getDeviceIdCached();
|
|
170
|
+
try {
|
|
171
|
+
setStatus('applying');
|
|
172
|
+
|
|
173
|
+
// Report apply
|
|
174
|
+
apiClient.current.reportEvent({
|
|
175
|
+
appSlug,
|
|
176
|
+
releaseId: metadata.releaseId,
|
|
177
|
+
deviceId,
|
|
178
|
+
eventType: 'apply',
|
|
179
|
+
appVersion,
|
|
180
|
+
deviceInfo: getDeviceInfo()
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Apply bundle using native module
|
|
184
|
+
if (OTAUpdateNative?.applyBundle) {
|
|
185
|
+
await OTAUpdateNative.applyBundle(metadata.bundlePath, restartApp);
|
|
186
|
+
} else if (restartApp) {
|
|
187
|
+
// If no native module, we need to restart manually
|
|
188
|
+
// The bundle will be loaded on next app start
|
|
189
|
+
if (__DEV__) {
|
|
190
|
+
console.log('[OTAUpdate] Update ready. Restart the app to apply.');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Report success (this might not run if app restarts)
|
|
195
|
+
apiClient.current.reportEvent({
|
|
196
|
+
appSlug,
|
|
197
|
+
releaseId: metadata.releaseId,
|
|
198
|
+
deviceId,
|
|
199
|
+
eventType: 'success',
|
|
200
|
+
appVersion,
|
|
201
|
+
deviceInfo: getDeviceInfo()
|
|
202
|
+
});
|
|
203
|
+
setCurrentVersion(metadata.version);
|
|
204
|
+
setStatus('idle');
|
|
205
|
+
} catch (err) {
|
|
206
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
207
|
+
apiClient.current.reportEvent({
|
|
208
|
+
appSlug,
|
|
209
|
+
releaseId: metadata.releaseId,
|
|
210
|
+
deviceId,
|
|
211
|
+
eventType: 'failure',
|
|
212
|
+
errorMessage: error.message,
|
|
213
|
+
appVersion,
|
|
214
|
+
deviceInfo: getDeviceInfo()
|
|
215
|
+
});
|
|
216
|
+
setError(error);
|
|
217
|
+
setStatus('error');
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
}, [appSlug, appVersion, getDeviceIdCached]);
|
|
221
|
+
|
|
222
|
+
// Clear pending update
|
|
223
|
+
const clearPendingUpdate = useCallback(async () => {
|
|
224
|
+
const metadata = await storage.current.getMetadata();
|
|
225
|
+
if (metadata) {
|
|
226
|
+
await storage.current.deleteBundle(metadata.releaseId);
|
|
227
|
+
await storage.current.clearMetadata();
|
|
228
|
+
}
|
|
229
|
+
setUpdateInfo(null);
|
|
230
|
+
releaseRef.current = null;
|
|
231
|
+
setStatus('idle');
|
|
232
|
+
}, []);
|
|
233
|
+
|
|
234
|
+
// Check on mount
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
if (checkOnMount) {
|
|
237
|
+
checkForUpdate();
|
|
238
|
+
}
|
|
239
|
+
}, [checkOnMount, checkForUpdate]);
|
|
240
|
+
|
|
241
|
+
// Check on foreground
|
|
242
|
+
useEffect(() => {
|
|
243
|
+
if (!checkOnForeground) return;
|
|
244
|
+
const handleAppStateChange = nextAppState => {
|
|
245
|
+
if (nextAppState === 'active' && status === 'idle') {
|
|
246
|
+
checkForUpdate();
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
const subscription = AppState.addEventListener('change', handleAppStateChange);
|
|
250
|
+
return () => {
|
|
251
|
+
subscription.remove();
|
|
252
|
+
};
|
|
253
|
+
}, [checkOnForeground, checkForUpdate, status]);
|
|
254
|
+
return {
|
|
255
|
+
status,
|
|
256
|
+
updateInfo,
|
|
257
|
+
downloadProgress,
|
|
258
|
+
error,
|
|
259
|
+
currentVersion,
|
|
260
|
+
checkForUpdate,
|
|
261
|
+
downloadUpdate,
|
|
262
|
+
applyUpdate,
|
|
263
|
+
clearPendingUpdate
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=useOTAUpdate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useState","useCallback","useEffect","useRef","AppState","NativeModules","Platform","OTAApiClient","getDeviceInfo","UpdateStorage","verifyBundle","OTAUpdateNative","OTAUpdate","getDeviceId","id","Math","random","toString","substring","useOTAUpdate","config","serverUrl","appSlug","channel","appVersion","publicKey","checkOnMount","checkOnForeground","status","setStatus","updateInfo","setUpdateInfo","downloadProgress","setDownloadProgress","error","setError","currentVersion","setCurrentVersion","apiClient","storage","deviceIdRef","releaseRef","loadCurrentVersion","metadata","current","getMetadata","version","getDeviceIdCached","checkForUpdate","deviceId","currentMetadata","response","checkUpdate","platform","OS","updateAvailable","release","info","releaseId","bundleSize","isMandatory","releaseNotes","err","Error","String","downloadUpdate","downloadedBytes","totalBytes","percentage","reportEvent","eventType","deviceInfo","bundleData","downloadBundle","bundleUrl","byteLength","verification","bundleHash","bundleSignature","valid","bundlePath","saveBundle","saveMetadata","downloadedAt","Date","now","errorMessage","message","applyUpdate","restartApp","applyBundle","__DEV__","console","log","clearPendingUpdate","deleteBundle","clearMetadata","handleAppStateChange","nextAppState","subscription","addEventListener","remove"],"sourceRoot":"../../../src","sources":["hooks/useOTAUpdate.ts"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,WAAW,EAAEC,SAAS,EAAEC,MAAM,QAAQ,OAAO;AAChE,SAASC,QAAQ,EAAkBC,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AAChF,SAASC,YAAY,EAAeC,aAAa,QAAQ,cAAc;AACvE,SAASC,aAAa,QAAsB,kBAAkB;AAC9D,SAASC,YAAY,QAA4B,uBAAuB;AAExE,MAAMC,eAAe,GAAGN,aAAa,CAACO,SAAS;AAiD/C;AACA,eAAeC,WAAWA,CAAA,EAAoB;EAC5C;EACA;EACA;EACA,MAAMC,EAAE,GAAG,UAAUC,IAAI,CAACC,MAAM,CAAC,CAAC,CAACC,QAAQ,CAAC,EAAE,CAAC,CAACC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;EAClE,OAAOJ,EAAE;AACX;AAEA,OAAO,SAASK,YAAYA,CAACC,MAAuB,EAAsB;EACxE,MAAM;IACJC,SAAS;IACTC,OAAO;IACPC,OAAO,GAAG,YAAY;IACtBC,UAAU;IACVC,SAAS;IACTC,YAAY,GAAG,IAAI;IACnBC,iBAAiB,GAAG;EACtB,CAAC,GAAGP,MAAM;EAEV,MAAM,CAACQ,MAAM,EAAEC,SAAS,CAAC,GAAG7B,QAAQ,CAAe,MAAM,CAAC;EAC1D,MAAM,CAAC8B,UAAU,EAAEC,aAAa,CAAC,GAAG/B,QAAQ,CAAoB,IAAI,CAAC;EACrE,MAAM,CAACgC,gBAAgB,EAAEC,mBAAmB,CAAC,GAAGjC,QAAQ,CAA0B,IAAI,CAAC;EACvF,MAAM,CAACkC,KAAK,EAAEC,QAAQ,CAAC,GAAGnC,QAAQ,CAAe,IAAI,CAAC;EACtD,MAAM,CAACoC,cAAc,EAAEC,iBAAiB,CAAC,GAAGrC,QAAQ,CAAgB,IAAI,CAAC;EAEzE,MAAMsC,SAAS,GAAGnC,MAAM,CAAC,IAAII,YAAY,CAACc,SAAS,CAAC,CAAC;EACrD,MAAMkB,OAAO,GAAGpC,MAAM,CAAC,IAAIM,aAAa,CAAC,CAAC,CAAC;EAC3C,MAAM+B,WAAW,GAAGrC,MAAM,CAAgB,IAAI,CAAC;EAC/C,MAAMsC,UAAU,GAAGtC,MAAM,CAAqB,IAAI,CAAC;;EAEnD;EACAD,SAAS,CAAC,MAAM;IACd,MAAMwC,kBAAkB,GAAG,MAAAA,CAAA,KAAY;MACrC,MAAMC,QAAQ,GAAG,MAAMJ,OAAO,CAACK,OAAO,CAACC,WAAW,CAAC,CAAC;MACpD,IAAIF,QAAQ,EAAE;QACZN,iBAAiB,CAACM,QAAQ,CAACG,OAAO,CAAC;MACrC;IACF,CAAC;IACDJ,kBAAkB,CAAC,CAAC;EACtB,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA,MAAMK,iBAAiB,GAAG9C,WAAW,CAAC,YAAY;IAChD,IAAI,CAACuC,WAAW,CAACI,OAAO,EAAE;MACxBJ,WAAW,CAACI,OAAO,GAAG,MAAM/B,WAAW,CAAC,CAAC;IAC3C;IACA,OAAO2B,WAAW,CAACI,OAAO;EAC5B,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA,MAAMI,cAAc,GAAG/C,WAAW,CAAC,YAAwC;IACzE,IAAI;MACF4B,SAAS,CAAC,UAAU,CAAC;MACrBM,QAAQ,CAAC,IAAI,CAAC;MAEd,MAAMc,QAAQ,GAAG,MAAMF,iBAAiB,CAAC,CAAC;MAC1C,MAAMG,eAAe,GAAG,MAAMX,OAAO,CAACK,OAAO,CAACC,WAAW,CAAC,CAAC;MAE3D,MAAMM,QAAQ,GAAG,MAAMb,SAAS,CAACM,OAAO,CAACQ,WAAW,CAAC;QACnD9B,OAAO;QACPC,OAAO;QACP8B,QAAQ,EAAE/C,QAAQ,CAACgD,EAAuB;QAC1ClB,cAAc,EAAEc,eAAe,EAAEJ,OAAO,IAAI,IAAI;QAChDtB,UAAU;QACVyB;MACF,CAAC,CAAC;MAEF,IAAI,CAACE,QAAQ,CAACI,eAAe,IAAI,CAACJ,QAAQ,CAACK,OAAO,EAAE;QAClD3B,SAAS,CAAC,YAAY,CAAC;QACvB,OAAO,IAAI;MACb;MAEAY,UAAU,CAACG,OAAO,GAAGO,QAAQ,CAACK,OAAO;MAErC,MAAMC,IAAgB,GAAG;QACvBX,OAAO,EAAEK,QAAQ,CAACK,OAAO,CAACV,OAAO;QACjCY,SAAS,EAAEP,QAAQ,CAACK,OAAO,CAAC1C,EAAE;QAC9B6C,UAAU,EAAER,QAAQ,CAACK,OAAO,CAACG,UAAU;QACvCC,WAAW,EAAET,QAAQ,CAACK,OAAO,CAACI,WAAW;QACzCC,YAAY,EAAEV,QAAQ,CAACK,OAAO,CAACK;MACjC,CAAC;MAED9B,aAAa,CAAC0B,IAAI,CAAC;MACnB5B,SAAS,CAAC,WAAW,CAAC;MAEtB,OAAO4B,IAAI;IACb,CAAC,CAAC,OAAOK,GAAG,EAAE;MACZ,MAAM5B,KAAK,GAAG4B,GAAG,YAAYC,KAAK,GAAGD,GAAG,GAAG,IAAIC,KAAK,CAACC,MAAM,CAACF,GAAG,CAAC,CAAC;MACjE3B,QAAQ,CAACD,KAAK,CAAC;MACfL,SAAS,CAAC,OAAO,CAAC;MAClB,OAAO,IAAI;IACb;EACF,CAAC,EAAE,CAACP,OAAO,EAAEC,OAAO,EAAEC,UAAU,EAAEuB,iBAAiB,CAAC,CAAC;;EAErD;EACA,MAAMkB,cAAc,GAAGhE,WAAW,CAAC,YAA2B;IAC5D,IAAI,CAACwC,UAAU,CAACG,OAAO,EAAE;MACvB,MAAM,IAAImB,KAAK,CAAC,iCAAiC,CAAC;IACpD;IAEA,MAAMP,OAAO,GAAGf,UAAU,CAACG,OAAO;IAClC,MAAMK,QAAQ,GAAG,MAAMF,iBAAiB,CAAC,CAAC;IAE1C,IAAI;MACFlB,SAAS,CAAC,aAAa,CAAC;MACxBI,mBAAmB,CAAC;QAAEiC,eAAe,EAAE,CAAC;QAAEC,UAAU,EAAEX,OAAO,CAACG,UAAU;QAAES,UAAU,EAAE;MAAE,CAAC,CAAC;;MAE1F;MACA9B,SAAS,CAACM,OAAO,CAACyB,WAAW,CAAC;QAC5B/C,OAAO;QACPoC,SAAS,EAAEF,OAAO,CAAC1C,EAAE;QACrBmC,QAAQ;QACRqB,SAAS,EAAE,UAAU;QACrB9C,UAAU;QACV+C,UAAU,EAAE/D,aAAa,CAAC;MAC5B,CAAC,CAAC;;MAEF;MACA,MAAMgE,UAAU,GAAG,MAAMlC,SAAS,CAACM,OAAO,CAAC6B,cAAc,CAACjB,OAAO,CAACkB,SAAS,CAAC;MAE5EzC,mBAAmB,CAAC;QAClBiC,eAAe,EAAEM,UAAU,CAACG,UAAU;QACtCR,UAAU,EAAEX,OAAO,CAACG,UAAU;QAC9BS,UAAU,EAAE;MACd,CAAC,CAAC;;MAEF;MACAvC,SAAS,CAAC,WAAW,CAAC;MAEtB,MAAM+C,YAAY,GAAG,MAAMlE,YAAY,CACrC8D,UAAU,EACVhB,OAAO,CAACqB,UAAU,EAClBrB,OAAO,CAACsB,eAAe,EACvBrD,SAAS,IAAI,IACf,CAAC;MAED,IAAI,CAACmD,YAAY,CAACG,KAAK,EAAE;QACvB,MAAM,IAAIhB,KAAK,CAACa,YAAY,CAAC1C,KAAK,IAAI,4BAA4B,CAAC;MACrE;;MAEA;MACA,MAAM8C,UAAU,GAAG,MAAMzC,OAAO,CAACK,OAAO,CAACqC,UAAU,CAACzB,OAAO,CAAC1C,EAAE,EAAE0D,UAAU,CAAC;;MAE3E;MACA,MAAMjC,OAAO,CAACK,OAAO,CAACsC,YAAY,CAAC;QACjCxB,SAAS,EAAEF,OAAO,CAAC1C,EAAE;QACrBgC,OAAO,EAAEU,OAAO,CAACV,OAAO;QACxBkC,UAAU;QACVH,UAAU,EAAErB,OAAO,CAACqB,UAAU;QAC9BM,YAAY,EAAEC,IAAI,CAACC,GAAG,CAAC;MACzB,CAAC,CAAC;MAEFxD,SAAS,CAAC,OAAO,CAAC;IACpB,CAAC,CAAC,OAAOiC,GAAG,EAAE;MACZ,MAAM5B,KAAK,GAAG4B,GAAG,YAAYC,KAAK,GAAGD,GAAG,GAAG,IAAIC,KAAK,CAACC,MAAM,CAACF,GAAG,CAAC,CAAC;;MAEjE;MACAxB,SAAS,CAACM,OAAO,CAACyB,WAAW,CAAC;QAC5B/C,OAAO;QACPoC,SAAS,EAAEF,OAAO,CAAC1C,EAAE;QACrBmC,QAAQ;QACRqB,SAAS,EAAE,SAAS;QACpBgB,YAAY,EAAEpD,KAAK,CAACqD,OAAO;QAC3B/D,UAAU;QACV+C,UAAU,EAAE/D,aAAa,CAAC;MAC5B,CAAC,CAAC;MAEF2B,QAAQ,CAACD,KAAK,CAAC;MACfL,SAAS,CAAC,OAAO,CAAC;MAClB,MAAMK,KAAK;IACb;EACF,CAAC,EAAE,CAACZ,OAAO,EAAEE,UAAU,EAAEC,SAAS,EAAEsB,iBAAiB,CAAC,CAAC;;EAEvD;EACA,MAAMyC,WAAW,GAAGvF,WAAW,CAAC,OAAOwF,UAAmB,GAAG,IAAI,KAAoB;IACnF,MAAM9C,QAAQ,GAAG,MAAMJ,OAAO,CAACK,OAAO,CAACC,WAAW,CAAC,CAAC;IAEpD,IAAI,CAACF,QAAQ,EAAE;MACb,MAAM,IAAIoB,KAAK,CAAC,8BAA8B,CAAC;IACjD;IAEA,MAAMd,QAAQ,GAAG,MAAMF,iBAAiB,CAAC,CAAC;IAE1C,IAAI;MACFlB,SAAS,CAAC,UAAU,CAAC;;MAErB;MACAS,SAAS,CAACM,OAAO,CAACyB,WAAW,CAAC;QAC5B/C,OAAO;QACPoC,SAAS,EAAEf,QAAQ,CAACe,SAAS;QAC7BT,QAAQ;QACRqB,SAAS,EAAE,OAAO;QAClB9C,UAAU;QACV+C,UAAU,EAAE/D,aAAa,CAAC;MAC5B,CAAC,CAAC;;MAEF;MACA,IAAIG,eAAe,EAAE+E,WAAW,EAAE;QAChC,MAAM/E,eAAe,CAAC+E,WAAW,CAAC/C,QAAQ,CAACqC,UAAU,EAAES,UAAU,CAAC;MACpE,CAAC,MAAM,IAAIA,UAAU,EAAE;QACrB;QACA;QACA,IAAIE,OAAO,EAAE;UACXC,OAAO,CAACC,GAAG,CAAC,qDAAqD,CAAC;QACpE;MACF;;MAEA;MACAvD,SAAS,CAACM,OAAO,CAACyB,WAAW,CAAC;QAC5B/C,OAAO;QACPoC,SAAS,EAAEf,QAAQ,CAACe,SAAS;QAC7BT,QAAQ;QACRqB,SAAS,EAAE,SAAS;QACpB9C,UAAU;QACV+C,UAAU,EAAE/D,aAAa,CAAC;MAC5B,CAAC,CAAC;MAEF6B,iBAAiB,CAACM,QAAQ,CAACG,OAAO,CAAC;MACnCjB,SAAS,CAAC,MAAM,CAAC;IACnB,CAAC,CAAC,OAAOiC,GAAG,EAAE;MACZ,MAAM5B,KAAK,GAAG4B,GAAG,YAAYC,KAAK,GAAGD,GAAG,GAAG,IAAIC,KAAK,CAACC,MAAM,CAACF,GAAG,CAAC,CAAC;MAEjExB,SAAS,CAACM,OAAO,CAACyB,WAAW,CAAC;QAC5B/C,OAAO;QACPoC,SAAS,EAAEf,QAAQ,CAACe,SAAS;QAC7BT,QAAQ;QACRqB,SAAS,EAAE,SAAS;QACpBgB,YAAY,EAAEpD,KAAK,CAACqD,OAAO;QAC3B/D,UAAU;QACV+C,UAAU,EAAE/D,aAAa,CAAC;MAC5B,CAAC,CAAC;MAEF2B,QAAQ,CAACD,KAAK,CAAC;MACfL,SAAS,CAAC,OAAO,CAAC;MAClB,MAAMK,KAAK;IACb;EACF,CAAC,EAAE,CAACZ,OAAO,EAAEE,UAAU,EAAEuB,iBAAiB,CAAC,CAAC;;EAE5C;EACA,MAAM+C,kBAAkB,GAAG7F,WAAW,CAAC,YAA2B;IAChE,MAAM0C,QAAQ,GAAG,MAAMJ,OAAO,CAACK,OAAO,CAACC,WAAW,CAAC,CAAC;IAEpD,IAAIF,QAAQ,EAAE;MACZ,MAAMJ,OAAO,CAACK,OAAO,CAACmD,YAAY,CAACpD,QAAQ,CAACe,SAAS,CAAC;MACtD,MAAMnB,OAAO,CAACK,OAAO,CAACoD,aAAa,CAAC,CAAC;IACvC;IAEAjE,aAAa,CAAC,IAAI,CAAC;IACnBU,UAAU,CAACG,OAAO,GAAG,IAAI;IACzBf,SAAS,CAAC,MAAM,CAAC;EACnB,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA3B,SAAS,CAAC,MAAM;IACd,IAAIwB,YAAY,EAAE;MAChBsB,cAAc,CAAC,CAAC;IAClB;EACF,CAAC,EAAE,CAACtB,YAAY,EAAEsB,cAAc,CAAC,CAAC;;EAElC;EACA9C,SAAS,CAAC,MAAM;IACd,IAAI,CAACyB,iBAAiB,EAAE;IAExB,MAAMsE,oBAAoB,GAAIC,YAA4B,IAAK;MAC7D,IAAIA,YAAY,KAAK,QAAQ,IAAItE,MAAM,KAAK,MAAM,EAAE;QAClDoB,cAAc,CAAC,CAAC;MAClB;IACF,CAAC;IAED,MAAMmD,YAAY,GAAG/F,QAAQ,CAACgG,gBAAgB,CAAC,QAAQ,EAAEH,oBAAoB,CAAC;IAE9E,OAAO,MAAM;MACXE,YAAY,CAACE,MAAM,CAAC,CAAC;IACvB,CAAC;EACH,CAAC,EAAE,CAAC1E,iBAAiB,EAAEqB,cAAc,EAAEpB,MAAM,CAAC,CAAC;EAE/C,OAAO;IACLA,MAAM;IACNE,UAAU;IACVE,gBAAgB;IAChBE,KAAK;IACLE,cAAc;IACdY,cAAc;IACdiB,cAAc;IACduB,WAAW;IACXM;EACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Main exports
|
|
2
|
+
export { OTAProvider, useOTA, withOTA, UpdateBanner } from './OTAProvider';
|
|
3
|
+
// Hook export
|
|
4
|
+
export { useOTAUpdate } from './hooks/useOTAUpdate';
|
|
5
|
+
// Utilities
|
|
6
|
+
export { OTAApiClient, getDeviceInfo } from './utils/api';
|
|
7
|
+
export { UpdateStorage, getStorageAdapter } from './utils/storage';
|
|
8
|
+
export { calculateHash, verifyBundleHash, verifySignature, verifyBundle } from './utils/verification';
|
|
9
|
+
// Version info
|
|
10
|
+
export const VERSION = '0.1.0';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["OTAProvider","useOTA","withOTA","UpdateBanner","useOTAUpdate","OTAApiClient","getDeviceInfo","UpdateStorage","getStorageAdapter","calculateHash","verifyBundleHash","verifySignature","verifyBundle","VERSION"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA;AACA,SAASA,WAAW,EAAEC,MAAM,EAAEC,OAAO,EAAEC,YAAY,QAAQ,eAAe;AAG1E;AACA,SAASC,YAAY,QAAQ,sBAAsB;AASnD;AACA,SAASC,YAAY,EAAEC,aAAa,QAAQ,aAAa;AAQzD,SAASC,aAAa,EAAEC,iBAAiB,QAAQ,iBAAiB;AAGlE,SACEC,aAAa,EACbC,gBAAgB,EAChBC,eAAe,EACfC,YAAY,QACP,sBAAsB;AAG7B;AACA,OAAO,MAAMC,OAAO,GAAG,OAAO","ignoreList":[]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
export class OTAApiClient {
|
|
3
|
+
constructor(serverUrl) {
|
|
4
|
+
this.serverUrl = serverUrl.replace(/\/$/, ''); // Remove trailing slash
|
|
5
|
+
}
|
|
6
|
+
async checkUpdate(request) {
|
|
7
|
+
const response = await fetch(`${this.serverUrl}/api/v1/check-update`, {
|
|
8
|
+
method: 'POST',
|
|
9
|
+
headers: {
|
|
10
|
+
'Content-Type': 'application/json'
|
|
11
|
+
},
|
|
12
|
+
body: JSON.stringify(request)
|
|
13
|
+
});
|
|
14
|
+
if (!response.ok) {
|
|
15
|
+
const error = await response.json().catch(() => ({
|
|
16
|
+
error: 'Unknown error'
|
|
17
|
+
}));
|
|
18
|
+
throw new Error(error.error || `HTTP ${response.status}`);
|
|
19
|
+
}
|
|
20
|
+
return response.json();
|
|
21
|
+
}
|
|
22
|
+
async reportEvent(request) {
|
|
23
|
+
try {
|
|
24
|
+
await fetch(`${this.serverUrl}/api/v1/report-event`, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/json'
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify(request)
|
|
30
|
+
});
|
|
31
|
+
} catch (error) {
|
|
32
|
+
// Silently fail analytics - don't block the app
|
|
33
|
+
if (__DEV__) {
|
|
34
|
+
console.warn('[OTAUpdate] Failed to report event:', error);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async downloadBundle(bundleUrl) {
|
|
39
|
+
const response = await fetch(bundleUrl);
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new Error(`Failed to download bundle: HTTP ${response.status}`);
|
|
42
|
+
}
|
|
43
|
+
return response.arrayBuffer();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function getDeviceInfo() {
|
|
47
|
+
return {
|
|
48
|
+
os: Platform.OS,
|
|
49
|
+
osVersion: Platform.Version.toString()
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Platform","OTAApiClient","constructor","serverUrl","replace","checkUpdate","request","response","fetch","method","headers","body","JSON","stringify","ok","error","json","catch","Error","status","reportEvent","__DEV__","console","warn","downloadBundle","bundleUrl","arrayBuffer","getDeviceInfo","os","OS","osVersion","Version","toString"],"sourceRoot":"../../../src","sources":["utils/api.ts"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,cAAc;AAyCvC,OAAO,MAAMC,YAAY,CAAC;EAGxBC,WAAWA,CAACC,SAAiB,EAAE;IAC7B,IAAI,CAACA,SAAS,GAAGA,SAAS,CAACC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;EACjD;EAEA,MAAMC,WAAWA,CAACC,OAA2B,EAAgC;IAC3E,MAAMC,QAAQ,GAAG,MAAMC,KAAK,CAAC,GAAG,IAAI,CAACL,SAAS,sBAAsB,EAAE;MACpEM,MAAM,EAAE,MAAM;MACdC,OAAO,EAAE;QACP,cAAc,EAAE;MAClB,CAAC;MACDC,IAAI,EAAEC,IAAI,CAACC,SAAS,CAACP,OAAO;IAC9B,CAAC,CAAC;IAEF,IAAI,CAACC,QAAQ,CAACO,EAAE,EAAE;MAChB,MAAMC,KAAK,GAAG,MAAMR,QAAQ,CAACS,IAAI,CAAC,CAAC,CAACC,KAAK,CAAC,OAAO;QAAEF,KAAK,EAAE;MAAgB,CAAC,CAAC,CAAC;MAC7E,MAAM,IAAIG,KAAK,CAAEH,KAAK,CAAuBA,KAAK,IAAI,QAAQR,QAAQ,CAACY,MAAM,EAAE,CAAC;IAClF;IAEA,OAAOZ,QAAQ,CAACS,IAAI,CAAC,CAAC;EACxB;EAEA,MAAMI,WAAWA,CAACd,OAA2B,EAAiB;IAC5D,IAAI;MACF,MAAME,KAAK,CAAC,GAAG,IAAI,CAACL,SAAS,sBAAsB,EAAE;QACnDM,MAAM,EAAE,MAAM;QACdC,OAAO,EAAE;UACP,cAAc,EAAE;QAClB,CAAC;QACDC,IAAI,EAAEC,IAAI,CAACC,SAAS,CAACP,OAAO;MAC9B,CAAC,CAAC;IACJ,CAAC,CAAC,OAAOS,KAAK,EAAE;MACd;MACA,IAAIM,OAAO,EAAE;QACXC,OAAO,CAACC,IAAI,CAAC,qCAAqC,EAAER,KAAK,CAAC;MAC5D;IACF;EACF;EAEA,MAAMS,cAAcA,CAACC,SAAiB,EAAwB;IAC5D,MAAMlB,QAAQ,GAAG,MAAMC,KAAK,CAACiB,SAAS,CAAC;IAEvC,IAAI,CAAClB,QAAQ,CAACO,EAAE,EAAE;MAChB,MAAM,IAAII,KAAK,CAAC,mCAAmCX,QAAQ,CAACY,MAAM,EAAE,CAAC;IACvE;IAEA,OAAOZ,QAAQ,CAACmB,WAAW,CAAC,CAAC;EAC/B;AACF;AAEA,OAAO,SAASC,aAAaA,CAAA,EAAsC;EACjE,OAAO;IACLC,EAAE,EAAE5B,QAAQ,CAAC6B,EAAE;IACfC,SAAS,EAAE9B,QAAQ,CAAC+B,OAAO,CAACC,QAAQ,CAAC;EACvC,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { NativeModules } from 'react-native';
|
|
2
|
+
|
|
3
|
+
// Types
|
|
4
|
+
|
|
5
|
+
// Try to use Expo FileSystem if available
|
|
6
|
+
let ExpoFileSystem = null;
|
|
7
|
+
try {
|
|
8
|
+
ExpoFileSystem = require('expo-file-system');
|
|
9
|
+
} catch {
|
|
10
|
+
// Expo not available, will use native module
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Native module for bare React Native
|
|
14
|
+
const OTAUpdateNative = NativeModules.OTAUpdate;
|
|
15
|
+
|
|
16
|
+
// Expo implementation
|
|
17
|
+
class ExpoStorageAdapter {
|
|
18
|
+
getDocumentDirectory() {
|
|
19
|
+
return ExpoFileSystem.documentDirectory || '';
|
|
20
|
+
}
|
|
21
|
+
async writeFile(path, data) {
|
|
22
|
+
if (data instanceof ArrayBuffer) {
|
|
23
|
+
// Convert ArrayBuffer to base64
|
|
24
|
+
const bytes = new Uint8Array(data);
|
|
25
|
+
let binary = '';
|
|
26
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
27
|
+
binary += String.fromCharCode(bytes[i]);
|
|
28
|
+
}
|
|
29
|
+
const base64 = btoa(binary);
|
|
30
|
+
await ExpoFileSystem.writeAsStringAsync(path, base64, {
|
|
31
|
+
encoding: ExpoFileSystem.EncodingType.Base64
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
await ExpoFileSystem.writeAsStringAsync(path, data);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async readFile(path) {
|
|
38
|
+
return ExpoFileSystem.readAsStringAsync(path);
|
|
39
|
+
}
|
|
40
|
+
async readFileAsBuffer(path) {
|
|
41
|
+
const base64 = await ExpoFileSystem.readAsStringAsync(path, {
|
|
42
|
+
encoding: ExpoFileSystem.EncodingType.Base64
|
|
43
|
+
});
|
|
44
|
+
const binary = atob(base64);
|
|
45
|
+
const bytes = new Uint8Array(binary.length);
|
|
46
|
+
for (let i = 0; i < binary.length; i++) {
|
|
47
|
+
bytes[i] = binary.charCodeAt(i);
|
|
48
|
+
}
|
|
49
|
+
return bytes.buffer;
|
|
50
|
+
}
|
|
51
|
+
async deleteFile(path) {
|
|
52
|
+
await ExpoFileSystem.deleteAsync(path, {
|
|
53
|
+
idempotent: true
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async exists(path) {
|
|
57
|
+
const info = await ExpoFileSystem.getInfoAsync(path);
|
|
58
|
+
return info.exists;
|
|
59
|
+
}
|
|
60
|
+
async makeDirectory(path) {
|
|
61
|
+
await ExpoFileSystem.makeDirectoryAsync(path, {
|
|
62
|
+
intermediates: true
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Native implementation for bare React Native
|
|
68
|
+
class NativeStorageAdapter {
|
|
69
|
+
getDocumentDirectory() {
|
|
70
|
+
if (!OTAUpdateNative) {
|
|
71
|
+
throw new Error('OTAUpdate native module not found. Did you link the library?');
|
|
72
|
+
}
|
|
73
|
+
return OTAUpdateNative.getDocumentDirectory();
|
|
74
|
+
}
|
|
75
|
+
async writeFile(path, data) {
|
|
76
|
+
if (!OTAUpdateNative) {
|
|
77
|
+
throw new Error('OTAUpdate native module not found');
|
|
78
|
+
}
|
|
79
|
+
if (data instanceof ArrayBuffer) {
|
|
80
|
+
const bytes = new Uint8Array(data);
|
|
81
|
+
let binary = '';
|
|
82
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
83
|
+
binary += String.fromCharCode(bytes[i]);
|
|
84
|
+
}
|
|
85
|
+
const base64 = btoa(binary);
|
|
86
|
+
await OTAUpdateNative.writeFileBase64(path, base64);
|
|
87
|
+
} else {
|
|
88
|
+
await OTAUpdateNative.writeFile(path, data);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async readFile(path) {
|
|
92
|
+
if (!OTAUpdateNative) {
|
|
93
|
+
throw new Error('OTAUpdate native module not found');
|
|
94
|
+
}
|
|
95
|
+
return OTAUpdateNative.readFile(path);
|
|
96
|
+
}
|
|
97
|
+
async readFileAsBuffer(path) {
|
|
98
|
+
if (!OTAUpdateNative) {
|
|
99
|
+
throw new Error('OTAUpdate native module not found');
|
|
100
|
+
}
|
|
101
|
+
const base64 = await OTAUpdateNative.readFileBase64(path);
|
|
102
|
+
const binary = atob(base64);
|
|
103
|
+
const bytes = new Uint8Array(binary.length);
|
|
104
|
+
for (let i = 0; i < binary.length; i++) {
|
|
105
|
+
bytes[i] = binary.charCodeAt(i);
|
|
106
|
+
}
|
|
107
|
+
return bytes.buffer;
|
|
108
|
+
}
|
|
109
|
+
async deleteFile(path) {
|
|
110
|
+
if (!OTAUpdateNative) {
|
|
111
|
+
throw new Error('OTAUpdate native module not found');
|
|
112
|
+
}
|
|
113
|
+
await OTAUpdateNative.deleteFile(path);
|
|
114
|
+
}
|
|
115
|
+
async exists(path) {
|
|
116
|
+
if (!OTAUpdateNative) {
|
|
117
|
+
throw new Error('OTAUpdate native module not found');
|
|
118
|
+
}
|
|
119
|
+
return OTAUpdateNative.exists(path);
|
|
120
|
+
}
|
|
121
|
+
async makeDirectory(path) {
|
|
122
|
+
if (!OTAUpdateNative) {
|
|
123
|
+
throw new Error('OTAUpdate native module not found');
|
|
124
|
+
}
|
|
125
|
+
await OTAUpdateNative.makeDirectory(path);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Factory function to get the appropriate storage adapter
|
|
130
|
+
export function getStorageAdapter() {
|
|
131
|
+
if (ExpoFileSystem) {
|
|
132
|
+
return new ExpoStorageAdapter();
|
|
133
|
+
}
|
|
134
|
+
if (OTAUpdateNative) {
|
|
135
|
+
return new NativeStorageAdapter();
|
|
136
|
+
}
|
|
137
|
+
throw new Error('No storage adapter available. Install expo-file-system or link the OTAUpdate native module.');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Update storage manager
|
|
141
|
+
export class UpdateStorage {
|
|
142
|
+
constructor() {
|
|
143
|
+
this.storage = getStorageAdapter();
|
|
144
|
+
this.baseDir = `${this.storage.getDocumentDirectory()}ota-update/`;
|
|
145
|
+
}
|
|
146
|
+
async ensureDirectory() {
|
|
147
|
+
const exists = await this.storage.exists(this.baseDir);
|
|
148
|
+
if (!exists) {
|
|
149
|
+
await this.storage.makeDirectory(this.baseDir);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async saveBundle(releaseId, data) {
|
|
153
|
+
await this.ensureDirectory();
|
|
154
|
+
const bundlePath = `${this.baseDir}${releaseId}.bundle`;
|
|
155
|
+
await this.storage.writeFile(bundlePath, data);
|
|
156
|
+
return bundlePath;
|
|
157
|
+
}
|
|
158
|
+
async getBundlePath(releaseId) {
|
|
159
|
+
const bundlePath = `${this.baseDir}${releaseId}.bundle`;
|
|
160
|
+
const exists = await this.storage.exists(bundlePath);
|
|
161
|
+
return exists ? bundlePath : null;
|
|
162
|
+
}
|
|
163
|
+
async readBundle(releaseId) {
|
|
164
|
+
const bundlePath = await this.getBundlePath(releaseId);
|
|
165
|
+
if (!bundlePath) return null;
|
|
166
|
+
return this.storage.readFileAsBuffer(bundlePath);
|
|
167
|
+
}
|
|
168
|
+
async deleteBundle(releaseId) {
|
|
169
|
+
const bundlePath = `${this.baseDir}${releaseId}.bundle`;
|
|
170
|
+
if (await this.storage.exists(bundlePath)) {
|
|
171
|
+
await this.storage.deleteFile(bundlePath);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async saveMetadata(update) {
|
|
175
|
+
await this.ensureDirectory();
|
|
176
|
+
const metadataPath = `${this.baseDir}current.json`;
|
|
177
|
+
await this.storage.writeFile(metadataPath, JSON.stringify(update));
|
|
178
|
+
}
|
|
179
|
+
async getMetadata() {
|
|
180
|
+
const metadataPath = `${this.baseDir}current.json`;
|
|
181
|
+
try {
|
|
182
|
+
if (await this.storage.exists(metadataPath)) {
|
|
183
|
+
const content = await this.storage.readFile(metadataPath);
|
|
184
|
+
return JSON.parse(content);
|
|
185
|
+
}
|
|
186
|
+
} catch {
|
|
187
|
+
// Corrupted metadata, return null
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
async clearMetadata() {
|
|
192
|
+
const metadataPath = `${this.baseDir}current.json`;
|
|
193
|
+
if (await this.storage.exists(metadataPath)) {
|
|
194
|
+
await this.storage.deleteFile(metadataPath);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async cleanOldBundles(keepReleaseId) {
|
|
198
|
+
// For now, we just keep one bundle at a time
|
|
199
|
+
// In a more advanced implementation, we might keep a few for rollback
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeModules","ExpoFileSystem","require","OTAUpdateNative","OTAUpdate","ExpoStorageAdapter","getDocumentDirectory","documentDirectory","writeFile","path","data","ArrayBuffer","bytes","Uint8Array","binary","i","length","String","fromCharCode","base64","btoa","writeAsStringAsync","encoding","EncodingType","Base64","readFile","readAsStringAsync","readFileAsBuffer","atob","charCodeAt","buffer","deleteFile","deleteAsync","idempotent","exists","info","getInfoAsync","makeDirectory","makeDirectoryAsync","intermediates","NativeStorageAdapter","Error","writeFileBase64","readFileBase64","getStorageAdapter","UpdateStorage","constructor","storage","baseDir","ensureDirectory","saveBundle","releaseId","bundlePath","getBundlePath","readBundle","deleteBundle","saveMetadata","update","metadataPath","JSON","stringify","getMetadata","content","parse","clearMetadata","cleanOldBundles","keepReleaseId"],"sourceRoot":"../../../src","sources":["utils/storage.ts"],"mappings":"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","ignoreList":[]}
|