react-native-pdf-jsi 3.3.1 → 3.4.2

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 (37) hide show
  1. package/README.md +45 -6
  2. package/android/src/main/java/org/wonday/pdf/FileManager.java +2 -0
  3. package/android/src/main/java/org/wonday/pdf/MemoryMappedCache.java +1 -1
  4. package/android/src/main/java/org/wonday/pdf/PDFExporter.java +0 -54
  5. package/android/src/main/java/org/wonday/pdf/PdfManager.java +5 -0
  6. package/android/src/main/java/org/wonday/pdf/PdfView.java +12 -2
  7. package/android/src/main/java/org/wonday/pdf/RNPDFJSIPackage.java +50 -0
  8. package/android/src/main/java/org/wonday/pdf/RNPDFPackage.java +0 -1
  9. package/fabric/RNPDFPdfNativeComponent.js +8 -3
  10. package/index.js +148 -23
  11. package/ios/RNPDFPdf/RNPDFPdfView.h +19 -1
  12. package/ios/RNPDFPdf/RNPDFPdfView.mm +154 -44
  13. package/package.json +11 -6
  14. package/src/PDFJSI.js +29 -4
  15. package/src/components/AnalyticsPanel.jsx +22 -9
  16. package/src/managers/AnalyticsManager.js +1 -5
  17. package/src/managers/BookmarkManager.js +2 -10
  18. package/src/managers/CacheManager.js +14 -1
  19. package/src/managers/ExportManager.js +5 -20
  20. package/src/utils/ErrorHandler.js +0 -11
  21. package/src/utils/PDFTextExtractor.js +82 -0
  22. package/android/.gradle/5.6.1/fileChanges/last-build.bin +0 -0
  23. package/android/.gradle/5.6.1/fileHashes/fileHashes.lock +0 -0
  24. package/android/.gradle/5.6.1/gc.properties +0 -0
  25. package/android/.gradle/8.5/checksums/checksums.lock +0 -0
  26. package/android/.gradle/8.5/checksums/md5-checksums.bin +0 -0
  27. package/android/.gradle/8.5/checksums/sha1-checksums.bin +0 -0
  28. package/android/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock +0 -0
  29. package/android/.gradle/8.5/dependencies-accessors/gc.properties +0 -0
  30. package/android/.gradle/8.5/executionHistory/executionHistory.lock +0 -0
  31. package/android/.gradle/8.5/fileChanges/last-build.bin +0 -0
  32. package/android/.gradle/8.5/fileHashes/fileHashes.lock +0 -0
  33. package/android/.gradle/8.5/gc.properties +0 -0
  34. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  35. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  36. package/android/.gradle/vcs-1/gc.properties +0 -0
  37. package/android/src/main/java/org/wonday/pdf/LicenseVerifier.java +0 -311
@@ -0,0 +1,82 @@
1
+ /**
2
+ * PDFTextExtractor - Text Extraction from PDF Files
3
+ *
4
+ * Handles extracting text content from PDF files for export functionality
5
+ *
6
+ * @author Punith M
7
+ * @version 1.0.0
8
+ */
9
+
10
+ /**
11
+ * PDFTextExtractor Class
12
+ */
13
+ class PDFTextExtractor {
14
+ /**
15
+ * Check if text extraction is available
16
+ * @returns {boolean} True if text extraction is available
17
+ */
18
+ static isTextExtractionAvailable() {
19
+ // For development: Always return true
20
+ // In production, this would check if native modules are available
21
+ return true;
22
+ }
23
+
24
+ /**
25
+ * Extract text from a specific page
26
+ * @param {string} filePath - Path to PDF file
27
+ * @param {number} pageNumber - Page number (0-indexed)
28
+ * @returns {Promise<string>} Extracted text content
29
+ */
30
+ static async extractTextFromPage(filePath, pageNumber) {
31
+ // For development: Return placeholder text
32
+ // In production, this would use native modules to extract text
33
+ console.warn(`📄 PDFTextExtractor: Text extraction not fully implemented. Returning placeholder for page ${pageNumber}`);
34
+ return `[Text extraction from page ${pageNumber + 1} not yet implemented]`;
35
+ }
36
+
37
+ /**
38
+ * Extract text from multiple pages
39
+ * @param {string} filePath - Path to PDF file
40
+ * @param {Array<number>} pageIndices - Array of page indices (0-indexed)
41
+ * @returns {Promise<Object>} Map of page index to extracted text
42
+ */
43
+ static async extractTextFromPages(filePath, pageIndices) {
44
+ const textMap = {};
45
+
46
+ for (const pageIndex of pageIndices) {
47
+ textMap[pageIndex] = await this.extractTextFromPage(filePath, pageIndex);
48
+ }
49
+
50
+ return textMap;
51
+ }
52
+
53
+ /**
54
+ * Extract text from all pages
55
+ * @param {string} filePath - Path to PDF file
56
+ * @returns {Promise<Object>} Map of page index to extracted text
57
+ */
58
+ static async extractAllText(filePath) {
59
+ // For development: Return placeholder for first few pages
60
+ // In production, this would extract from all pages
61
+ console.warn('📄 PDFTextExtractor: Full text extraction not yet implemented. Returning placeholder data.');
62
+
63
+ // Return placeholder data structure
64
+ return {
65
+ 0: '[Text extraction from all pages not yet implemented]',
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Get page count
71
+ * @param {string} filePath - Path to PDF file
72
+ * @returns {Promise<number>} Number of pages
73
+ */
74
+ static async getPageCount(filePath) {
75
+ // Placeholder implementation
76
+ // In production, this would use native modules
77
+ return 1;
78
+ }
79
+ }
80
+
81
+ export default PDFTextExtractor;
82
+
File without changes
File without changes
@@ -1,2 +0,0 @@
1
- #Thu Oct 02 20:04:14 IST 2025
2
- gradle.version=8.5
File without changes
@@ -1,311 +0,0 @@
1
- package org.wonday.pdf;
2
-
3
- import android.content.Context;
4
- import android.content.pm.ApplicationInfo;
5
- import android.content.pm.PackageManager;
6
- import android.util.Log;
7
-
8
- import com.facebook.react.bridge.ReactApplicationContext;
9
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
10
- import com.facebook.react.bridge.ReactMethod;
11
- import com.facebook.react.bridge.Promise;
12
- import com.facebook.react.bridge.ReadableMap;
13
- import com.facebook.react.bridge.WritableMap;
14
- import com.facebook.react.bridge.Arguments;
15
-
16
- import java.security.MessageDigest;
17
- import java.security.NoSuchAlgorithmException;
18
- import java.util.HashMap;
19
- import java.util.Map;
20
-
21
- import javax.crypto.Mac;
22
- import javax.crypto.spec.SecretKeySpec;
23
-
24
- public class LicenseVerifier extends ReactContextBaseJavaModule {
25
- private static final String TAG = "LicenseVerifier";
26
-
27
- // License info cache
28
- private String currentLicenseKey = null;
29
- private String currentTier = null;
30
- private long expiryTimestamp = 0;
31
- private String currentEmail = null;
32
-
33
- // Secret key for HMAC verification (from app config)
34
- private String secretKey = null;
35
-
36
- public LicenseVerifier(ReactApplicationContext reactContext) {
37
- super(reactContext);
38
- loadSecretKey();
39
- }
40
-
41
- @Override
42
- public String getName() {
43
- return "LicenseVerifier";
44
- }
45
-
46
- /**
47
- * Load secret key from AndroidManifest meta-data
48
- */
49
- private void loadSecretKey() {
50
- try {
51
- Context context = getReactApplicationContext();
52
- ApplicationInfo appInfo = context.getPackageManager()
53
- .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
54
-
55
- if (appInfo.metaData != null) {
56
- secretKey = appInfo.metaData.getString("com.reactnativepdf.license.secret");
57
- }
58
-
59
- if (secretKey == null) {
60
- Log.w(TAG, "License secret not found in AndroidManifest");
61
- secretKey = "default-secret-change-in-production";
62
- }
63
- } catch (Exception e) {
64
- Log.e(TAG, "Error loading license secret", e);
65
- secretKey = "default-secret-change-in-production";
66
- }
67
- }
68
-
69
- /**
70
- * Set license information from JS
71
- */
72
- @ReactMethod
73
- public void setLicenseInfo(ReadableMap licenseInfo, Promise promise) {
74
- try {
75
- if (licenseInfo == null) {
76
- promise.reject("INVALID_LICENSE", "License info is null");
77
- return;
78
- }
79
-
80
- String licenseKey = licenseInfo.getString("key");
81
- String tier = licenseInfo.getString("tier");
82
- String email = licenseInfo.getString("email");
83
- String expiresAt = licenseInfo.getString("expiresAt");
84
-
85
- if (licenseKey == null || tier == null) {
86
- promise.reject("INVALID_LICENSE", "Missing required license fields");
87
- return;
88
- }
89
-
90
- // Verify license key format and checksum
91
- if (!verifyLicenseKey(licenseKey)) {
92
- promise.reject("INVALID_LICENSE", "Invalid license key format or checksum");
93
- return;
94
- }
95
-
96
- // Parse expiry timestamp
97
- long expiry = 0;
98
- if (expiresAt != null && !expiresAt.isEmpty()) {
99
- try {
100
- expiry = java.time.Instant.parse(expiresAt).toEpochMilli();
101
- } catch (Exception e) {
102
- Log.w(TAG, "Invalid expiry date format", e);
103
- }
104
- }
105
-
106
- // Cache license info
107
- this.currentLicenseKey = licenseKey;
108
- this.currentTier = tier;
109
- this.currentEmail = email;
110
- this.expiryTimestamp = expiry;
111
-
112
- Log.i(TAG, "License set: " + tier + " for " + email);
113
- promise.resolve(true);
114
-
115
- } catch (Exception e) {
116
- Log.e(TAG, "Error setting license info", e);
117
- promise.reject("LICENSE_ERROR", e.getMessage());
118
- }
119
- }
120
-
121
- /**
122
- * Require Pro license for a feature
123
- */
124
- @ReactMethod
125
- public void requirePro(String featureName, Promise promise) {
126
- try {
127
- if (!isProActive()) {
128
- WritableMap error = Arguments.createMap();
129
- error.putString("code", "LICENSE_REQUIRED");
130
- error.putString("feature", featureName);
131
- error.putString("message", featureName + " requires a Pro license");
132
- promise.reject("LICENSE_REQUIRED", error);
133
- return;
134
- }
135
-
136
- promise.resolve(true);
137
- } catch (Exception e) {
138
- Log.e(TAG, "Error checking Pro license", e);
139
- promise.reject("LICENSE_ERROR", e.getMessage());
140
- }
141
- }
142
-
143
- /**
144
- * Check if Pro license is active
145
- */
146
- public boolean isProActive() {
147
- // 🧪 TESTING MODE: Always return true for testing
148
- Log.i(TAG, "🧪 TESTING MODE: isProActive() returning true for testing");
149
- return true;
150
-
151
- /* PRODUCTION CODE (commented out for testing):
152
- if (currentLicenseKey == null || currentTier == null) {
153
- Log.w(TAG, "No license set");
154
- return false;
155
- }
156
-
157
- // Check if license is expired
158
- if (expiryTimestamp > 0 && System.currentTimeMillis() > expiryTimestamp) {
159
- Log.w(TAG, "License expired");
160
- return false;
161
- }
162
-
163
- // Check if tier is Pro or higher
164
- return isProTier(currentTier);
165
- */
166
- }
167
-
168
- /**
169
- * Check if tier is Pro or higher
170
- */
171
- private boolean isProTier(String tier) {
172
- if (tier == null) return false;
173
-
174
- switch (tier.toLowerCase()) {
175
- case "solo":
176
- case "professional":
177
- case "team":
178
- case "enterprise":
179
- return true;
180
- default:
181
- return false;
182
- }
183
- }
184
-
185
- /**
186
- * Get current license tier
187
- */
188
- @ReactMethod
189
- public void getTier(Promise promise) {
190
- try {
191
- if (currentTier == null) {
192
- promise.resolve("free");
193
- } else {
194
- promise.resolve(currentTier);
195
- }
196
- } catch (Exception e) {
197
- Log.e(TAG, "Error getting tier", e);
198
- promise.reject("LICENSE_ERROR", e.getMessage());
199
- }
200
- }
201
-
202
- /**
203
- * Check if license is expired
204
- */
205
- @ReactMethod
206
- public void isExpired(Promise promise) {
207
- try {
208
- boolean expired = expiryTimestamp > 0 && System.currentTimeMillis() > expiryTimestamp;
209
- promise.resolve(expired);
210
- } catch (Exception e) {
211
- Log.e(TAG, "Error checking expiry", e);
212
- promise.reject("LICENSE_ERROR", e.getMessage());
213
- }
214
- }
215
-
216
- /**
217
- * Verify license key format and checksum
218
- */
219
- private boolean verifyLicenseKey(String licenseKey) {
220
- if (licenseKey == null || licenseKey.length() != 19) {
221
- return false;
222
- }
223
-
224
- // Check format: X###-####-####-####
225
- if (!licenseKey.matches("^[SPTE][A-F0-9]{3}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}$")) {
226
- return false;
227
- }
228
-
229
- // Verify checksum
230
- try {
231
- String[] parts = licenseKey.split("-");
232
- String prefix = parts[0].substring(0, 1);
233
- String seg1 = parts[0].substring(1);
234
- String seg2 = parts[1];
235
- String seg3 = parts[2];
236
- String checksum = parts[3];
237
-
238
- String data = prefix + seg1 + seg2 + seg3;
239
- String expectedChecksum = generateChecksum(data);
240
-
241
- return checksum.equals(expectedChecksum);
242
- } catch (Exception e) {
243
- Log.e(TAG, "Error verifying license key", e);
244
- return false;
245
- }
246
- }
247
-
248
- /**
249
- * Generate checksum for license key
250
- */
251
- private String generateChecksum(String data) {
252
- try {
253
- Mac mac = Mac.getInstance("HmacSHA256");
254
- SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
255
- mac.init(secretKeySpec);
256
-
257
- byte[] hash = mac.doFinal(data.getBytes());
258
- StringBuilder hexString = new StringBuilder();
259
-
260
- for (byte b : hash) {
261
- String hex = Integer.toHexString(0xff & b);
262
- if (hex.length() == 1) {
263
- hexString.append('0');
264
- }
265
- hexString.append(hex);
266
- }
267
-
268
- return hexString.toString().toUpperCase().substring(0, 4);
269
- } catch (Exception e) {
270
- Log.e(TAG, "Error generating checksum", e);
271
- return "0000";
272
- }
273
- }
274
-
275
- /**
276
- * Get license info for debugging
277
- */
278
- @ReactMethod
279
- public void getLicenseInfo(Promise promise) {
280
- try {
281
- WritableMap info = Arguments.createMap();
282
- info.putString("key", currentLicenseKey);
283
- info.putString("tier", currentTier);
284
- info.putString("email", currentEmail);
285
- info.putDouble("expiresAt", expiryTimestamp);
286
- info.putBoolean("isPro", isProActive());
287
- promise.resolve(info);
288
- } catch (Exception e) {
289
- Log.e(TAG, "Error getting license info", e);
290
- promise.reject("LICENSE_ERROR", e.getMessage());
291
- }
292
- }
293
-
294
- /**
295
- * Clear license info
296
- */
297
- @ReactMethod
298
- public void clearLicense(Promise promise) {
299
- try {
300
- currentLicenseKey = null;
301
- currentTier = null;
302
- currentEmail = null;
303
- expiryTimestamp = 0;
304
- Log.i(TAG, "License cleared");
305
- promise.resolve(true);
306
- } catch (Exception e) {
307
- Log.e(TAG, "Error clearing license", e);
308
- promise.reject("LICENSE_ERROR", e.getMessage());
309
- }
310
- }
311
- }