@swiftpatch/react-native 2.0.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 +430 -0
- package/android/build.gradle +105 -0
- package/android/src/main/AndroidManifest.xml +6 -0
- package/android/src/main/java/com/swiftpatch/BundleManager.kt +107 -0
- package/android/src/main/java/com/swiftpatch/CrashDetector.kt +79 -0
- package/android/src/main/java/com/swiftpatch/CryptoVerifier.kt +69 -0
- package/android/src/main/java/com/swiftpatch/DownloadManager.kt +120 -0
- package/android/src/main/java/com/swiftpatch/EventQueue.kt +86 -0
- package/android/src/main/java/com/swiftpatch/FileUtils.kt +60 -0
- package/android/src/main/java/com/swiftpatch/PatchApplier.kt +60 -0
- package/android/src/main/java/com/swiftpatch/SignalCrashHandler.kt +84 -0
- package/android/src/main/java/com/swiftpatch/SlotManager.kt +299 -0
- package/android/src/main/java/com/swiftpatch/SwiftPatchModule.kt +630 -0
- package/android/src/main/java/com/swiftpatch/SwiftPatchPackage.kt +21 -0
- package/android/src/main/jni/CMakeLists.txt +12 -0
- package/android/src/main/jni/bspatch.c +188 -0
- package/android/src/main/jni/bspatch.h +57 -0
- package/android/src/main/jni/bspatch_jni.c +28 -0
- package/ios/Libraries/bspatch/bspatch.c +188 -0
- package/ios/Libraries/bspatch/bspatch.h +50 -0
- package/ios/Libraries/bspatch/module.modulemap +4 -0
- package/ios/SwiftPatch/BundleManager.swift +113 -0
- package/ios/SwiftPatch/CrashDetector.swift +71 -0
- package/ios/SwiftPatch/CryptoVerifier.swift +70 -0
- package/ios/SwiftPatch/DownloadManager.swift +125 -0
- package/ios/SwiftPatch/EventQueue.swift +116 -0
- package/ios/SwiftPatch/FileUtils.swift +38 -0
- package/ios/SwiftPatch/PatchApplier.swift +41 -0
- package/ios/SwiftPatch/SignalCrashHandler.swift +129 -0
- package/ios/SwiftPatch/SlotManager.swift +360 -0
- package/ios/SwiftPatch/SwiftPatchModule.m +56 -0
- package/ios/SwiftPatch/SwiftPatchModule.swift +621 -0
- package/lib/commonjs/SwiftPatchCore.js +140 -0
- package/lib/commonjs/SwiftPatchCore.js.map +1 -0
- package/lib/commonjs/SwiftPatchProvider.js +617 -0
- package/lib/commonjs/SwiftPatchProvider.js.map +1 -0
- package/lib/commonjs/constants.js +50 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/core/Downloader.js +63 -0
- package/lib/commonjs/core/Downloader.js.map +1 -0
- package/lib/commonjs/core/Installer.js +46 -0
- package/lib/commonjs/core/Installer.js.map +1 -0
- package/lib/commonjs/core/Rollback.js +36 -0
- package/lib/commonjs/core/Rollback.js.map +1 -0
- package/lib/commonjs/core/UpdateChecker.js +57 -0
- package/lib/commonjs/core/UpdateChecker.js.map +1 -0
- package/lib/commonjs/core/Verifier.js +82 -0
- package/lib/commonjs/core/Verifier.js.map +1 -0
- package/lib/commonjs/core/index.js +41 -0
- package/lib/commonjs/core/index.js.map +1 -0
- package/lib/commonjs/index.js +154 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/modal/SwiftPatchModal.js +667 -0
- package/lib/commonjs/modal/SwiftPatchModal.js.map +1 -0
- package/lib/commonjs/modal/useSwiftPatchModal.js +26 -0
- package/lib/commonjs/modal/useSwiftPatchModal.js.map +1 -0
- package/lib/commonjs/native/NativeSwiftPatch.js +85 -0
- package/lib/commonjs/native/NativeSwiftPatch.js.map +1 -0
- package/lib/commonjs/native/NativeSwiftPatchSpec.js +15 -0
- package/lib/commonjs/native/NativeSwiftPatchSpec.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types.js +126 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/useSwiftPatch.js +31 -0
- package/lib/commonjs/useSwiftPatch.js.map +1 -0
- package/lib/commonjs/utils/api.js +206 -0
- package/lib/commonjs/utils/api.js.map +1 -0
- package/lib/commonjs/utils/device.js +23 -0
- package/lib/commonjs/utils/device.js.map +1 -0
- package/lib/commonjs/utils/logger.js +30 -0
- package/lib/commonjs/utils/logger.js.map +1 -0
- package/lib/commonjs/utils/storage.js +31 -0
- package/lib/commonjs/utils/storage.js.map +1 -0
- package/lib/commonjs/withSwiftPatch.js +42 -0
- package/lib/commonjs/withSwiftPatch.js.map +1 -0
- package/lib/module/SwiftPatchCore.js +135 -0
- package/lib/module/SwiftPatchCore.js.map +1 -0
- package/lib/module/SwiftPatchProvider.js +611 -0
- package/lib/module/SwiftPatchProvider.js.map +1 -0
- package/lib/module/constants.js +46 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/core/Downloader.js +57 -0
- package/lib/module/core/Downloader.js.map +1 -0
- package/lib/module/core/Installer.js +41 -0
- package/lib/module/core/Installer.js.map +1 -0
- package/lib/module/core/Rollback.js +31 -0
- package/lib/module/core/Rollback.js.map +1 -0
- package/lib/module/core/UpdateChecker.js +51 -0
- package/lib/module/core/UpdateChecker.js.map +1 -0
- package/lib/module/core/Verifier.js +76 -0
- package/lib/module/core/Verifier.js.map +1 -0
- package/lib/module/core/index.js +8 -0
- package/lib/module/core/index.js.map +1 -0
- package/lib/module/index.js +34 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/modal/SwiftPatchModal.js +661 -0
- package/lib/module/modal/SwiftPatchModal.js.map +1 -0
- package/lib/module/modal/useSwiftPatchModal.js +22 -0
- package/lib/module/modal/useSwiftPatchModal.js.map +1 -0
- package/lib/module/native/NativeSwiftPatch.js +78 -0
- package/lib/module/native/NativeSwiftPatch.js.map +1 -0
- package/lib/module/native/NativeSwiftPatchSpec.js +12 -0
- package/lib/module/native/NativeSwiftPatchSpec.js.map +1 -0
- package/lib/module/types.js +139 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/useSwiftPatch.js +26 -0
- package/lib/module/useSwiftPatch.js.map +1 -0
- package/lib/module/utils/api.js +197 -0
- package/lib/module/utils/api.js.map +1 -0
- package/lib/module/utils/device.js +18 -0
- package/lib/module/utils/device.js.map +1 -0
- package/lib/module/utils/logger.js +26 -0
- package/lib/module/utils/logger.js.map +1 -0
- package/lib/module/utils/storage.js +24 -0
- package/lib/module/utils/storage.js.map +1 -0
- package/lib/module/withSwiftPatch.js +37 -0
- package/lib/module/withSwiftPatch.js.map +1 -0
- package/lib/typescript/SwiftPatchCore.d.ts +64 -0
- package/lib/typescript/SwiftPatchCore.d.ts.map +1 -0
- package/lib/typescript/SwiftPatchProvider.d.ts +22 -0
- package/lib/typescript/SwiftPatchProvider.d.ts.map +1 -0
- package/lib/typescript/constants.d.ts +33 -0
- package/lib/typescript/constants.d.ts.map +1 -0
- package/lib/typescript/core/Downloader.d.ts +34 -0
- package/lib/typescript/core/Downloader.d.ts.map +1 -0
- package/lib/typescript/core/Installer.d.ts +25 -0
- package/lib/typescript/core/Installer.d.ts.map +1 -0
- package/lib/typescript/core/Rollback.d.ts +18 -0
- package/lib/typescript/core/Rollback.d.ts.map +1 -0
- package/lib/typescript/core/UpdateChecker.d.ts +27 -0
- package/lib/typescript/core/UpdateChecker.d.ts.map +1 -0
- package/lib/typescript/core/Verifier.d.ts +31 -0
- package/lib/typescript/core/Verifier.d.ts.map +1 -0
- package/lib/typescript/core/index.d.ts +8 -0
- package/lib/typescript/core/index.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +13 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/modal/SwiftPatchModal.d.ts +11 -0
- package/lib/typescript/modal/SwiftPatchModal.d.ts.map +1 -0
- package/lib/typescript/modal/useSwiftPatchModal.d.ts +7 -0
- package/lib/typescript/modal/useSwiftPatchModal.d.ts.map +1 -0
- package/lib/typescript/native/NativeSwiftPatch.d.ts +61 -0
- package/lib/typescript/native/NativeSwiftPatch.d.ts.map +1 -0
- package/lib/typescript/native/NativeSwiftPatchSpec.d.ts +67 -0
- package/lib/typescript/native/NativeSwiftPatchSpec.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +266 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/lib/typescript/useSwiftPatch.d.ts +12 -0
- package/lib/typescript/useSwiftPatch.d.ts.map +1 -0
- package/lib/typescript/utils/api.d.ts +87 -0
- package/lib/typescript/utils/api.d.ts.map +1 -0
- package/lib/typescript/utils/device.d.ts +9 -0
- package/lib/typescript/utils/device.d.ts.map +1 -0
- package/lib/typescript/utils/logger.d.ts +8 -0
- package/lib/typescript/utils/logger.d.ts.map +1 -0
- package/lib/typescript/utils/storage.d.ts +14 -0
- package/lib/typescript/utils/storage.d.ts.map +1 -0
- package/lib/typescript/withSwiftPatch.d.ts +12 -0
- package/lib/typescript/withSwiftPatch.d.ts.map +1 -0
- package/package.json +99 -0
- package/react-native-swiftpatch.podspec +50 -0
- package/src/SwiftPatchCore.ts +148 -0
- package/src/SwiftPatchProvider.tsx +514 -0
- package/src/constants.ts +49 -0
- package/src/core/Downloader.ts +74 -0
- package/src/core/Installer.ts +38 -0
- package/src/core/Rollback.ts +28 -0
- package/src/core/UpdateChecker.ts +70 -0
- package/src/core/Verifier.ts +92 -0
- package/src/core/index.ts +11 -0
- package/src/index.ts +64 -0
- package/src/modal/SwiftPatchModal.tsx +657 -0
- package/src/modal/useSwiftPatchModal.ts +24 -0
- package/src/native/NativeSwiftPatch.ts +205 -0
- package/src/native/NativeSwiftPatchSpec.ts +139 -0
- package/src/types.ts +336 -0
- package/src/useSwiftPatch.ts +29 -0
- package/src/utils/api.ts +244 -0
- package/src/utils/device.ts +15 -0
- package/src/utils/logger.ts +29 -0
- package/src/utils/storage.ts +23 -0
- package/src/withSwiftPatch.tsx +41 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import NativeSwiftPatch from './native/NativeSwiftPatch';
|
|
2
|
+
import { reportInstallStatus } from './utils/api';
|
|
3
|
+
import { logger } from './utils/logger';
|
|
4
|
+
import { UpdateChecker } from './core/UpdateChecker';
|
|
5
|
+
import { Downloader } from './core/Downloader';
|
|
6
|
+
import { Installer } from './core/Installer';
|
|
7
|
+
import { Rollback as RollbackModule } from './core/Rollback';
|
|
8
|
+
import type {
|
|
9
|
+
SwiftPatchConfig,
|
|
10
|
+
ReleaseInfo,
|
|
11
|
+
BundleInfo,
|
|
12
|
+
} from './types';
|
|
13
|
+
import { DEFAULT_CONFIG } from './constants';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Imperative API for SwiftPatch (non-React usage).
|
|
17
|
+
*
|
|
18
|
+
* Use this when you need to interact with SwiftPatch outside of
|
|
19
|
+
* React components, such as in native module callbacks or background tasks.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { SwiftPatch } from '@orbitplus/react-native';
|
|
24
|
+
*
|
|
25
|
+
* const sp = new SwiftPatch({ deploymentKey: 'your-key' });
|
|
26
|
+
* await sp.init();
|
|
27
|
+
* const update = await sp.checkForUpdate();
|
|
28
|
+
* if (update) {
|
|
29
|
+
* await sp.downloadAndInstall(update);
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class SwiftPatch {
|
|
34
|
+
private config: Required<Omit<SwiftPatchConfig, 'customHeaders' | 'publicKey'>> & {
|
|
35
|
+
customHeaders: Record<string, string>;
|
|
36
|
+
publicKey: string | null;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
private updateChecker!: UpdateChecker;
|
|
40
|
+
private downloader!: Downloader;
|
|
41
|
+
private installer!: Installer;
|
|
42
|
+
private rollbackModule!: RollbackModule;
|
|
43
|
+
|
|
44
|
+
constructor(userConfig: SwiftPatchConfig) {
|
|
45
|
+
this.config = { ...DEFAULT_CONFIG, ...userConfig } as typeof this.config;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Initialize the native module
|
|
50
|
+
*/
|
|
51
|
+
async init(): Promise<void> {
|
|
52
|
+
await NativeSwiftPatch.initialize({
|
|
53
|
+
deploymentKey: this.config.deploymentKey,
|
|
54
|
+
serverUrl: this.config.serverUrl,
|
|
55
|
+
publicKey: this.config.publicKey,
|
|
56
|
+
});
|
|
57
|
+
NativeSwiftPatch.setDebugMode(this.config.debug);
|
|
58
|
+
logger.setDebug(this.config.debug);
|
|
59
|
+
|
|
60
|
+
// Initialize core modules
|
|
61
|
+
this.updateChecker = new UpdateChecker({
|
|
62
|
+
serverUrl: this.config.serverUrl,
|
|
63
|
+
deploymentKey: this.config.deploymentKey,
|
|
64
|
+
customHeaders: this.config.customHeaders,
|
|
65
|
+
});
|
|
66
|
+
this.downloader = new Downloader();
|
|
67
|
+
this.installer = new Installer();
|
|
68
|
+
this.rollbackModule = new RollbackModule();
|
|
69
|
+
|
|
70
|
+
logger.info('SwiftPatch initialized (imperative)');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Check for an available update
|
|
75
|
+
*/
|
|
76
|
+
async checkForUpdate(): Promise<ReleaseInfo | null> {
|
|
77
|
+
const result = await this.updateChecker.check();
|
|
78
|
+
|
|
79
|
+
if (result.updateAvailable && result.release) {
|
|
80
|
+
return result.release;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Download an update
|
|
87
|
+
*/
|
|
88
|
+
async download(release: ReleaseInfo): Promise<void> {
|
|
89
|
+
await this.downloader.downloadRelease(release);
|
|
90
|
+
|
|
91
|
+
await reportInstallStatus({
|
|
92
|
+
serverUrl: this.config.serverUrl,
|
|
93
|
+
releaseId: release.id,
|
|
94
|
+
status: 'downloaded',
|
|
95
|
+
deploymentKey: this.config.deploymentKey,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Install a downloaded update
|
|
101
|
+
*/
|
|
102
|
+
async install(release: ReleaseInfo): Promise<void> {
|
|
103
|
+
await this.installer.install(release.bundleHash);
|
|
104
|
+
|
|
105
|
+
await reportInstallStatus({
|
|
106
|
+
serverUrl: this.config.serverUrl,
|
|
107
|
+
releaseId: release.id,
|
|
108
|
+
status: 'installed',
|
|
109
|
+
deploymentKey: this.config.deploymentKey,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Download and install an update in one call
|
|
115
|
+
*/
|
|
116
|
+
async downloadAndInstall(release: ReleaseInfo): Promise<void> {
|
|
117
|
+
await this.download(release);
|
|
118
|
+
await this.install(release);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Restart the app to apply the update
|
|
123
|
+
*/
|
|
124
|
+
restart(): void {
|
|
125
|
+
NativeSwiftPatch.restart();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Rollback to the previous bundle
|
|
130
|
+
*/
|
|
131
|
+
async rollback(): Promise<void> {
|
|
132
|
+
await this.rollbackModule.rollback();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get current bundle info
|
|
137
|
+
*/
|
|
138
|
+
async getCurrentBundle(): Promise<BundleInfo | null> {
|
|
139
|
+
return NativeSwiftPatch.getCurrentBundle();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Clear any pending update
|
|
144
|
+
*/
|
|
145
|
+
async clearPendingUpdate(): Promise<void> {
|
|
146
|
+
await this.rollbackModule.clearPending();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useReducer,
|
|
6
|
+
useCallback,
|
|
7
|
+
useRef,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import { AppState, type AppStateStatus } from 'react-native';
|
|
11
|
+
import type {
|
|
12
|
+
SwiftPatchConfig,
|
|
13
|
+
SwiftPatchState,
|
|
14
|
+
SwiftPatchActions,
|
|
15
|
+
ReleaseInfo,
|
|
16
|
+
UpdateStatus,
|
|
17
|
+
SwiftPatchError,
|
|
18
|
+
DownloadProgress,
|
|
19
|
+
SlotMetadata,
|
|
20
|
+
BundleInfo,
|
|
21
|
+
} from './types';
|
|
22
|
+
import {
|
|
23
|
+
UpdateStatus as Status,
|
|
24
|
+
InstallMode,
|
|
25
|
+
SwiftPatchErrorCode,
|
|
26
|
+
EnvironmentMode,
|
|
27
|
+
} from './types';
|
|
28
|
+
import { DEFAULT_CONFIG, EVENT_POLL_INTERVAL_MS } from './constants';
|
|
29
|
+
import NativeSwiftPatch, {
|
|
30
|
+
onDownloadProgress,
|
|
31
|
+
onRollback,
|
|
32
|
+
onVersionChanged,
|
|
33
|
+
} from './native/NativeSwiftPatch';
|
|
34
|
+
import { reportInstallStatus, logBulkEvents } from './utils/api';
|
|
35
|
+
import { logger } from './utils/logger';
|
|
36
|
+
import { UpdateChecker } from './core/UpdateChecker';
|
|
37
|
+
import { Downloader } from './core/Downloader';
|
|
38
|
+
import { Installer } from './core/Installer';
|
|
39
|
+
import { Rollback as RollbackModule } from './core/Rollback';
|
|
40
|
+
|
|
41
|
+
// Context
|
|
42
|
+
interface SwiftPatchContextValue extends SwiftPatchState, SwiftPatchActions {}
|
|
43
|
+
|
|
44
|
+
const SwiftPatchContext = createContext<SwiftPatchContextValue | null>(null);
|
|
45
|
+
|
|
46
|
+
// State reducer
|
|
47
|
+
type Action =
|
|
48
|
+
| { type: 'SET_STATUS'; payload: UpdateStatus }
|
|
49
|
+
| { type: 'SET_DOWNLOAD_PROGRESS'; payload: DownloadProgress | null }
|
|
50
|
+
| { type: 'SET_AVAILABLE_UPDATE'; payload: ReleaseInfo | null }
|
|
51
|
+
| { type: 'SET_ERROR'; payload: SwiftPatchError | null }
|
|
52
|
+
| { type: 'SET_RESTART_REQUIRED'; payload: boolean }
|
|
53
|
+
| { type: 'SET_LAST_CHECKED'; payload: Date }
|
|
54
|
+
| { type: 'SET_CURRENT_BUNDLE'; payload: BundleInfo | null }
|
|
55
|
+
| { type: 'SET_SLOT_METADATA'; payload: SlotMetadata | null }
|
|
56
|
+
| { type: 'SET_ENVIRONMENT'; payload: EnvironmentMode };
|
|
57
|
+
|
|
58
|
+
function reducer(state: SwiftPatchState, action: Action): SwiftPatchState {
|
|
59
|
+
switch (action.type) {
|
|
60
|
+
case 'SET_STATUS':
|
|
61
|
+
return { ...state, status: action.payload };
|
|
62
|
+
case 'SET_DOWNLOAD_PROGRESS':
|
|
63
|
+
return { ...state, downloadProgress: action.payload };
|
|
64
|
+
case 'SET_AVAILABLE_UPDATE':
|
|
65
|
+
return { ...state, availableUpdate: action.payload };
|
|
66
|
+
case 'SET_ERROR':
|
|
67
|
+
return {
|
|
68
|
+
...state,
|
|
69
|
+
error: action.payload,
|
|
70
|
+
status: action.payload ? Status.ERROR : state.status,
|
|
71
|
+
};
|
|
72
|
+
case 'SET_RESTART_REQUIRED':
|
|
73
|
+
return { ...state, isRestartRequired: action.payload };
|
|
74
|
+
case 'SET_LAST_CHECKED':
|
|
75
|
+
return { ...state, lastCheckedAt: action.payload };
|
|
76
|
+
case 'SET_CURRENT_BUNDLE':
|
|
77
|
+
return { ...state, currentBundle: action.payload };
|
|
78
|
+
case 'SET_SLOT_METADATA':
|
|
79
|
+
return { ...state, slotMetadata: action.payload };
|
|
80
|
+
case 'SET_ENVIRONMENT':
|
|
81
|
+
return { ...state, environment: action.payload };
|
|
82
|
+
default:
|
|
83
|
+
return state;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const initialState: SwiftPatchState = {
|
|
88
|
+
status: Status.UP_TO_DATE,
|
|
89
|
+
downloadProgress: null,
|
|
90
|
+
currentBundle: null,
|
|
91
|
+
availableUpdate: null,
|
|
92
|
+
isRestartRequired: false,
|
|
93
|
+
error: null,
|
|
94
|
+
lastCheckedAt: null,
|
|
95
|
+
slotMetadata: null,
|
|
96
|
+
environment: EnvironmentMode.PRODUCTION,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Provider Props
|
|
100
|
+
interface SwiftPatchProviderProps {
|
|
101
|
+
config: SwiftPatchConfig;
|
|
102
|
+
children: ReactNode;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* SwiftPatch Provider Component
|
|
107
|
+
*
|
|
108
|
+
* Wrap your app with this provider to enable OTA updates
|
|
109
|
+
* with dual-slot architecture, crash detection, and event analytics.
|
|
110
|
+
*/
|
|
111
|
+
export function SwiftPatchProvider({
|
|
112
|
+
config,
|
|
113
|
+
children,
|
|
114
|
+
}: SwiftPatchProviderProps) {
|
|
115
|
+
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
116
|
+
const [state, dispatch] = useReducer(reducer, initialState);
|
|
117
|
+
const lastCheckRef = useRef<number>(0);
|
|
118
|
+
const isCheckingRef = useRef<boolean>(false);
|
|
119
|
+
const configRef = useRef(mergedConfig);
|
|
120
|
+
configRef.current = mergedConfig;
|
|
121
|
+
|
|
122
|
+
// Core modules refs
|
|
123
|
+
const updateCheckerRef = useRef<UpdateChecker | null>(null);
|
|
124
|
+
const downloaderRef = useRef<Downloader | null>(null);
|
|
125
|
+
const installerRef = useRef<Installer | null>(null);
|
|
126
|
+
const rollbackModuleRef = useRef<RollbackModule | null>(null);
|
|
127
|
+
const eventPollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
128
|
+
|
|
129
|
+
// Initialize native module and core modules
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const init = async () => {
|
|
132
|
+
try {
|
|
133
|
+
await NativeSwiftPatch.initialize({
|
|
134
|
+
deploymentKey: mergedConfig.deploymentKey,
|
|
135
|
+
serverUrl: mergedConfig.serverUrl!,
|
|
136
|
+
publicKey: mergedConfig.publicKey || null,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
NativeSwiftPatch.setDebugMode(mergedConfig.debug || false);
|
|
140
|
+
logger.setDebug(mergedConfig.debug || false);
|
|
141
|
+
|
|
142
|
+
// Mark app as mounted (for signal crash detection)
|
|
143
|
+
await NativeSwiftPatch.markMounted();
|
|
144
|
+
|
|
145
|
+
// Initialize core modules
|
|
146
|
+
updateCheckerRef.current = new UpdateChecker({
|
|
147
|
+
serverUrl: mergedConfig.serverUrl!,
|
|
148
|
+
deploymentKey: mergedConfig.deploymentKey,
|
|
149
|
+
customHeaders: mergedConfig.customHeaders,
|
|
150
|
+
});
|
|
151
|
+
downloaderRef.current = new Downloader();
|
|
152
|
+
installerRef.current = new Installer();
|
|
153
|
+
rollbackModuleRef.current = new RollbackModule();
|
|
154
|
+
|
|
155
|
+
// Get current bundle info
|
|
156
|
+
const currentBundle = await NativeSwiftPatch.getCurrentBundle();
|
|
157
|
+
if (currentBundle) {
|
|
158
|
+
dispatch({ type: 'SET_CURRENT_BUNDLE', payload: currentBundle });
|
|
159
|
+
dispatch({ type: 'SET_STATUS', payload: Status.UP_TO_DATE });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Get slot metadata
|
|
163
|
+
const metadata = await NativeSwiftPatch.getSlotMetadata();
|
|
164
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: metadata });
|
|
165
|
+
dispatch({
|
|
166
|
+
type: 'SET_ENVIRONMENT',
|
|
167
|
+
payload: metadata.environment,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Check for pending install (temp hash set)
|
|
171
|
+
const hasPending = await NativeSwiftPatch.hasPendingInstall();
|
|
172
|
+
if (hasPending) {
|
|
173
|
+
dispatch({ type: 'SET_RESTART_REQUIRED', payload: true });
|
|
174
|
+
dispatch({ type: 'SET_STATUS', payload: Status.RESTART_REQUIRED });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Record successful launch & auto-stabilize
|
|
178
|
+
if (currentBundle && !currentBundle.isOriginal) {
|
|
179
|
+
const launchCount = await NativeSwiftPatch.recordSuccessfulLaunch(currentBundle.hash);
|
|
180
|
+
const autoStabilizeThreshold = mergedConfig.autoStabilizeAfterLaunches || 0;
|
|
181
|
+
if (autoStabilizeThreshold > 0 && launchCount >= autoStabilizeThreshold) {
|
|
182
|
+
if (metadata.prod.currentSlot === 'NEW_SLOT') {
|
|
183
|
+
try {
|
|
184
|
+
await NativeSwiftPatch.stabilize();
|
|
185
|
+
const updatedMeta = await NativeSwiftPatch.getSlotMetadata();
|
|
186
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: updatedMeta });
|
|
187
|
+
logger.info('Auto-stabilized after', launchCount, 'successful launches');
|
|
188
|
+
} catch (_e) {
|
|
189
|
+
logger.warn('Auto-stabilization failed');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
logger.info('SwiftPatch initialized (v2.0.0 with dual-slot architecture)');
|
|
196
|
+
} catch (error: unknown) {
|
|
197
|
+
const message = error instanceof Error ? error.message : 'Unknown initialization error';
|
|
198
|
+
logger.error('Failed to initialize SwiftPatch', error);
|
|
199
|
+
dispatch({
|
|
200
|
+
type: 'SET_ERROR',
|
|
201
|
+
payload: { code: SwiftPatchErrorCode.CONFIG_ERROR, message },
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
init();
|
|
207
|
+
|
|
208
|
+
// Cleanup mount state on unmount
|
|
209
|
+
return () => {
|
|
210
|
+
NativeSwiftPatch.markUnmounted().catch(() => {});
|
|
211
|
+
};
|
|
212
|
+
}, [mergedConfig.deploymentKey, mergedConfig.serverUrl, mergedConfig.publicKey, mergedConfig.debug, mergedConfig.autoStabilizeAfterLaunches]);
|
|
213
|
+
|
|
214
|
+
// Event queue polling
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
const pollEvents = async () => {
|
|
217
|
+
try {
|
|
218
|
+
const events = await NativeSwiftPatch.popEvents();
|
|
219
|
+
if (events && events.length > 0) {
|
|
220
|
+
const deviceId = await NativeSwiftPatch.getDeviceId();
|
|
221
|
+
const cfg = configRef.current;
|
|
222
|
+
|
|
223
|
+
const result = await logBulkEvents({
|
|
224
|
+
serverUrl: cfg.serverUrl!,
|
|
225
|
+
deploymentKey: cfg.deploymentKey,
|
|
226
|
+
deviceId,
|
|
227
|
+
events: events as any,
|
|
228
|
+
customHeaders: cfg.customHeaders,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
if (result.acknowledged.length > 0) {
|
|
232
|
+
await NativeSwiftPatch.acknowledgeEvents(
|
|
233
|
+
JSON.stringify(result.acknowledged)
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch (_e) {
|
|
238
|
+
// Silent - event polling is non-critical
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
eventPollIntervalRef.current = setInterval(pollEvents, EVENT_POLL_INTERVAL_MS);
|
|
243
|
+
|
|
244
|
+
return () => {
|
|
245
|
+
if (eventPollIntervalRef.current) {
|
|
246
|
+
clearInterval(eventPollIntervalRef.current);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}, []);
|
|
250
|
+
|
|
251
|
+
// Subscribe to download progress
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
const unsubscribe = onDownloadProgress((progress) => {
|
|
254
|
+
dispatch({ type: 'SET_DOWNLOAD_PROGRESS', payload: progress });
|
|
255
|
+
});
|
|
256
|
+
return unsubscribe;
|
|
257
|
+
}, []);
|
|
258
|
+
|
|
259
|
+
// Subscribe to rollback events
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
const unsubscribe = onRollback((reason) => {
|
|
262
|
+
logger.warn('Rollback occurred:', reason);
|
|
263
|
+
dispatch({ type: 'SET_STATUS', payload: Status.UP_TO_DATE });
|
|
264
|
+
dispatch({ type: 'SET_AVAILABLE_UPDATE', payload: null });
|
|
265
|
+
dispatch({ type: 'SET_RESTART_REQUIRED', payload: false });
|
|
266
|
+
// Refresh metadata
|
|
267
|
+
NativeSwiftPatch.getSlotMetadata().then((meta) => {
|
|
268
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: meta });
|
|
269
|
+
}).catch(() => {});
|
|
270
|
+
});
|
|
271
|
+
return unsubscribe;
|
|
272
|
+
}, []);
|
|
273
|
+
|
|
274
|
+
// Subscribe to version change events
|
|
275
|
+
useEffect(() => {
|
|
276
|
+
const unsubscribe = onVersionChanged((reason) => {
|
|
277
|
+
logger.info('Version changed:', reason);
|
|
278
|
+
dispatch({ type: 'SET_STATUS', payload: Status.UP_TO_DATE });
|
|
279
|
+
dispatch({ type: 'SET_AVAILABLE_UPDATE', payload: null });
|
|
280
|
+
dispatch({ type: 'SET_RESTART_REQUIRED', payload: false });
|
|
281
|
+
NativeSwiftPatch.getSlotMetadata().then((meta) => {
|
|
282
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: meta });
|
|
283
|
+
}).catch(() => {});
|
|
284
|
+
});
|
|
285
|
+
return unsubscribe;
|
|
286
|
+
}, []);
|
|
287
|
+
|
|
288
|
+
// Check for update
|
|
289
|
+
const checkForUpdate = useCallback(async (): Promise<ReleaseInfo | null> => {
|
|
290
|
+
if (isCheckingRef.current) return null;
|
|
291
|
+
if (!updateCheckerRef.current) return null;
|
|
292
|
+
|
|
293
|
+
isCheckingRef.current = true;
|
|
294
|
+
dispatch({ type: 'SET_STATUS', payload: Status.CHECKING });
|
|
295
|
+
dispatch({ type: 'SET_ERROR', payload: null });
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
const result = await updateCheckerRef.current.check();
|
|
299
|
+
lastCheckRef.current = Date.now();
|
|
300
|
+
dispatch({ type: 'SET_LAST_CHECKED', payload: new Date() });
|
|
301
|
+
|
|
302
|
+
if (result.updateAvailable && result.release) {
|
|
303
|
+
dispatch({ type: 'SET_AVAILABLE_UPDATE', payload: result.release });
|
|
304
|
+
dispatch({ type: 'SET_STATUS', payload: Status.UPDATE_AVAILABLE });
|
|
305
|
+
return result.release;
|
|
306
|
+
} else {
|
|
307
|
+
dispatch({ type: 'SET_STATUS', payload: Status.UP_TO_DATE });
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
} catch (error: unknown) {
|
|
311
|
+
const message = error instanceof Error ? error.message : 'Failed to check for update';
|
|
312
|
+
dispatch({
|
|
313
|
+
type: 'SET_ERROR',
|
|
314
|
+
payload: { code: SwiftPatchErrorCode.NETWORK_ERROR, message },
|
|
315
|
+
});
|
|
316
|
+
return null;
|
|
317
|
+
} finally {
|
|
318
|
+
isCheckingRef.current = false;
|
|
319
|
+
}
|
|
320
|
+
}, []);
|
|
321
|
+
|
|
322
|
+
// Check on resume
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
if (!mergedConfig.checkOnResume) return;
|
|
325
|
+
|
|
326
|
+
const handleAppStateChange = (nextState: AppStateStatus) => {
|
|
327
|
+
if (nextState === 'active') {
|
|
328
|
+
const now = Date.now();
|
|
329
|
+
if (now - lastCheckRef.current >= (mergedConfig.checkInterval ?? 60_000)) {
|
|
330
|
+
checkForUpdate();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const subscription = AppState.addEventListener('change', handleAppStateChange);
|
|
336
|
+
return () => subscription.remove();
|
|
337
|
+
}, [mergedConfig.checkOnResume, mergedConfig.checkInterval, checkForUpdate]);
|
|
338
|
+
|
|
339
|
+
// Restart
|
|
340
|
+
const restart = useCallback((): void => {
|
|
341
|
+
NativeSwiftPatch.restart();
|
|
342
|
+
}, []);
|
|
343
|
+
|
|
344
|
+
// Install update
|
|
345
|
+
const installUpdate = useCallback(async (): Promise<void> => {
|
|
346
|
+
const update = state.availableUpdate;
|
|
347
|
+
if (!update) throw new Error('No update available to install');
|
|
348
|
+
|
|
349
|
+
dispatch({ type: 'SET_STATUS', payload: Status.INSTALLING });
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
await NativeSwiftPatch.installUpdate(update.bundleHash);
|
|
353
|
+
|
|
354
|
+
dispatch({ type: 'SET_STATUS', payload: Status.RESTART_REQUIRED });
|
|
355
|
+
dispatch({ type: 'SET_RESTART_REQUIRED', payload: true });
|
|
356
|
+
|
|
357
|
+
const cfg = configRef.current;
|
|
358
|
+
await reportInstallStatus({
|
|
359
|
+
serverUrl: cfg.serverUrl!,
|
|
360
|
+
releaseId: update.id,
|
|
361
|
+
status: 'installed',
|
|
362
|
+
deploymentKey: cfg.deploymentKey,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Auto-restart for immediate install mode
|
|
366
|
+
if (
|
|
367
|
+
(update.isMandatory && cfg.mandatoryInstallMode === InstallMode.IMMEDIATE) ||
|
|
368
|
+
(!update.isMandatory && cfg.installMode === InstallMode.IMMEDIATE)
|
|
369
|
+
) {
|
|
370
|
+
restart();
|
|
371
|
+
}
|
|
372
|
+
} catch (error: unknown) {
|
|
373
|
+
const message = error instanceof Error ? error.message : 'Failed to install update';
|
|
374
|
+
dispatch({
|
|
375
|
+
type: 'SET_ERROR',
|
|
376
|
+
payload: { code: SwiftPatchErrorCode.INSTALL_ERROR, message },
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}, [state.availableUpdate, restart]);
|
|
380
|
+
|
|
381
|
+
// Download update
|
|
382
|
+
const downloadUpdate = useCallback(async (): Promise<void> => {
|
|
383
|
+
const update = state.availableUpdate;
|
|
384
|
+
if (!update) throw new Error('No update available to download');
|
|
385
|
+
if (!downloaderRef.current) throw new Error('Downloader not initialized');
|
|
386
|
+
|
|
387
|
+
dispatch({ type: 'SET_STATUS', payload: Status.DOWNLOADING });
|
|
388
|
+
dispatch({
|
|
389
|
+
type: 'SET_DOWNLOAD_PROGRESS',
|
|
390
|
+
payload: { downloadedBytes: 0, totalBytes: update.downloadSize, percentage: 0 },
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
try {
|
|
394
|
+
await downloaderRef.current.downloadRelease(update);
|
|
395
|
+
|
|
396
|
+
dispatch({ type: 'SET_STATUS', payload: Status.READY_TO_INSTALL });
|
|
397
|
+
dispatch({ type: 'SET_DOWNLOAD_PROGRESS', payload: null });
|
|
398
|
+
|
|
399
|
+
const cfg = configRef.current;
|
|
400
|
+
await reportInstallStatus({
|
|
401
|
+
serverUrl: cfg.serverUrl!,
|
|
402
|
+
releaseId: update.id,
|
|
403
|
+
status: 'downloaded',
|
|
404
|
+
deploymentKey: cfg.deploymentKey,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Auto-install for mandatory updates
|
|
408
|
+
if (update.isMandatory && cfg.mandatoryInstallMode === InstallMode.IMMEDIATE) {
|
|
409
|
+
await installUpdate();
|
|
410
|
+
}
|
|
411
|
+
} catch (error: unknown) {
|
|
412
|
+
const message = error instanceof Error ? error.message : 'Failed to download update';
|
|
413
|
+
dispatch({
|
|
414
|
+
type: 'SET_ERROR',
|
|
415
|
+
payload: { code: SwiftPatchErrorCode.DOWNLOAD_ERROR, message },
|
|
416
|
+
});
|
|
417
|
+
dispatch({ type: 'SET_DOWNLOAD_PROGRESS', payload: null });
|
|
418
|
+
}
|
|
419
|
+
}, [state.availableUpdate, installUpdate]);
|
|
420
|
+
|
|
421
|
+
// Rollback
|
|
422
|
+
const rollback = useCallback(async (): Promise<void> => {
|
|
423
|
+
await NativeSwiftPatch.rollback();
|
|
424
|
+
dispatch({ type: 'SET_STATUS', payload: Status.UP_TO_DATE });
|
|
425
|
+
dispatch({ type: 'SET_AVAILABLE_UPDATE', payload: null });
|
|
426
|
+
dispatch({ type: 'SET_RESTART_REQUIRED', payload: false });
|
|
427
|
+
const meta = await NativeSwiftPatch.getSlotMetadata();
|
|
428
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: meta });
|
|
429
|
+
}, []);
|
|
430
|
+
|
|
431
|
+
// Clear pending
|
|
432
|
+
const clearPendingUpdate = useCallback(async (): Promise<void> => {
|
|
433
|
+
await NativeSwiftPatch.clearPendingUpdate();
|
|
434
|
+
dispatch({ type: 'SET_STATUS', payload: Status.UP_TO_DATE });
|
|
435
|
+
dispatch({ type: 'SET_AVAILABLE_UPDATE', payload: null });
|
|
436
|
+
dispatch({ type: 'SET_RESTART_REQUIRED', payload: false });
|
|
437
|
+
}, []);
|
|
438
|
+
|
|
439
|
+
// Get current bundle
|
|
440
|
+
const getCurrentBundle = useCallback(async () => {
|
|
441
|
+
return NativeSwiftPatch.getCurrentBundle();
|
|
442
|
+
}, []);
|
|
443
|
+
|
|
444
|
+
// Stabilize (promote NEW → STABLE)
|
|
445
|
+
const stabilize = useCallback(async (): Promise<SlotMetadata> => {
|
|
446
|
+
const meta = await NativeSwiftPatch.stabilize();
|
|
447
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: meta });
|
|
448
|
+
return meta;
|
|
449
|
+
}, []);
|
|
450
|
+
|
|
451
|
+
// Switch environment
|
|
452
|
+
const switchEnvironment = useCallback(async (env: EnvironmentMode): Promise<SlotMetadata> => {
|
|
453
|
+
const meta = await NativeSwiftPatch.switchEnvironment(env);
|
|
454
|
+
dispatch({ type: 'SET_ENVIRONMENT', payload: env });
|
|
455
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: meta });
|
|
456
|
+
// Refresh current bundle info for the new environment
|
|
457
|
+
const bundle = await NativeSwiftPatch.getCurrentBundle();
|
|
458
|
+
dispatch({ type: 'SET_CURRENT_BUNDLE', payload: bundle });
|
|
459
|
+
return meta;
|
|
460
|
+
}, []);
|
|
461
|
+
|
|
462
|
+
// Get slot metadata
|
|
463
|
+
const getSlotMetadata = useCallback(async (): Promise<SlotMetadata> => {
|
|
464
|
+
const meta = await NativeSwiftPatch.getSlotMetadata();
|
|
465
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: meta });
|
|
466
|
+
return meta;
|
|
467
|
+
}, []);
|
|
468
|
+
|
|
469
|
+
// Mark mounted
|
|
470
|
+
const markMounted = useCallback((): void => {
|
|
471
|
+
NativeSwiftPatch.markMounted().catch(() => {});
|
|
472
|
+
}, []);
|
|
473
|
+
|
|
474
|
+
// Download stage bundle
|
|
475
|
+
const downloadStageBundle = useCallback(async (url: string, hash: string): Promise<void> => {
|
|
476
|
+
await NativeSwiftPatch.downloadStageBundle(url, hash);
|
|
477
|
+
const meta = await NativeSwiftPatch.getSlotMetadata();
|
|
478
|
+
dispatch({ type: 'SET_SLOT_METADATA', payload: meta });
|
|
479
|
+
}, []);
|
|
480
|
+
|
|
481
|
+
const contextValue: SwiftPatchContextValue = {
|
|
482
|
+
...state,
|
|
483
|
+
checkForUpdate,
|
|
484
|
+
downloadUpdate,
|
|
485
|
+
installUpdate,
|
|
486
|
+
restart,
|
|
487
|
+
rollback,
|
|
488
|
+
clearPendingUpdate,
|
|
489
|
+
getCurrentBundle,
|
|
490
|
+
stabilize,
|
|
491
|
+
switchEnvironment,
|
|
492
|
+
getSlotMetadata,
|
|
493
|
+
markMounted,
|
|
494
|
+
downloadStageBundle,
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
return (
|
|
498
|
+
<SwiftPatchContext.Provider value={contextValue}>
|
|
499
|
+
{children}
|
|
500
|
+
</SwiftPatchContext.Provider>
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Hook to access SwiftPatch context.
|
|
506
|
+
* Must be used within SwiftPatchProvider.
|
|
507
|
+
*/
|
|
508
|
+
export function useSwiftPatchContext(): SwiftPatchContextValue {
|
|
509
|
+
const context = useContext(SwiftPatchContext);
|
|
510
|
+
if (!context) {
|
|
511
|
+
throw new Error('useSwiftPatch must be used within a SwiftPatchProvider');
|
|
512
|
+
}
|
|
513
|
+
return context;
|
|
514
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { InstallMode } from './types';
|
|
2
|
+
import type { SwiftPatchConfig } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Default SDK configuration values
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_CONFIG: Required<Omit<SwiftPatchConfig, 'deploymentKey' | 'customHeaders' | 'publicKey' | 'sdkPin'>> & {
|
|
8
|
+
customHeaders: Record<string, string>;
|
|
9
|
+
publicKey: string | null;
|
|
10
|
+
sdkPin: string | null;
|
|
11
|
+
} = {
|
|
12
|
+
serverUrl: 'https://orbitplus.hyperbrainlabs.com/api/v1',
|
|
13
|
+
checkOnResume: true,
|
|
14
|
+
checkInterval: 60_000,
|
|
15
|
+
installMode: InstallMode.ON_NEXT_RESTART,
|
|
16
|
+
mandatoryInstallMode: InstallMode.IMMEDIATE,
|
|
17
|
+
debug: false,
|
|
18
|
+
customHeaders: {},
|
|
19
|
+
publicKey: null,
|
|
20
|
+
autoStabilizeAfterLaunches: 0,
|
|
21
|
+
sdkPin: null,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Native event names emitted from native modules
|
|
26
|
+
*/
|
|
27
|
+
export const NativeEvents = {
|
|
28
|
+
DOWNLOAD_PROGRESS: 'SwiftPatch:downloadProgress',
|
|
29
|
+
INSTALL_COMPLETE: 'SwiftPatch:installComplete',
|
|
30
|
+
ROLLBACK_OCCURRED: 'SwiftPatch:rollbackOccurred',
|
|
31
|
+
ERROR: 'SwiftPatch:error',
|
|
32
|
+
VERSION_CHANGED: 'SwiftPatch:versionChanged',
|
|
33
|
+
NATIVE_EVENT: 'SwiftPatch:event',
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* SDK version identifier
|
|
38
|
+
*/
|
|
39
|
+
export const SDK_VERSION = '2.0.0';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Crash detection window in milliseconds
|
|
43
|
+
*/
|
|
44
|
+
export const CRASH_DETECTION_WINDOW_MS = 10_000;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Event polling interval (ms)
|
|
48
|
+
*/
|
|
49
|
+
export const EVENT_POLL_INTERVAL_MS = 3_000;
|