react-native-instantpay-code-push 1.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.
Files changed (87) hide show
  1. package/InstantpayCodePush.podspec +20 -0
  2. package/LICENSE +20 -0
  3. package/README.md +158 -0
  4. package/android/build.gradle +91 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/instantpaycodepush/BundleFileStorageService.kt +835 -0
  8. package/android/src/main/java/com/instantpaycodepush/BundleMetadata.kt +249 -0
  9. package/android/src/main/java/com/instantpaycodepush/CommonHelper.kt +39 -0
  10. package/android/src/main/java/com/instantpaycodepush/DecompressService.kt +85 -0
  11. package/android/src/main/java/com/instantpaycodepush/DecompressionStrategy.kt +24 -0
  12. package/android/src/main/java/com/instantpaycodepush/FileManagerService.kt +105 -0
  13. package/android/src/main/java/com/instantpaycodepush/HashUtils.kt +50 -0
  14. package/android/src/main/java/com/instantpaycodepush/InstantpayCodePushModule.kt +182 -0
  15. package/android/src/main/java/com/instantpaycodepush/InstantpayCodePushPackage.kt +33 -0
  16. package/android/src/main/java/com/instantpaycodepush/IpayCodePush.kt +101 -0
  17. package/android/src/main/java/com/instantpaycodepush/IpayCodePushException.kt +135 -0
  18. package/android/src/main/java/com/instantpaycodepush/IpayCodePushImpl.kt +329 -0
  19. package/android/src/main/java/com/instantpaycodepush/OkHttpDownloadService.kt +283 -0
  20. package/android/src/main/java/com/instantpaycodepush/ReactIntegrationManager.kt +141 -0
  21. package/android/src/main/java/com/instantpaycodepush/ReactIntegrationManagerBase.kt +35 -0
  22. package/android/src/main/java/com/instantpaycodepush/SignatureVerifier.kt +354 -0
  23. package/android/src/main/java/com/instantpaycodepush/VersionedPreferencesService.kt +70 -0
  24. package/android/src/main/java/com/instantpaycodepush/ZipDecompressionStrategy.kt +198 -0
  25. package/ios/InstantpayCodePush.h +5 -0
  26. package/ios/InstantpayCodePush.mm +21 -0
  27. package/lib/module/DefaultResolver.js +34 -0
  28. package/lib/module/DefaultResolver.js.map +1 -0
  29. package/lib/module/NativeInstantpayCodePush.js +5 -0
  30. package/lib/module/NativeInstantpayCodePush.js.map +1 -0
  31. package/lib/module/checkForUpdate.js +68 -0
  32. package/lib/module/checkForUpdate.js.map +1 -0
  33. package/lib/module/error.js +137 -0
  34. package/lib/module/error.js.map +1 -0
  35. package/lib/module/fetchUpdateInfo.js +36 -0
  36. package/lib/module/fetchUpdateInfo.js.map +1 -0
  37. package/lib/module/global.d.js +8 -0
  38. package/lib/module/global.d.js.map +1 -0
  39. package/lib/module/hooks/useEventCallback.js +13 -0
  40. package/lib/module/hooks/useEventCallback.js.map +1 -0
  41. package/lib/module/index.js +291 -0
  42. package/lib/module/index.js.map +1 -0
  43. package/lib/module/native.js +233 -0
  44. package/lib/module/native.js.map +1 -0
  45. package/lib/module/package.json +1 -0
  46. package/lib/module/store.js +53 -0
  47. package/lib/module/store.js.map +1 -0
  48. package/lib/module/types.js +62 -0
  49. package/lib/module/types.js.map +1 -0
  50. package/lib/module/wrap.js +171 -0
  51. package/lib/module/wrap.js.map +1 -0
  52. package/lib/typescript/package.json +1 -0
  53. package/lib/typescript/src/DefaultResolver.d.ts +10 -0
  54. package/lib/typescript/src/DefaultResolver.d.ts.map +1 -0
  55. package/lib/typescript/src/NativeInstantpayCodePush.d.ts +100 -0
  56. package/lib/typescript/src/NativeInstantpayCodePush.d.ts.map +1 -0
  57. package/lib/typescript/src/checkForUpdate.d.ts +29 -0
  58. package/lib/typescript/src/checkForUpdate.d.ts.map +1 -0
  59. package/lib/typescript/src/error.d.ts +124 -0
  60. package/lib/typescript/src/error.d.ts.map +1 -0
  61. package/lib/typescript/src/fetchUpdateInfo.d.ts +8 -0
  62. package/lib/typescript/src/fetchUpdateInfo.d.ts.map +1 -0
  63. package/lib/typescript/src/hooks/useEventCallback.d.ts +5 -0
  64. package/lib/typescript/src/hooks/useEventCallback.d.ts.map +1 -0
  65. package/lib/typescript/src/index.d.ts +203 -0
  66. package/lib/typescript/src/index.d.ts.map +1 -0
  67. package/lib/typescript/src/native.d.ts +128 -0
  68. package/lib/typescript/src/native.d.ts.map +1 -0
  69. package/lib/typescript/src/store.d.ts +11 -0
  70. package/lib/typescript/src/store.d.ts.map +1 -0
  71. package/lib/typescript/src/types.d.ts +174 -0
  72. package/lib/typescript/src/types.d.ts.map +1 -0
  73. package/lib/typescript/src/wrap.d.ts +179 -0
  74. package/lib/typescript/src/wrap.d.ts.map +1 -0
  75. package/package.json +174 -0
  76. package/src/DefaultResolver.ts +36 -0
  77. package/src/NativeInstantpayCodePush.ts +111 -0
  78. package/src/checkForUpdate.ts +122 -0
  79. package/src/error.ts +159 -0
  80. package/src/fetchUpdateInfo.ts +47 -0
  81. package/src/global.d.ts +23 -0
  82. package/src/hooks/useEventCallback.ts +30 -0
  83. package/src/index.tsx +379 -0
  84. package/src/native.ts +280 -0
  85. package/src/store.ts +69 -0
  86. package/src/types.ts +227 -0
  87. package/src/wrap.tsx +384 -0
@@ -0,0 +1,198 @@
1
+ package com.instantpaycodepush
2
+
3
+ import android.util.Log
4
+ import java.io.BufferedInputStream
5
+ import java.io.File
6
+ import java.io.FileInputStream
7
+ import java.io.FileOutputStream
8
+ import java.io.IOException
9
+ import java.util.zip.CRC32
10
+ import java.util.zip.ZipEntry
11
+ import java.util.zip.ZipException
12
+ import java.util.zip.ZipFile
13
+ import java.util.zip.ZipInputStream
14
+
15
+ /**
16
+ * Strategy for handling ZIP compressed files
17
+ */
18
+ class ZipDecompressionStrategy : DecompressionStrategy {
19
+
20
+ companion object {
21
+ private const val CLASS_TAG = "*ZipStrategy"
22
+ private const val MIN_ZIP_SIZE = 22L
23
+ }
24
+
25
+ override fun isValid(filePath: String): Boolean {
26
+ val file = File(filePath)
27
+
28
+ if (!file.exists() || file.length() < MIN_ZIP_SIZE) {
29
+ CommonHelper.logPrint(CLASS_TAG, "Invalid ZIP: file doesn't exist or too small (${file.length()} bytes)")
30
+ return false
31
+ }
32
+
33
+ try {
34
+ FileInputStream(file).use { fis ->
35
+ val header = ByteArray(4)
36
+ if (fis.read(header) != 4) {
37
+ CommonHelper.logPrint(CLASS_TAG, "Invalid ZIP: cannot read header")
38
+ return false
39
+ }
40
+
41
+ // ZIP magic bytes: 0x50 0x4B 0x03 0x04 ("PK\u0003\u0004")
42
+ val expectedMagic = byteArrayOf(0x50.toByte(), 0x4B.toByte(), 0x03.toByte(), 0x04.toByte())
43
+
44
+ if (!header.contentEquals(expectedMagic)) {
45
+ val headerHex = header.joinToString(" ") { "0x%02X".format(it) }
46
+ CommonHelper.logPrint(CLASS_TAG, "Invalid ZIP: wrong magic bytes (expected 0x50 0x4B 0x03 0x04, got $headerHex)")
47
+ return false
48
+ }
49
+ }
50
+ } catch (e: Exception) {
51
+ CommonHelper.logPrint(CLASS_TAG, "Invalid ZIP: error reading file: ${e.message}")
52
+ return false
53
+ }
54
+
55
+ try {
56
+ ZipFile(file).use { zipFile ->
57
+ val entries = zipFile.entries()
58
+ if (!entries.hasMoreElements()) {
59
+ CommonHelper.logPrint(CLASS_TAG, "Invalid ZIP: no entries found")
60
+ return false
61
+ }
62
+
63
+ val firstEntry = entries.nextElement()
64
+ zipFile.getInputStream(firstEntry).use { stream ->
65
+ val buffer = ByteArray(1024)
66
+ stream.read(buffer)
67
+ }
68
+ }
69
+ return true
70
+ } catch (e: ZipException) {
71
+ CommonHelper.logPrint(CLASS_TAG, "Invalid ZIP: ZIP structure error: ${e.message}")
72
+ return false
73
+ } catch (e: Exception) {
74
+ CommonHelper.logPrint(CLASS_TAG, "Invalid ZIP: validation error: ${e.message}")
75
+ return false
76
+ }
77
+ }
78
+
79
+ override fun decompress(
80
+ filePath: String,
81
+ destinationPath: String,
82
+ progressCallback: (Double) -> Unit,
83
+ ): Boolean {
84
+ return try {
85
+ val destinationDir = File(destinationPath)
86
+ if (!destinationDir.exists()) {
87
+ destinationDir.mkdirs()
88
+ }
89
+
90
+ // Calculate total bytes to extract for accurate progress reporting
91
+ val totalBytes =
92
+ try {
93
+ ZipFile(File(filePath)).use { zipFile ->
94
+ zipFile
95
+ .entries()
96
+ .asSequence()
97
+ .filter { !it.isDirectory }
98
+ .sumOf { it.size }
99
+ }
100
+ } catch (e: Exception) {
101
+ CommonHelper.logPrint(CLASS_TAG, "Failed to calculate total bytes: ${e.message}")
102
+ 0L
103
+ }
104
+
105
+ if (totalBytes == 0L) {
106
+ CommonHelper.logPrint(CLASS_TAG, "No content found in ZIP")
107
+ return false
108
+ }
109
+
110
+ CommonHelper.logPrint(CLASS_TAG, "Extracting $totalBytes bytes from ZIP")
111
+
112
+ var extractedFileCount = 0
113
+ var extractedBytes = 0L
114
+ var lastReportedProgress = 0.0
115
+
116
+ FileInputStream(filePath).use { fileInputStream ->
117
+ BufferedInputStream(fileInputStream).use { bufferedInputStream ->
118
+ ZipInputStream(bufferedInputStream).use { zipInputStream ->
119
+ var entry: ZipEntry? = zipInputStream.nextEntry
120
+ while (entry != null) {
121
+ val file = File(destinationPath, entry.name)
122
+
123
+ // Zip Slip vulnerability check - verify entry path is within destination
124
+ try {
125
+ val canonicalDestPath = destinationDir.canonicalPath
126
+ val canonicalFilePath = file.canonicalPath
127
+
128
+ if (!canonicalFilePath.startsWith(canonicalDestPath)) {
129
+ CommonHelper.logPrint(CLASS_TAG, "Skipping potentially malicious zip entry: ${entry.name}")
130
+ entry = zipInputStream.nextEntry
131
+ continue
132
+ }
133
+ } catch (e: IOException) {
134
+ // If we can't resolve canonical paths, treat as potentially malicious
135
+ CommonHelper.logPrint(CLASS_TAG, "Failed to resolve canonical path for zip entry: ${entry.name} full error : $e")
136
+ entry = zipInputStream.nextEntry
137
+ continue
138
+ }
139
+
140
+ if (entry.isDirectory) {
141
+ file.mkdirs()
142
+ } else {
143
+ file.parentFile?.mkdirs()
144
+
145
+ val crc = CRC32()
146
+ FileOutputStream(file).use { output ->
147
+ val buffer = ByteArray(8 * 1024)
148
+ var bytesRead: Int
149
+
150
+ while (zipInputStream.read(buffer).also { bytesRead = it } != -1) {
151
+ output.write(buffer, 0, bytesRead)
152
+ crc.update(buffer, 0, bytesRead)
153
+
154
+ // Track bytes written for byte-based progress
155
+ extractedBytes += bytesRead
156
+
157
+ // Report progress more frequently (every 1%)
158
+ val currentProgress = extractedBytes.toDouble() / totalBytes
159
+ if (currentProgress - lastReportedProgress >= 0.01) {
160
+ progressCallback.invoke(currentProgress)
161
+ lastReportedProgress = currentProgress
162
+ }
163
+ }
164
+ }
165
+
166
+ if (entry.crc != -1L && crc.value != entry.crc) {
167
+ CommonHelper.logPrint(CLASS_TAG, "CRC mismatch for ${entry.name}: expected ${entry.crc}, got ${crc.value}")
168
+ file.delete()
169
+ return false
170
+ }
171
+
172
+ extractedFileCount++
173
+ }
174
+
175
+ zipInputStream.closeEntry()
176
+ entry = zipInputStream.nextEntry
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ if (extractedFileCount == 0) {
183
+ CommonHelper.logPrint(CLASS_TAG, "No files extracted from ZIP")
184
+ return false
185
+ }
186
+
187
+ CommonHelper.logPrint(CLASS_TAG, "Successfully extracted $extractedFileCount files ($extractedBytes bytes)")
188
+ progressCallback.invoke(1.0)
189
+ true
190
+ } catch (e: ZipException) {
191
+ CommonHelper.logPrint(CLASS_TAG, "ZIP extraction failed: ${e.message}")
192
+ false
193
+ } catch (e: Exception) {
194
+ CommonHelper.logPrint(CLASS_TAG, "Failed to unzip file: ${e.message}")
195
+ false
196
+ }
197
+ }
198
+ }
@@ -0,0 +1,5 @@
1
+ #import <InstantpayCodePushSpec/InstantpayCodePushSpec.h>
2
+
3
+ @interface InstantpayCodePush : NSObject <NativeInstantpayCodePushSpec>
4
+
5
+ @end
@@ -0,0 +1,21 @@
1
+ #import "InstantpayCodePush.h"
2
+
3
+ @implementation InstantpayCodePush
4
+ - (NSNumber *)multiply:(double)a b:(double)b {
5
+ NSNumber *result = @(a * b);
6
+
7
+ return result;
8
+ }
9
+
10
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
11
+ (const facebook::react::ObjCTurboModule::InitParams &)params
12
+ {
13
+ return std::make_shared<facebook::react::NativeInstantpayCodePushSpecJSI>(params);
14
+ }
15
+
16
+ + (NSString *)moduleName
17
+ {
18
+ return @"InstantpayCodePush";
19
+ }
20
+
21
+ @end
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ import { fetchUpdateInfo } from "./fetchUpdateInfo.js";
4
+ /**
5
+ * Creates a default resolver that uses baseURL for network operations.
6
+ * This encapsulates the existing baseURL logic into a resolver.
7
+ *
8
+ * @param baseURL - The base URL for the update server
9
+ * @returns A HotUpdaterResolver that uses the baseURL
10
+ */
11
+ export function createDefaultResolver(baseURL) {
12
+ return {
13
+ checkUpdate: async params => {
14
+ // Build URL based on strategy (existing buildUpdateUrl logic)
15
+ let url;
16
+ if (params.updateStrategy === "fingerprint") {
17
+ if (!params.fingerprintHash) {
18
+ throw new Error("Fingerprint hash is required");
19
+ }
20
+ url = `${baseURL}/fingerprint/${params.platform}/${params.fingerprintHash}/${params.channel}/${params.minBundleId}/${params.bundleId}`;
21
+ } else {
22
+ url = `${baseURL}/app-version/${params.platform}/${params.appVersion}/${params.channel}/${params.minBundleId}/${params.bundleId}`;
23
+ }
24
+
25
+ // Use existing fetchUpdateInfo
26
+ return fetchUpdateInfo({
27
+ url,
28
+ requestHeaders: params.requestHeaders,
29
+ requestTimeout: params.requestTimeout
30
+ });
31
+ }
32
+ };
33
+ }
34
+ //# sourceMappingURL=DefaultResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["fetchUpdateInfo","createDefaultResolver","baseURL","checkUpdate","params","url","updateStrategy","fingerprintHash","Error","platform","channel","minBundleId","bundleId","appVersion","requestHeaders","requestTimeout"],"sourceRoot":"../../src","sources":["DefaultResolver.ts"],"mappings":";;AACA,SAASA,eAAe,QAAQ,sBAAmB;AAGnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,qBAAqBA,CAACC,OAAe,EAAwB;EACzE,OAAO;IACHC,WAAW,EAAE,MACTC,MAAiC,IACD;MAChC;MACA,IAAIC,GAAW;MACf,IAAID,MAAM,CAACE,cAAc,KAAK,aAAa,EAAE;QACzC,IAAI,CAACF,MAAM,CAACG,eAAe,EAAE;UACzB,MAAM,IAAIC,KAAK,CAAC,8BAA8B,CAAC;QACnD;QACAH,GAAG,GAAG,GAAGH,OAAO,gBAAgBE,MAAM,CAACK,QAAQ,IAAIL,MAAM,CAACG,eAAe,IAAIH,MAAM,CAACM,OAAO,IAAIN,MAAM,CAACO,WAAW,IAAIP,MAAM,CAACQ,QAAQ,EAAE;MAC1I,CAAC,MAAM;QACHP,GAAG,GAAG,GAAGH,OAAO,gBAAgBE,MAAM,CAACK,QAAQ,IAAIL,MAAM,CAACS,UAAU,IAAIT,MAAM,CAACM,OAAO,IAAIN,MAAM,CAACO,WAAW,IAAIP,MAAM,CAACQ,QAAQ,EAAE;MACrI;;MAEA;MACA,OAAOZ,eAAe,CAAC;QACnBK,GAAG;QACHS,cAAc,EAAEV,MAAM,CAACU,cAAc;QACrCC,cAAc,EAAEX,MAAM,CAACW;MAC3B,CAAC,CAAC;IACN;EACJ,CAAC;AACL","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+ export default TurboModuleRegistry.getEnforcing('InstantpayCodePush');
5
+ //# sourceMappingURL=NativeInstantpayCodePush.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeInstantpayCodePush.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAA0B,cAAc;AA8GpE,eAAeA,mBAAmB,CAACC,YAAY,CAAO,oBAAoB,CAAC","ignoreList":[]}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+
3
+ import { Platform } from "react-native";
4
+ import { IpayCodePushError } from "./error.js";
5
+ import { getAppVersion, getBundleId, getChannel, getFingerprintHash, getMinBundleId, updateBundle } from "./native.js";
6
+
7
+ // Internal type that includes resolver for use within index.ts
8
+
9
+ export async function checkForUpdate(options) {
10
+ if (__DEV__) {
11
+ console.log('checkForUpdate : Running in dev mode');
12
+ return null;
13
+ }
14
+ if (Platform.OS == 'ios') {
15
+ console.log("Under Development in iOS Platform");
16
+ return null;
17
+ }
18
+ if (!["ios", "android"].includes(Platform.OS)) {
19
+ options.onError?.(new IpayCodePushError("IpayCodePush is only supported on iOS and Android"));
20
+ return null;
21
+ }
22
+ const currentAppVersion = getAppVersion();
23
+ const platform = Platform.OS;
24
+ const currentBundleId = getBundleId();
25
+ const minBundleId = getMinBundleId();
26
+ const channel = getChannel();
27
+ if (!currentAppVersion) {
28
+ options.onError?.(new IpayCodePushError("Failed to get app version"));
29
+ return null;
30
+ }
31
+ const fingerprintHash = getFingerprintHash();
32
+ if (!options.resolver?.checkUpdate) {
33
+ options.onError?.(new IpayCodePushError("Resolver is required but not configured"));
34
+ return null;
35
+ }
36
+ let updateInfo = null;
37
+ try {
38
+ updateInfo = await options.resolver.checkUpdate({
39
+ platform,
40
+ appVersion: currentAppVersion,
41
+ bundleId: currentBundleId,
42
+ minBundleId,
43
+ channel,
44
+ updateStrategy: options.updateStrategy,
45
+ fingerprintHash,
46
+ requestHeaders: options.requestHeaders,
47
+ requestTimeout: options.requestTimeout
48
+ });
49
+ } catch (error) {
50
+ options.onError?.(error);
51
+ return null;
52
+ }
53
+ if (!updateInfo) {
54
+ return null;
55
+ }
56
+ return {
57
+ ...updateInfo,
58
+ updateBundle: async () => {
59
+ return updateBundle({
60
+ bundleId: updateInfo.id,
61
+ fileUrl: updateInfo.fileUrl,
62
+ fileHash: updateInfo.fileHash,
63
+ status: updateInfo.status
64
+ });
65
+ }
66
+ };
67
+ }
68
+ //# sourceMappingURL=checkForUpdate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Platform","IpayCodePushError","getAppVersion","getBundleId","getChannel","getFingerprintHash","getMinBundleId","updateBundle","checkForUpdate","options","__DEV__","console","log","OS","includes","onError","currentAppVersion","platform","currentBundleId","minBundleId","channel","fingerprintHash","resolver","checkUpdate","updateInfo","appVersion","bundleId","updateStrategy","requestHeaders","requestTimeout","error","id","fileUrl","fileHash","status"],"sourceRoot":"../../src","sources":["checkForUpdate.ts"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,SAASC,iBAAiB,QAAQ,YAAS;AAE3C,SACIC,aAAa,EACbC,WAAW,EACXC,UAAU,EACVC,kBAAkB,EAClBC,cAAc,EACdC,YAAY,QACT,aAAU;;AAgCjB;;AAKA,OAAO,eAAeC,cAAcA,CAChCC,OAAsC,EACF;EACpC,IAAIC,OAAO,EAAE;IACTC,OAAO,CAACC,GAAG,CAAC,sCAAsC,CAAC;IACnD,OAAO,IAAI;EACf;EAEA,IAAGZ,QAAQ,CAACa,EAAE,IAAI,KAAK,EAAC;IACpBF,OAAO,CAACC,GAAG,CAAC,mCAAmC,CAAC;IAChD,OAAO,IAAI;EACf;EAEA,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAACE,QAAQ,CAACd,QAAQ,CAACa,EAAE,CAAC,EAAE;IAC3CJ,OAAO,CAACM,OAAO,GACX,IAAId,iBAAiB,CAAC,mDAAmD,CAC7E,CAAC;IACD,OAAO,IAAI;EACf;EAEA,MAAMe,iBAAiB,GAAGd,aAAa,CAAC,CAAC;EACzC,MAAMe,QAAQ,GAAGjB,QAAQ,CAACa,EAAuB;EACjD,MAAMK,eAAe,GAAGf,WAAW,CAAC,CAAC;EACrC,MAAMgB,WAAW,GAAGb,cAAc,CAAC,CAAC;EACpC,MAAMc,OAAO,GAAGhB,UAAU,CAAC,CAAC;EAE5B,IAAI,CAACY,iBAAiB,EAAE;IACpBP,OAAO,CAACM,OAAO,GAAG,IAAId,iBAAiB,CAAC,2BAA2B,CAAC,CAAC;IACrE,OAAO,IAAI;EACf;EAEA,MAAMoB,eAAe,GAAGhB,kBAAkB,CAAC,CAAC;EAE5C,IAAI,CAACI,OAAO,CAACa,QAAQ,EAAEC,WAAW,EAAE;IAChCd,OAAO,CAACM,OAAO,GACX,IAAId,iBAAiB,CAAC,yCAAyC,CACnE,CAAC;IACD,OAAO,IAAI;EACf;EAEA,IAAIuB,UAAgC,GAAG,IAAI;EAE3C,IAAI;IACAA,UAAU,GAAG,MAAMf,OAAO,CAACa,QAAQ,CAACC,WAAW,CAAC;MAC5CN,QAAQ;MACRQ,UAAU,EAAET,iBAAiB;MAC7BU,QAAQ,EAAER,eAAe;MACzBC,WAAW;MACXC,OAAO;MACPO,cAAc,EAAElB,OAAO,CAACkB,cAAc;MACtCN,eAAe;MACfO,cAAc,EAAEnB,OAAO,CAACmB,cAAc;MACtCC,cAAc,EAAEpB,OAAO,CAACoB;IAC5B,CAAC,CAAC;EACN,CAAC,CAAC,OAAOC,KAAK,EAAE;IACZrB,OAAO,CAACM,OAAO,GAAGe,KAAc,CAAC;IACjC,OAAO,IAAI;EACf;EAEA,IAAI,CAACN,UAAU,EAAE;IACb,OAAO,IAAI;EACf;EAEA,OAAO;IACH,GAAGA,UAAU;IACbjB,YAAY,EAAE,MAAAA,CAAA,KAAY;MACtB,OAAOA,YAAY,CAAC;QAChBmB,QAAQ,EAAEF,UAAU,CAACO,EAAE;QACvBC,OAAO,EAAER,UAAU,CAACQ,OAAO;QAC3BC,QAAQ,EAAET,UAAU,CAACS,QAAQ;QAC7BC,MAAM,EAAEV,UAAU,CAACU;MACvB,CAAC,CAAC;IACN;EACJ,CAAC;AACL","ignoreList":[]}
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Ipay Code Push Error Codes
5
+ *
6
+ * This file defines all possible error codes that can be thrown by the native
7
+ * updateBundle function. These error codes are shared across iOS and Android
8
+ * implementations to ensure consistent error handling.
9
+ *
10
+ * Error Classification:
11
+ * - Parameter Validation: Invalid or missing function parameters
12
+ * - Bundle Storage: Errors during download, extraction, and storage
13
+ * - Signature Verification: Cryptographic verification failures (collapsed to a single public code)
14
+ * - Internal: Platform-specific or unexpected errors
15
+ *
16
+ * Retryability:
17
+ * - Retryable: DOWNLOAD_FAILED, INCOMPLETE_DOWNLOAD
18
+ * - Non-retryable: Most validation and verification errors
19
+ */
20
+
21
+ export let IpayCodePushErrorCode = /*#__PURE__*/function (IpayCodePushErrorCode) {
22
+ // ==================== Parameter Validation Errors ====================
23
+ /**
24
+ * Bundle ID is missing or empty.
25
+ * Thrown when bundleId parameter is null, undefined, or empty string.
26
+ * @retryable false
27
+ */
28
+ IpayCodePushErrorCode["MISSING_BUNDLE_ID"] = "MISSING_BUNDLE_ID";
29
+ /**
30
+ * File URL is invalid or malformed.
31
+ * Thrown when fileUrl parameter cannot be parsed as a valid URL.
32
+ * @retryable false
33
+ */
34
+ IpayCodePushErrorCode["INVALID_FILE_URL"] = "INVALID_FILE_URL";
35
+ // ==================== Bundle Storage Errors ====================
36
+ /**
37
+ * Failed to create required directory for bundle storage.
38
+ * Thrown when bundle directory creation fails due to permissions or disk errors.
39
+ * @retryable false - Usually indicates permissions or filesystem corruption
40
+ */
41
+ IpayCodePushErrorCode["DIRECTORY_CREATION_FAILED"] = "DIRECTORY_CREATION_FAILED";
42
+ /**
43
+ * Bundle download failed.
44
+ * Covers network errors, HTTP errors (4xx/5xx), timeouts, and connection issues.
45
+ * Check error message for specific cause (network, HTTP status code, etc.).
46
+ * @retryable true - Network issues are often transient
47
+ */
48
+ IpayCodePushErrorCode["DOWNLOAD_FAILED"] = "DOWNLOAD_FAILED";
49
+ /**
50
+ * Download incomplete - received size doesn't match expected size.
51
+ * Thrown when downloaded file size doesn't match Content-Length header.
52
+ * Error message includes both expected and actual byte counts.
53
+ * @retryable true - Download may succeed on retry
54
+ */
55
+ IpayCodePushErrorCode["INCOMPLETE_DOWNLOAD"] = "INCOMPLETE_DOWNLOAD";
56
+ /**
57
+ * Bundle archive format is invalid or corrupted.
58
+ * Thrown when ZIP file has wrong magic bytes, invalid structure, or unsupported format.
59
+ * Also thrown for path traversal attempts during extraction.
60
+ * @retryable false - Indicates corrupted or malicious bundle
61
+ */
62
+ IpayCodePushErrorCode["EXTRACTION_FORMAT_ERROR"] = "EXTRACTION_FORMAT_ERROR";
63
+ /**
64
+ * Bundle missing required platform files.
65
+ * Thrown when extracted bundle doesn't contain index.android.bundle (Android)
66
+ * or main.jsbundle (iOS).
67
+ * @retryable false - Indicates incorrectly built bundle
68
+ */
69
+ IpayCodePushErrorCode["INVALID_BUNDLE"] = "INVALID_BUNDLE";
70
+ /**
71
+ * Insufficient disk space for bundle download and extraction.
72
+ * Thrown when available disk space is less than required (file size * 2).
73
+ * Error message includes required and available bytes.
74
+ * @retryable false - User must free up disk space
75
+ */
76
+ IpayCodePushErrorCode["INSUFFICIENT_DISK_SPACE"] = "INSUFFICIENT_DISK_SPACE";
77
+ /**
78
+ * Bundle signature verification failed (general).
79
+ * Thrown when cryptographic signature verification fails.
80
+ * All signature/hash sub-errors are collapsed into this public code.
81
+ * @retryable false - Indicates tampered or incorrectly signed bundle
82
+ */
83
+ IpayCodePushErrorCode["SIGNATURE_VERIFICATION_FAILED"] = "SIGNATURE_VERIFICATION_FAILED";
84
+ /**
85
+ * Failed to move bundle to final location.
86
+ * Thrown when atomic move from temp directory to final directory fails.
87
+ * iOS: Thrown if move operation fails.
88
+ * Android: Thrown if rename, move, AND copy all fail.
89
+ * @retryable false - Usually indicates filesystem corruption or permissions
90
+ */
91
+ IpayCodePushErrorCode["MOVE_OPERATION_FAILED"] = "MOVE_OPERATION_FAILED";
92
+ /**
93
+ * Bundle is in crashed history and cannot be applied.
94
+ * Thrown when attempting to install a bundle that previously caused a crash.
95
+ * Use IpayCodePush.clearCrashHistory() to allow retrying this bundle.
96
+ * @retryable false - Bundle was marked as crashed for safety
97
+ */
98
+ IpayCodePushErrorCode["BUNDLE_IN_CRASHED_HISTORY"] = "BUNDLE_IN_CRASHED_HISTORY";
99
+ // ==================== Signature Verification Errors ====================
100
+ // (Collapsed into SIGNATURE_VERIFICATION_FAILED)
101
+ // ==================== Internal Errors ====================
102
+ /**
103
+ * Internal error: self deallocated during update (iOS only).
104
+ * Thrown when the native object is deallocated mid-operation.
105
+ * iOS-specific due to manual memory management (ARC).
106
+ * Not applicable to Android (uses garbage collection).
107
+ * @platform iOS
108
+ * @retryable false - Memory management issue
109
+ */
110
+ IpayCodePushErrorCode["SELF_DEALLOCATED"] = "SELF_DEALLOCATED";
111
+ /**
112
+ * An unknown or unexpected error occurred.
113
+ * Catch-all for errors that don't fit other categories.
114
+ * Check error message for details.
115
+ * @retryable unknown - Depends on underlying cause
116
+ */
117
+ IpayCodePushErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
118
+ return IpayCodePushErrorCode;
119
+ }({});
120
+
121
+ /**
122
+ * Type guard to check if an error is a IpayCodePushError
123
+ */
124
+ export function isIpayCodePushError(error) {
125
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && Object.values(IpayCodePushErrorCode).includes(error.code);
126
+ }
127
+
128
+ /**
129
+ * Base error class for Ipay Code Push
130
+ */
131
+ export class IpayCodePushError extends Error {
132
+ constructor(message) {
133
+ super(message);
134
+ this.name = "IpayCodePushError";
135
+ }
136
+ }
137
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["IpayCodePushErrorCode","isIpayCodePushError","error","code","Object","values","includes","IpayCodePushError","Error","constructor","message","name"],"sourceRoot":"../../src","sources":["error.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAYA,qBAAqB,0BAArBA,qBAAqB;EAC7B;EAEA;AACJ;AACA;AACA;AACA;EAPYA,qBAAqB;EAU7B;AACJ;AACA;AACA;AACA;EAdYA,qBAAqB;EAiB7B;EAEA;AACJ;AACA;AACA;AACA;EAvBYA,qBAAqB;EA0B7B;AACJ;AACA;AACA;AACA;AACA;EA/BYA,qBAAqB;EAkC7B;AACJ;AACA;AACA;AACA;AACA;EAvCYA,qBAAqB;EA0C7B;AACJ;AACA;AACA;AACA;AACA;EA/CYA,qBAAqB;EAkD7B;AACJ;AACA;AACA;AACA;AACA;EAvDYA,qBAAqB;EA0D7B;AACJ;AACA;AACA;AACA;AACA;EA/DYA,qBAAqB;EAkE7B;AACJ;AACA;AACA;AACA;AACA;EAvEYA,qBAAqB;EA0E7B;AACJ;AACA;AACA;AACA;AACA;AACA;EAhFYA,qBAAqB;EAmF7B;AACJ;AACA;AACA;AACA;AACA;EAxFYA,qBAAqB;EA2F7B;EACA;EAEA;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EAvGYA,qBAAqB;EA0G7B;AACJ;AACA;AACA;AACA;AACA;EA/GYA,qBAAqB;EAAA,OAArBA,qBAAqB;AAAA;;AAmHjC;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAC/BC,KAAc,EAC2C;EACzD,OACI,OAAOA,KAAK,KAAK,QAAQ,IACzBA,KAAK,KAAK,IAAI,IACd,MAAM,IAAIA,KAAK,IACf,OAAOA,KAAK,CAACC,IAAI,KAAK,QAAQ,IAC9BC,MAAM,CAACC,MAAM,CAACL,qBAAqB,CAAC,CAACM,QAAQ,CACzCJ,KAAK,CAACC,IACV,CAAC;AAET;;AAEA;AACA;AACA;AACA,OAAO,MAAMI,iBAAiB,SAASC,KAAK,CAAC;EACzCC,WAAWA,CAACC,OAAe,EAAE;IACzB,KAAK,CAACA,OAAO,CAAC;IACd,IAAI,CAACC,IAAI,GAAG,mBAAmB;EACnC;AACJ","ignoreList":[]}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ export const fetchUpdateInfo = async ({
4
+ url,
5
+ requestHeaders,
6
+ onError,
7
+ requestTimeout = 5000
8
+ }) => {
9
+ try {
10
+ const controller = new AbortController();
11
+ const timeoutId = setTimeout(() => {
12
+ controller.abort();
13
+ }, requestTimeout);
14
+ const headers = {
15
+ "Content-Type": "application/json",
16
+ ...requestHeaders
17
+ };
18
+ const response = await fetch(url, {
19
+ signal: controller.signal,
20
+ headers
21
+ });
22
+ clearTimeout(timeoutId);
23
+ if (response.status !== 200) {
24
+ throw new Error(response.statusText);
25
+ }
26
+ return response.json();
27
+ } catch (error) {
28
+ if (error instanceof Error && error.name === "AbortError") {
29
+ onError?.(new Error("Request timed out"));
30
+ } else {
31
+ onError?.(error);
32
+ }
33
+ return null;
34
+ }
35
+ };
36
+ //# sourceMappingURL=fetchUpdateInfo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["fetchUpdateInfo","url","requestHeaders","onError","requestTimeout","controller","AbortController","timeoutId","setTimeout","abort","headers","response","fetch","signal","clearTimeout","status","Error","statusText","json","error","name"],"sourceRoot":"../../src","sources":["fetchUpdateInfo.ts"],"mappings":";;AAEA,OAAO,MAAMA,eAAe,GAAG,MAAAA,CAAO;EAClCC,GAAG;EACHC,cAAc;EACdC,OAAO;EACPC,cAAc,GAAG;AAMrB,CAAC,KAAoC;EACjC,IAAI;IACA,MAAMC,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;IACxC,MAAMC,SAAS,GAAGC,UAAU,CAAC,MAAM;MAC/BH,UAAU,CAACI,KAAK,CAAC,CAAC;IACtB,CAAC,EAAEL,cAAc,CAAC;IAElB,MAAMM,OAAO,GAAG;MACZ,cAAc,EAAE,kBAAkB;MAClC,GAAGR;IACP,CAAC;IAED,MAAMS,QAAQ,GAAG,MAAMC,KAAK,CAACX,GAAG,EAAE;MAC9BY,MAAM,EAAER,UAAU,CAACQ,MAAM;MACzBH;IACJ,CAAC,CAAC;IAEFI,YAAY,CAACP,SAAS,CAAC;IAEvB,IAAII,QAAQ,CAACI,MAAM,KAAK,GAAG,EAAE;MACzB,MAAM,IAAIC,KAAK,CAACL,QAAQ,CAACM,UAAU,CAAC;IACxC;IAEA,OAAON,QAAQ,CAACO,IAAI,CAAC,CAAC;EAC1B,CAAC,CAAC,OAAOC,KAAc,EAAE;IAErB,IAAIA,KAAK,YAAYH,KAAK,IAAIG,KAAK,CAACC,IAAI,KAAK,YAAY,EAAE;MACvDjB,OAAO,GAAG,IAAIa,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC7C,CAAC,MAAM;MACHb,OAAO,GAAGgB,KAAc,CAAC;IAC7B;IAEA,OAAO,IAAI;EACf;AACJ,CAAC","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Global type definitions for IpayCodePush
5
+ */
6
+
7
+ export {};
8
+ //# sourceMappingURL=global.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["global.d.ts"],"mappings":";;AAAA;AACA;AACA;;AAoBA","ignoreList":[]}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useLayoutEffect, useRef } from "react";
4
+ export function useEventCallback(fn) {
5
+ const callbackRef = useRef(() => {
6
+ throw new Error("Cannot call an event handler while rendering.");
7
+ });
8
+ useLayoutEffect(() => {
9
+ callbackRef.current = fn;
10
+ }, [fn]);
11
+ return useCallback((...args) => callbackRef.current?.(...args), [callbackRef]);
12
+ }
13
+ //# sourceMappingURL=useEventCallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useCallback","useLayoutEffect","useRef","useEventCallback","fn","callbackRef","Error","current","args"],"sourceRoot":"../../../src","sources":["hooks/useEventCallback.ts"],"mappings":";;AAAA,SAASA,WAAW,EAAEC,eAAe,EAAEC,MAAM,QAAQ,OAAO;AAc5D,OAAO,SAASC,gBAAgBA,CAC5BC,EAA0B,EACJ;EACtB,MAAMC,WAAW,GAAGH,MAAM,CAAyB,MAAM;IACrD,MAAM,IAAII,KAAK,CAAC,+CAA+C,CAAC;EACpE,CAAC,CAAC;EAEFL,eAAe,CAAC,MAAM;IAClBI,WAAW,CAACE,OAAO,GAAGH,EAAE;EAC5B,CAAC,EAAE,CAACA,EAAE,CAAC,CAAC;EAER,OAAOJ,WAAW,CACd,CAAC,GAAGQ,IAAU,KAAKH,WAAW,CAACE,OAAO,GAAG,GAAGC,IAAI,CAAC,EACjD,CAACH,WAAW,CAChB,CAAC;AACL","ignoreList":[]}