@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.
Files changed (182) hide show
  1. package/README.md +430 -0
  2. package/android/build.gradle +105 -0
  3. package/android/src/main/AndroidManifest.xml +6 -0
  4. package/android/src/main/java/com/swiftpatch/BundleManager.kt +107 -0
  5. package/android/src/main/java/com/swiftpatch/CrashDetector.kt +79 -0
  6. package/android/src/main/java/com/swiftpatch/CryptoVerifier.kt +69 -0
  7. package/android/src/main/java/com/swiftpatch/DownloadManager.kt +120 -0
  8. package/android/src/main/java/com/swiftpatch/EventQueue.kt +86 -0
  9. package/android/src/main/java/com/swiftpatch/FileUtils.kt +60 -0
  10. package/android/src/main/java/com/swiftpatch/PatchApplier.kt +60 -0
  11. package/android/src/main/java/com/swiftpatch/SignalCrashHandler.kt +84 -0
  12. package/android/src/main/java/com/swiftpatch/SlotManager.kt +299 -0
  13. package/android/src/main/java/com/swiftpatch/SwiftPatchModule.kt +630 -0
  14. package/android/src/main/java/com/swiftpatch/SwiftPatchPackage.kt +21 -0
  15. package/android/src/main/jni/CMakeLists.txt +12 -0
  16. package/android/src/main/jni/bspatch.c +188 -0
  17. package/android/src/main/jni/bspatch.h +57 -0
  18. package/android/src/main/jni/bspatch_jni.c +28 -0
  19. package/ios/Libraries/bspatch/bspatch.c +188 -0
  20. package/ios/Libraries/bspatch/bspatch.h +50 -0
  21. package/ios/Libraries/bspatch/module.modulemap +4 -0
  22. package/ios/SwiftPatch/BundleManager.swift +113 -0
  23. package/ios/SwiftPatch/CrashDetector.swift +71 -0
  24. package/ios/SwiftPatch/CryptoVerifier.swift +70 -0
  25. package/ios/SwiftPatch/DownloadManager.swift +125 -0
  26. package/ios/SwiftPatch/EventQueue.swift +116 -0
  27. package/ios/SwiftPatch/FileUtils.swift +38 -0
  28. package/ios/SwiftPatch/PatchApplier.swift +41 -0
  29. package/ios/SwiftPatch/SignalCrashHandler.swift +129 -0
  30. package/ios/SwiftPatch/SlotManager.swift +360 -0
  31. package/ios/SwiftPatch/SwiftPatchModule.m +56 -0
  32. package/ios/SwiftPatch/SwiftPatchModule.swift +621 -0
  33. package/lib/commonjs/SwiftPatchCore.js +140 -0
  34. package/lib/commonjs/SwiftPatchCore.js.map +1 -0
  35. package/lib/commonjs/SwiftPatchProvider.js +617 -0
  36. package/lib/commonjs/SwiftPatchProvider.js.map +1 -0
  37. package/lib/commonjs/constants.js +50 -0
  38. package/lib/commonjs/constants.js.map +1 -0
  39. package/lib/commonjs/core/Downloader.js +63 -0
  40. package/lib/commonjs/core/Downloader.js.map +1 -0
  41. package/lib/commonjs/core/Installer.js +46 -0
  42. package/lib/commonjs/core/Installer.js.map +1 -0
  43. package/lib/commonjs/core/Rollback.js +36 -0
  44. package/lib/commonjs/core/Rollback.js.map +1 -0
  45. package/lib/commonjs/core/UpdateChecker.js +57 -0
  46. package/lib/commonjs/core/UpdateChecker.js.map +1 -0
  47. package/lib/commonjs/core/Verifier.js +82 -0
  48. package/lib/commonjs/core/Verifier.js.map +1 -0
  49. package/lib/commonjs/core/index.js +41 -0
  50. package/lib/commonjs/core/index.js.map +1 -0
  51. package/lib/commonjs/index.js +154 -0
  52. package/lib/commonjs/index.js.map +1 -0
  53. package/lib/commonjs/modal/SwiftPatchModal.js +667 -0
  54. package/lib/commonjs/modal/SwiftPatchModal.js.map +1 -0
  55. package/lib/commonjs/modal/useSwiftPatchModal.js +26 -0
  56. package/lib/commonjs/modal/useSwiftPatchModal.js.map +1 -0
  57. package/lib/commonjs/native/NativeSwiftPatch.js +85 -0
  58. package/lib/commonjs/native/NativeSwiftPatch.js.map +1 -0
  59. package/lib/commonjs/native/NativeSwiftPatchSpec.js +15 -0
  60. package/lib/commonjs/native/NativeSwiftPatchSpec.js.map +1 -0
  61. package/lib/commonjs/package.json +1 -0
  62. package/lib/commonjs/types.js +126 -0
  63. package/lib/commonjs/types.js.map +1 -0
  64. package/lib/commonjs/useSwiftPatch.js +31 -0
  65. package/lib/commonjs/useSwiftPatch.js.map +1 -0
  66. package/lib/commonjs/utils/api.js +206 -0
  67. package/lib/commonjs/utils/api.js.map +1 -0
  68. package/lib/commonjs/utils/device.js +23 -0
  69. package/lib/commonjs/utils/device.js.map +1 -0
  70. package/lib/commonjs/utils/logger.js +30 -0
  71. package/lib/commonjs/utils/logger.js.map +1 -0
  72. package/lib/commonjs/utils/storage.js +31 -0
  73. package/lib/commonjs/utils/storage.js.map +1 -0
  74. package/lib/commonjs/withSwiftPatch.js +42 -0
  75. package/lib/commonjs/withSwiftPatch.js.map +1 -0
  76. package/lib/module/SwiftPatchCore.js +135 -0
  77. package/lib/module/SwiftPatchCore.js.map +1 -0
  78. package/lib/module/SwiftPatchProvider.js +611 -0
  79. package/lib/module/SwiftPatchProvider.js.map +1 -0
  80. package/lib/module/constants.js +46 -0
  81. package/lib/module/constants.js.map +1 -0
  82. package/lib/module/core/Downloader.js +57 -0
  83. package/lib/module/core/Downloader.js.map +1 -0
  84. package/lib/module/core/Installer.js +41 -0
  85. package/lib/module/core/Installer.js.map +1 -0
  86. package/lib/module/core/Rollback.js +31 -0
  87. package/lib/module/core/Rollback.js.map +1 -0
  88. package/lib/module/core/UpdateChecker.js +51 -0
  89. package/lib/module/core/UpdateChecker.js.map +1 -0
  90. package/lib/module/core/Verifier.js +76 -0
  91. package/lib/module/core/Verifier.js.map +1 -0
  92. package/lib/module/core/index.js +8 -0
  93. package/lib/module/core/index.js.map +1 -0
  94. package/lib/module/index.js +34 -0
  95. package/lib/module/index.js.map +1 -0
  96. package/lib/module/modal/SwiftPatchModal.js +661 -0
  97. package/lib/module/modal/SwiftPatchModal.js.map +1 -0
  98. package/lib/module/modal/useSwiftPatchModal.js +22 -0
  99. package/lib/module/modal/useSwiftPatchModal.js.map +1 -0
  100. package/lib/module/native/NativeSwiftPatch.js +78 -0
  101. package/lib/module/native/NativeSwiftPatch.js.map +1 -0
  102. package/lib/module/native/NativeSwiftPatchSpec.js +12 -0
  103. package/lib/module/native/NativeSwiftPatchSpec.js.map +1 -0
  104. package/lib/module/types.js +139 -0
  105. package/lib/module/types.js.map +1 -0
  106. package/lib/module/useSwiftPatch.js +26 -0
  107. package/lib/module/useSwiftPatch.js.map +1 -0
  108. package/lib/module/utils/api.js +197 -0
  109. package/lib/module/utils/api.js.map +1 -0
  110. package/lib/module/utils/device.js +18 -0
  111. package/lib/module/utils/device.js.map +1 -0
  112. package/lib/module/utils/logger.js +26 -0
  113. package/lib/module/utils/logger.js.map +1 -0
  114. package/lib/module/utils/storage.js +24 -0
  115. package/lib/module/utils/storage.js.map +1 -0
  116. package/lib/module/withSwiftPatch.js +37 -0
  117. package/lib/module/withSwiftPatch.js.map +1 -0
  118. package/lib/typescript/SwiftPatchCore.d.ts +64 -0
  119. package/lib/typescript/SwiftPatchCore.d.ts.map +1 -0
  120. package/lib/typescript/SwiftPatchProvider.d.ts +22 -0
  121. package/lib/typescript/SwiftPatchProvider.d.ts.map +1 -0
  122. package/lib/typescript/constants.d.ts +33 -0
  123. package/lib/typescript/constants.d.ts.map +1 -0
  124. package/lib/typescript/core/Downloader.d.ts +34 -0
  125. package/lib/typescript/core/Downloader.d.ts.map +1 -0
  126. package/lib/typescript/core/Installer.d.ts +25 -0
  127. package/lib/typescript/core/Installer.d.ts.map +1 -0
  128. package/lib/typescript/core/Rollback.d.ts +18 -0
  129. package/lib/typescript/core/Rollback.d.ts.map +1 -0
  130. package/lib/typescript/core/UpdateChecker.d.ts +27 -0
  131. package/lib/typescript/core/UpdateChecker.d.ts.map +1 -0
  132. package/lib/typescript/core/Verifier.d.ts +31 -0
  133. package/lib/typescript/core/Verifier.d.ts.map +1 -0
  134. package/lib/typescript/core/index.d.ts +8 -0
  135. package/lib/typescript/core/index.d.ts.map +1 -0
  136. package/lib/typescript/index.d.ts +13 -0
  137. package/lib/typescript/index.d.ts.map +1 -0
  138. package/lib/typescript/modal/SwiftPatchModal.d.ts +11 -0
  139. package/lib/typescript/modal/SwiftPatchModal.d.ts.map +1 -0
  140. package/lib/typescript/modal/useSwiftPatchModal.d.ts +7 -0
  141. package/lib/typescript/modal/useSwiftPatchModal.d.ts.map +1 -0
  142. package/lib/typescript/native/NativeSwiftPatch.d.ts +61 -0
  143. package/lib/typescript/native/NativeSwiftPatch.d.ts.map +1 -0
  144. package/lib/typescript/native/NativeSwiftPatchSpec.d.ts +67 -0
  145. package/lib/typescript/native/NativeSwiftPatchSpec.d.ts.map +1 -0
  146. package/lib/typescript/types.d.ts +266 -0
  147. package/lib/typescript/types.d.ts.map +1 -0
  148. package/lib/typescript/useSwiftPatch.d.ts +12 -0
  149. package/lib/typescript/useSwiftPatch.d.ts.map +1 -0
  150. package/lib/typescript/utils/api.d.ts +87 -0
  151. package/lib/typescript/utils/api.d.ts.map +1 -0
  152. package/lib/typescript/utils/device.d.ts +9 -0
  153. package/lib/typescript/utils/device.d.ts.map +1 -0
  154. package/lib/typescript/utils/logger.d.ts +8 -0
  155. package/lib/typescript/utils/logger.d.ts.map +1 -0
  156. package/lib/typescript/utils/storage.d.ts +14 -0
  157. package/lib/typescript/utils/storage.d.ts.map +1 -0
  158. package/lib/typescript/withSwiftPatch.d.ts +12 -0
  159. package/lib/typescript/withSwiftPatch.d.ts.map +1 -0
  160. package/package.json +99 -0
  161. package/react-native-swiftpatch.podspec +50 -0
  162. package/src/SwiftPatchCore.ts +148 -0
  163. package/src/SwiftPatchProvider.tsx +514 -0
  164. package/src/constants.ts +49 -0
  165. package/src/core/Downloader.ts +74 -0
  166. package/src/core/Installer.ts +38 -0
  167. package/src/core/Rollback.ts +28 -0
  168. package/src/core/UpdateChecker.ts +70 -0
  169. package/src/core/Verifier.ts +92 -0
  170. package/src/core/index.ts +11 -0
  171. package/src/index.ts +64 -0
  172. package/src/modal/SwiftPatchModal.tsx +657 -0
  173. package/src/modal/useSwiftPatchModal.ts +24 -0
  174. package/src/native/NativeSwiftPatch.ts +205 -0
  175. package/src/native/NativeSwiftPatchSpec.ts +139 -0
  176. package/src/types.ts +336 -0
  177. package/src/useSwiftPatch.ts +29 -0
  178. package/src/utils/api.ts +244 -0
  179. package/src/utils/device.ts +15 -0
  180. package/src/utils/logger.ts +29 -0
  181. package/src/utils/storage.ts +23 -0
  182. package/src/withSwiftPatch.tsx +41 -0
@@ -0,0 +1,299 @@
1
+ package com.swiftpatch
2
+
3
+ import android.content.Context
4
+ import android.content.SharedPreferences
5
+ import java.io.File
6
+
7
+ enum class SlotState(val value: String) {
8
+ DEFAULT_SLOT("DEFAULT_SLOT"),
9
+ STABLE_SLOT("STABLE_SLOT"),
10
+ NEW_SLOT("NEW_SLOT");
11
+
12
+ companion object {
13
+ fun from(value: String): SlotState = entries.find { it.value == value } ?: DEFAULT_SLOT
14
+ }
15
+ }
16
+
17
+ enum class EnvironmentMode(val value: String) {
18
+ PRODUCTION("PROD"),
19
+ STAGING("STAGE");
20
+
21
+ companion object {
22
+ fun from(value: String): EnvironmentMode = entries.find { it.value == value } ?: PRODUCTION
23
+ }
24
+ }
25
+
26
+ class SlotManager(private val context: Context, private val prefs: SharedPreferences) {
27
+
28
+ private val baseDir: File get() = File(context.filesDir, "swiftpatch")
29
+ private val prodDir: File get() = File(baseDir, "prod")
30
+ private val prodNewDir: File get() = File(prodDir, "new")
31
+ private val prodStableDir: File get() = File(prodDir, "stable")
32
+ private val stageDir: File get() = File(baseDir, "stage")
33
+ private val stageNewDir: File get() = File(stageDir, "new")
34
+
35
+ fun ensureSlotDirectories() {
36
+ prodNewDir.mkdirs()
37
+ prodStableDir.mkdirs()
38
+ stageNewDir.mkdirs()
39
+ }
40
+
41
+ // ═══ Current State ═══
42
+
43
+ var currentEnvironment: EnvironmentMode
44
+ get() = EnvironmentMode.from(prefs.getString("environment", "PROD") ?: "PROD")
45
+ set(value) = prefs.edit().putString("environment", value.value).apply()
46
+
47
+ var currentProdSlot: SlotState
48
+ get() = SlotState.from(prefs.getString("prod_current_slot", "DEFAULT_SLOT") ?: "DEFAULT_SLOT")
49
+ set(value) = prefs.edit().putString("prod_current_slot", value.value).apply()
50
+
51
+ var prodNewHash: String?
52
+ get() = prefs.getString("prod_new_hash", null)
53
+ set(value) {
54
+ if (value != null) prefs.edit().putString("prod_new_hash", value).apply()
55
+ else prefs.edit().remove("prod_new_hash").apply()
56
+ }
57
+
58
+ var prodStableHash: String?
59
+ get() = prefs.getString("prod_stable_hash", null)
60
+ set(value) {
61
+ if (value != null) prefs.edit().putString("prod_stable_hash", value).apply()
62
+ else prefs.edit().remove("prod_stable_hash").apply()
63
+ }
64
+
65
+ var prodTempHash: String?
66
+ get() = prefs.getString("prod_temp_hash", null)
67
+ set(value) {
68
+ if (value != null) prefs.edit().putString("prod_temp_hash", value).apply()
69
+ else prefs.edit().remove("prod_temp_hash").apply()
70
+ }
71
+
72
+ var stageNewHash: String?
73
+ get() = prefs.getString("stage_new_hash", null)
74
+ set(value) {
75
+ if (value != null) prefs.edit().putString("stage_new_hash", value).apply()
76
+ else prefs.edit().remove("stage_new_hash").apply()
77
+ }
78
+
79
+ // ═══ Bundle Path Resolution ═══
80
+
81
+ fun getBundleFile(): String? {
82
+ val env = currentEnvironment
83
+
84
+ if (env == EnvironmentMode.STAGING) {
85
+ val hash = stageNewHash ?: return null
86
+ val path = File(stageNewDir, "$hash.bundle")
87
+ return if (path.exists()) path.absolutePath else null
88
+ }
89
+
90
+ // Production mode
91
+ return when (currentProdSlot) {
92
+ SlotState.NEW_SLOT -> {
93
+ val hash = prodNewHash
94
+ if (hash != null) {
95
+ val path = File(prodNewDir, "$hash.bundle")
96
+ if (path.exists()) return path.absolutePath
97
+ }
98
+ // Fallthrough to stable
99
+ val stableHash = prodStableHash
100
+ if (stableHash != null) {
101
+ val stablePath = File(prodStableDir, "$stableHash.bundle")
102
+ if (stablePath.exists()) {
103
+ currentProdSlot = SlotState.STABLE_SLOT
104
+ return stablePath.absolutePath
105
+ }
106
+ }
107
+ currentProdSlot = SlotState.DEFAULT_SLOT
108
+ null
109
+ }
110
+ SlotState.STABLE_SLOT -> {
111
+ val hash = prodStableHash
112
+ if (hash != null) {
113
+ val path = File(prodStableDir, "$hash.bundle")
114
+ if (path.exists()) return path.absolutePath
115
+ }
116
+ currentProdSlot = SlotState.DEFAULT_SLOT
117
+ null
118
+ }
119
+ SlotState.DEFAULT_SLOT -> null
120
+ }
121
+ }
122
+
123
+ // ═══ Temp Hash (Deferred Apply) ═══
124
+
125
+ fun applyTempHashOnLaunch() {
126
+ val tempHash = prodTempHash ?: return
127
+
128
+ val bundlesDir = File(baseDir, "bundles")
129
+ val sourcePath = File(bundlesDir, "$tempHash.bundle")
130
+ val destPath = File(prodNewDir, "$tempHash.bundle")
131
+
132
+ if (sourcePath.exists()) {
133
+ destPath.delete()
134
+ sourcePath.renameTo(destPath)
135
+ }
136
+
137
+ prodNewHash = tempHash
138
+ prodTempHash = null
139
+ currentProdSlot = SlotState.NEW_SLOT
140
+
141
+ prefs.edit().putString("current_bundle_installed_at",
142
+ java.time.Instant.now().toString()).apply()
143
+ }
144
+
145
+ // ═══ Stabilization (NEW → STABLE) ═══
146
+
147
+ fun stabilize(): Boolean {
148
+ val newHash = prodNewHash ?: return false
149
+
150
+ val sourcePath = File(prodNewDir, "$newHash.bundle")
151
+ val destPath = File(prodStableDir, "$newHash.bundle")
152
+
153
+ if (!sourcePath.exists()) return false
154
+
155
+ // Remove old stable bundle
156
+ prodStableHash?.let { oldHash ->
157
+ File(prodStableDir, "$oldHash.bundle").delete()
158
+ }
159
+
160
+ // Copy new bundle to stable
161
+ destPath.delete()
162
+ sourcePath.copyTo(destPath, overwrite = true)
163
+
164
+ prodStableHash = newHash
165
+ prodNewHash = null
166
+ currentProdSlot = SlotState.STABLE_SLOT
167
+
168
+ return true
169
+ }
170
+
171
+ // ═══ Rollback ═══
172
+
173
+ fun rollbackProd(isAutoRollback: Boolean): String {
174
+ return when (currentProdSlot) {
175
+ SlotState.NEW_SLOT -> {
176
+ prodNewHash?.let { hash ->
177
+ File(prodNewDir, "$hash.bundle").delete()
178
+ }
179
+ prodNewHash = null
180
+ prodTempHash = null
181
+
182
+ if (prodStableHash != null) {
183
+ currentProdSlot = SlotState.STABLE_SLOT
184
+ "ROLLED_BACK_TO_STABLE"
185
+ } else {
186
+ currentProdSlot = SlotState.DEFAULT_SLOT
187
+ "ROLLED_BACK_TO_DEFAULT"
188
+ }
189
+ }
190
+ SlotState.STABLE_SLOT -> {
191
+ prodStableHash?.let { hash ->
192
+ File(prodStableDir, "$hash.bundle").delete()
193
+ }
194
+ prodStableHash = null
195
+ currentProdSlot = SlotState.DEFAULT_SLOT
196
+ "ROLLED_BACK_TO_DEFAULT"
197
+ }
198
+ SlotState.DEFAULT_SLOT -> "ALREADY_AT_DEFAULT"
199
+ }
200
+ }
201
+
202
+ fun rollbackStage() {
203
+ stageNewHash?.let { hash ->
204
+ File(stageNewDir, "$hash.bundle").delete()
205
+ }
206
+ stageNewHash = null
207
+ }
208
+
209
+ // ═══ Version Change Detection ═══
210
+
211
+ fun checkVersionChange(): Boolean {
212
+ val currentAppVersion = try {
213
+ context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "0.0.0"
214
+ } catch (_: Exception) { "0.0.0" }
215
+
216
+ val lastKnownVersion = prefs.getString("last_known_app_version", null)
217
+
218
+ if (lastKnownVersion != null && lastKnownVersion != currentAppVersion) {
219
+ fallbackToDefault()
220
+ prefs.edit().putString("last_known_app_version", currentAppVersion).apply()
221
+ return true
222
+ }
223
+
224
+ if (lastKnownVersion == null) {
225
+ prefs.edit().putString("last_known_app_version", currentAppVersion).apply()
226
+ }
227
+
228
+ return false
229
+ }
230
+
231
+ fun fallbackToDefault() {
232
+ prodNewHash = null
233
+ prodStableHash = null
234
+ prodTempHash = null
235
+ stageNewHash = null
236
+ currentProdSlot = SlotState.DEFAULT_SLOT
237
+
238
+ // Clear legacy keys
239
+ prefs.edit()
240
+ .remove("current_bundle_hash")
241
+ .remove("current_bundle_path")
242
+ .remove("previous_bundle_hash")
243
+ .remove("previous_bundle_path")
244
+ .remove("pending_bundle_hash")
245
+ .remove("pending_bundle_path")
246
+ .remove("pending_install_confirmation")
247
+ .putInt("crash_count", 0)
248
+ .apply()
249
+
250
+ // Delete all bundle directories
251
+ prodNewDir.deleteRecursively()
252
+ prodStableDir.deleteRecursively()
253
+ stageNewDir.deleteRecursively()
254
+
255
+ ensureSlotDirectories()
256
+ }
257
+
258
+ // ═══ Metadata ═══
259
+
260
+ fun getMetadata(): Map<String, Any?> {
261
+ return mapOf(
262
+ "environment" to currentEnvironment.value,
263
+ "prod" to mapOf(
264
+ "currentSlot" to currentProdSlot.value,
265
+ "newHash" to prodNewHash,
266
+ "stableHash" to prodStableHash,
267
+ "tempHash" to prodTempHash,
268
+ ),
269
+ "stage" to mapOf(
270
+ "newHash" to stageNewHash,
271
+ )
272
+ )
273
+ }
274
+
275
+ // ═══ Cleanup ═══
276
+
277
+ fun cleanup() {
278
+ val keepHashes = setOfNotNull(prodNewHash, prodStableHash, stageNewHash)
279
+
280
+ cleanDirectory(prodNewDir, keepHashes)
281
+ cleanDirectory(prodStableDir, keepHashes)
282
+ cleanDirectory(stageNewDir, keepHashes)
283
+
284
+ // Clean legacy bundles dir
285
+ cleanDirectory(File(baseDir, "bundles"), keepHashes)
286
+
287
+ // Clean temp
288
+ File(baseDir, "temp").listFiles()?.forEach { it.delete() }
289
+ }
290
+
291
+ private fun cleanDirectory(dir: File, keepHashes: Set<String>) {
292
+ dir.listFiles()?.forEach { file ->
293
+ val fileHash = file.nameWithoutExtension
294
+ if (fileHash !in keepHashes) {
295
+ file.delete()
296
+ }
297
+ }
298
+ }
299
+ }