@unvired/react-native-unvired-sdk 0.0.11 → 0.0.13

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 (52) hide show
  1. package/BuildNo.txt +1 -1
  2. package/README.md +884 -255
  3. package/dist/PlatformAdapter.d.ts +57 -0
  4. package/dist/PlatformAdapter.js +116 -0
  5. package/dist/database/Database.d.ts +71 -0
  6. package/dist/database/Database.js +156 -0
  7. package/dist/database/DatabaseManager.d.ts +32 -0
  8. package/dist/database/DatabaseManager.js +323 -0
  9. package/dist/database/index.d.ts +6 -0
  10. package/dist/database/index.js +5 -0
  11. package/dist/database/types.d.ts +94 -0
  12. package/dist/database/types.js +4 -0
  13. package/dist/device-info/BaseDeviceInfo.d.ts +39 -0
  14. package/dist/device-info/BaseDeviceInfo.js +116 -0
  15. package/dist/device-info/DeviceInfo.d.ts +9 -0
  16. package/dist/device-info/DeviceInfo.js +11 -0
  17. package/dist/device-info/DeviceInfo.types.d.ts +11 -0
  18. package/dist/device-info/DeviceInfo.types.js +3 -0
  19. package/dist/device-info/index.d.ts +3 -0
  20. package/dist/device-info/index.js +3 -0
  21. package/dist/file-system/BaseFileSystem.d.ts +60 -0
  22. package/dist/file-system/BaseFileSystem.js +194 -0
  23. package/dist/file-system/FileSystem.d.ts +9 -0
  24. package/dist/file-system/FileSystem.js +11 -0
  25. package/dist/file-system/FileSystem.types.d.ts +11 -0
  26. package/dist/file-system/FileSystem.types.js +3 -0
  27. package/dist/file-system/index.d.ts +3 -0
  28. package/dist/file-system/index.js +3 -0
  29. package/dist/local-storage/index.d.ts +1 -0
  30. package/dist/local-storage/index.js +2 -0
  31. package/dist/local-storage/localStorage.d.ts +48 -0
  32. package/dist/local-storage/localStorage.js +123 -0
  33. package/dist/logger/BaseLogger.js +8 -13
  34. package/dist/logger/{Logger.js → index.js} +1 -4
  35. package/dist/logger/services/LoggerNative.js +5 -5
  36. package/dist/logger/services/LoggerWindows.d.ts +20 -0
  37. package/dist/logger/services/LoggerWindows.js +225 -0
  38. package/dist/main.d.ts +13 -0
  39. package/dist/main.js +28 -0
  40. package/dist/push-notification/BasePushNotification.d.ts +52 -0
  41. package/dist/push-notification/BasePushNotification.js +180 -0
  42. package/dist/push-notification/PushNotification.d.ts +9 -0
  43. package/dist/push-notification/PushNotification.js +11 -0
  44. package/dist/push-notification/PushNotification.types.d.ts +12 -0
  45. package/dist/push-notification/PushNotification.types.js +3 -0
  46. package/dist/push-notification/index.d.ts +3 -0
  47. package/dist/push-notification/index.js +3 -0
  48. package/example/USAGE_EXAMPLE.ts +167 -0
  49. package/package.json +17 -5
  50. package/dist/index.d.ts +0 -3
  51. package/dist/index.js +0 -4
  52. /package/dist/logger/{Logger.d.ts → index.d.ts} +0 -0
@@ -0,0 +1,225 @@
1
+ import * as pako from 'pako';
2
+ // Import with null safety
3
+ let RNFS = null;
4
+ try {
5
+ RNFS = require('@dr.pogodin/react-native-fs');
6
+ if (!RNFS || !RNFS.DocumentDirectoryPath) {
7
+ console.error('❌ @dr.pogodin/react-native-fs is not properly linked.');
8
+ RNFS = null;
9
+ }
10
+ }
11
+ catch (e) {
12
+ console.error('❌ @dr.pogodin/react-native-fs module not found.');
13
+ }
14
+ export class LoggerWindows {
15
+ constructor() {
16
+ this.isRotating = false; // Rotation lock to prevent concurrent rotations
17
+ this.isAvailable = false;
18
+ this.writeQueue = [];
19
+ this.isWriting = false;
20
+ const dir = 'unvired_logs';
21
+ const file = 'applog.txt'; // main log file
22
+ if (!RNFS) {
23
+ console.warn('⚠️ LoggerWindows: RNFS not available, logging to file system disabled');
24
+ this.logDir = '';
25
+ this.logFile = '';
26
+ this.backupZip = '';
27
+ return;
28
+ }
29
+ this.isAvailable = true;
30
+ // Windows specifically uses DocumentDirectoryPath (AppData/Local/Packages/.../LocalState)
31
+ this.logDir = `${RNFS.DocumentDirectoryPath}/${dir}`;
32
+ this.logFile = `${this.logDir}/${file}`;
33
+ this.backupZip = `${this.logDir}/backuplog.zip`;
34
+ }
35
+ async init() {
36
+ if (!this.isAvailable || !this.logDir || !RNFS)
37
+ return;
38
+ try {
39
+ if (!(await RNFS.exists(this.logDir)))
40
+ await RNFS.mkdir(this.logDir);
41
+ if (!(await RNFS.exists(this.logFile)))
42
+ await RNFS.writeFile(this.logFile, '', 'utf8');
43
+ }
44
+ catch (e) {
45
+ console.error('❌ LoggerWindows init error:', e);
46
+ }
47
+ }
48
+ async writeLine(line, maxSize) {
49
+ if (!this.isAvailable || !RNFS)
50
+ return;
51
+ // Push to queue
52
+ this.writeQueue.push(line);
53
+ // Trigger processing if not already running
54
+ this.processWriteQueue(maxSize);
55
+ }
56
+ async processWriteQueue(maxSize) {
57
+ if (this.isWriting)
58
+ return;
59
+ this.isWriting = true;
60
+ try {
61
+ await this.ensureDir();
62
+ while (this.writeQueue.length > 0) {
63
+ // Peek at the chunk of lines to write?
64
+ // Writing one by one is safe but slow.
65
+ // Let's write one by one for safety first.
66
+ const line = this.writeQueue.shift();
67
+ if (!line)
68
+ continue;
69
+ try {
70
+ await RNFS.appendFile(this.logFile, line + '\n', 'utf8');
71
+ // Check rotation (only occasionally to avoid stat spam?)
72
+ // We can check every N writes or if queue is empty
73
+ if (!this.isRotating && this.writeQueue.length === 0) {
74
+ try {
75
+ const stat = await RNFS.stat(this.logFile);
76
+ if (Number(stat.size) >= maxSize) {
77
+ this.rotateLog();
78
+ }
79
+ }
80
+ catch (statErr) {
81
+ // ignore
82
+ }
83
+ }
84
+ }
85
+ catch (filesErr) {
86
+ // If file is locked, we might want to put line back?
87
+ // or just retry?
88
+ // For now, retry once then drop to avoid infinite loop
89
+ console.warn('⚠️ Write failed, retrying once:', filesErr.message);
90
+ try {
91
+ await new Promise(r => setTimeout(r, 50)); // small delay
92
+ await RNFS.appendFile(this.logFile, line + '\n', 'utf8');
93
+ }
94
+ catch (retryErr) {
95
+ console.error('❌ Failed to write log line after retry:', retryErr);
96
+ }
97
+ }
98
+ }
99
+ }
100
+ catch (e) {
101
+ console.error('❌ LoggerWindows queue error:', e);
102
+ }
103
+ finally {
104
+ this.isWriting = false;
105
+ // If logs came in while we were finishing, trigger again
106
+ if (this.writeQueue.length > 0) {
107
+ this.processWriteQueue(maxSize);
108
+ }
109
+ }
110
+ }
111
+ async ensureDir() {
112
+ if (!this.isAvailable || !this.logDir || !RNFS)
113
+ return;
114
+ try {
115
+ if (!(await RNFS.exists(this.logDir)))
116
+ await RNFS.mkdir(this.logDir);
117
+ }
118
+ catch (e) {
119
+ // Ignore if dir already exists race condition
120
+ }
121
+ }
122
+ async rotateLog() {
123
+ if (!this.isAvailable || !RNFS) {
124
+ return;
125
+ }
126
+ // Prevent concurrent rotations
127
+ if (this.isRotating) {
128
+ console.log('⏭️ Rotation already in progress, skipping...');
129
+ return;
130
+ }
131
+ this.isRotating = true;
132
+ try {
133
+ console.log('🔄 Starting log rotation (using pako gzip)...');
134
+ // Check if log file exists
135
+ if (!(await RNFS.exists(this.logFile))) {
136
+ return;
137
+ }
138
+ // Step 1: Read current log content
139
+ // Reading whole file into memory might be heavy for huge files,
140
+ // but for mobile logs generally acceptable (e.g. 5-10MB limit)
141
+ const content = await RNFS.readFile(this.logFile, 'utf8');
142
+ // Step 2: Compress content using Pako (gzip)
143
+ const binaryData = pako.gzip(content);
144
+ // Step 3: Convert binary to base64 for writing using Buffer (more robust)
145
+ // React Native environment usually has Buffer polyfill, or we use a chunked approach
146
+ const base64 = Buffer.from(binaryData).toString('base64');
147
+ // Step 4: Write to backup file (overwriting old one)
148
+ // We rename extensions to .gz to be accurate, or keep .zip if requirement is strict
149
+ // (but technically it IS a gzip stream, not a PKZip archive)
150
+ // User asked for base64 return, so storing it purely is fine.
151
+ await RNFS.writeFile(this.backupZip, base64, 'base64');
152
+ console.log('✅ Backup created successfully');
153
+ // Step 5: Clear current log
154
+ await RNFS.writeFile(this.logFile, '', 'utf8');
155
+ console.log('✔ Log rotation completed successfully');
156
+ }
157
+ catch (e) {
158
+ console.error('❌ Logger rotation error:', e);
159
+ // Recovery: ensure log file exists
160
+ try {
161
+ if (!(await RNFS.exists(this.logFile))) {
162
+ await RNFS.writeFile(this.logFile, '', 'utf8');
163
+ }
164
+ }
165
+ catch { }
166
+ }
167
+ finally {
168
+ this.isRotating = false;
169
+ }
170
+ }
171
+ // ------------------------
172
+ // Public accessors
173
+ // ------------------------
174
+ async getLogFileURL() {
175
+ if (!this.isAvailable)
176
+ return '';
177
+ return this.logFile;
178
+ }
179
+ async getLogFileContent() {
180
+ if (!this.isAvailable || !RNFS)
181
+ return '';
182
+ try {
183
+ if (await RNFS.exists(this.logFile)) {
184
+ return await RNFS.readFile(this.logFile, 'utf8');
185
+ }
186
+ return '';
187
+ }
188
+ catch (e) {
189
+ return '';
190
+ }
191
+ }
192
+ async getBackupLogFileContent() {
193
+ if (!this.isAvailable || !RNFS)
194
+ return null;
195
+ try {
196
+ // Do NOT force rotation. Only return existing backup if present.
197
+ // await this.rotateLog();
198
+ if (await RNFS.exists(this.backupZip)) {
199
+ // It's already written as base64 in rotateLog step via writeFile('base64'),
200
+ // but readFile('base64') reads the file content and returns base64.
201
+ // Wait, writeFile(path, data, 'base64') expects data to BE base64.
202
+ // readFile(path, 'base64') reads binary and RETURNS base64.
203
+ // Yes, so we can just read it back.
204
+ return await RNFS.readFile(this.backupZip, 'base64');
205
+ }
206
+ return null;
207
+ }
208
+ catch (e) {
209
+ console.error('❌ LoggerWindows getBackupLogFileContent error:', e);
210
+ return null;
211
+ }
212
+ }
213
+ async clear() {
214
+ if (!this.isAvailable || !RNFS)
215
+ return;
216
+ try {
217
+ await RNFS.writeFile(this.logFile, '', 'utf8');
218
+ if (await RNFS.exists(this.backupZip))
219
+ await RNFS.unlink(this.backupZip);
220
+ }
221
+ catch (e) {
222
+ // silent
223
+ }
224
+ }
225
+ }
package/dist/main.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ export { Logger, logger } from './logger';
2
+ export type { LogLevel, ILogger, ILoggerImplementation } from './logger';
3
+ export { LocalStorage } from './local-storage';
4
+ export { DatabaseManager, Database, createDatabase } from './database';
5
+ export type { IDatabaseAdapter, DatabaseOptions, ExecuteOptions, SaveWebDBOptions, ExportWebDBOptions, DeleteUserDataOptions, SuccessCallback, ErrorCallback, ResultCallback, SQLResultSet, SQLTransaction, SQLiteDatabase } from './database';
6
+ export { DeviceInfo } from './device-info';
7
+ export type { IDeviceInfo } from './device-info';
8
+ export { FileSystem } from './file-system';
9
+ export type { IFileEntry } from './file-system';
10
+ export { PushNotification } from './push-notification';
11
+ export type { IPushNotificationAdapter } from './push-notification';
12
+ export { ReactNativePlatformAdapter, getPlatformAdapter, resetPlatformAdapter, DatabaseType } from './PlatformAdapter';
13
+ export type { IPlatformAdapter, ILoggerAdapter, IStorageAdapter } from './PlatformAdapter';
package/dist/main.js ADDED
@@ -0,0 +1,28 @@
1
+ // ============================================
2
+ // Logger Module
3
+ // ============================================
4
+ export { Logger, logger } from './logger';
5
+ // ============================================
6
+ // Local Storage Module
7
+ // ============================================
8
+ export { LocalStorage } from './local-storage';
9
+ // ============================================
10
+ // Database Module
11
+ // ============================================
12
+ export { DatabaseManager, Database, createDatabase } from './database';
13
+ // ============================================
14
+ // Device Info Module
15
+ // ============================================
16
+ export { DeviceInfo } from './device-info';
17
+ // ============================================
18
+ // File System Module
19
+ // ============================================
20
+ export { FileSystem } from './file-system';
21
+ // ============================================
22
+ // Push Notification Module
23
+ // ============================================
24
+ export { PushNotification } from './push-notification';
25
+ // ============================================
26
+ // Platform Adapter
27
+ // ============================================
28
+ export { ReactNativePlatformAdapter, getPlatformAdapter, resetPlatformAdapter, DatabaseType } from './PlatformAdapter';
@@ -0,0 +1,52 @@
1
+ import { IPushNotificationAdapter } from './PushNotification.types';
2
+ /**
3
+ * Base Push Notification Class
4
+ * Handles push notifications using Firebase Cloud Messaging
5
+ */
6
+ export declare class BasePushNotification implements IPushNotificationAdapter {
7
+ private tokenRefreshCallback;
8
+ private messageCallback;
9
+ private backgroundMessageCallback;
10
+ /**
11
+ * Request push notification permission
12
+ */
13
+ requestPermission(options?: {
14
+ forceShow?: boolean;
15
+ }): Promise<void>;
16
+ /**
17
+ * Get FCM token
18
+ */
19
+ getToken(): Promise<string>;
20
+ /**
21
+ * Listen for token refresh
22
+ */
23
+ onTokenRefresh(callback: (token: string) => void): void;
24
+ /**
25
+ * Listen for foreground messages
26
+ */
27
+ onMessage(callback: (message: any) => void): void;
28
+ /**
29
+ * Listen for background messages
30
+ */
31
+ onBackgroundMessage(callback: (message: any) => void): void;
32
+ /**
33
+ * Check if device supports push notifications
34
+ */
35
+ static isSupported(): Promise<boolean>;
36
+ /**
37
+ * Delete FCM token
38
+ */
39
+ deleteToken(): Promise<void>;
40
+ /**
41
+ * Get initial notification (app opened from notification)
42
+ */
43
+ getInitialNotification(): Promise<any | null>;
44
+ /**
45
+ * Subscribe to topic
46
+ */
47
+ subscribeToTopic(topic: string): Promise<void>;
48
+ /**
49
+ * Unsubscribe from topic
50
+ */
51
+ unsubscribeFromTopic(topic: string): Promise<void>;
52
+ }
@@ -0,0 +1,180 @@
1
+ // BasePushNotification.ts
2
+ // Base push notification implementation
3
+ let messaging;
4
+ let FirebaseMessagingTypes;
5
+ try {
6
+ const firebaseMessaging = require('@react-native-firebase/messaging');
7
+ messaging = firebaseMessaging.default;
8
+ FirebaseMessagingTypes = firebaseMessaging.FirebaseMessagingTypes;
9
+ }
10
+ catch (error) {
11
+ console.warn('Firebase messaging not installed. Push notifications will not work.');
12
+ }
13
+ /**
14
+ * Base Push Notification Class
15
+ * Handles push notifications using Firebase Cloud Messaging
16
+ */
17
+ export class BasePushNotification {
18
+ constructor() {
19
+ this.tokenRefreshCallback = null;
20
+ this.messageCallback = null;
21
+ this.backgroundMessageCallback = null;
22
+ }
23
+ /**
24
+ * Request push notification permission
25
+ */
26
+ async requestPermission(options = {}) {
27
+ if (!messaging) {
28
+ throw new Error('Firebase messaging is not installed');
29
+ }
30
+ try {
31
+ const authStatus = await messaging().requestPermission();
32
+ const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
33
+ authStatus === messaging.AuthorizationStatus.PROVISIONAL;
34
+ if (enabled) {
35
+ console.log('Push notification permission granted:', authStatus);
36
+ }
37
+ else {
38
+ console.log('Push notification permission denied');
39
+ }
40
+ }
41
+ catch (error) {
42
+ console.error('Error requesting push notification permission:', error);
43
+ throw error;
44
+ }
45
+ }
46
+ /**
47
+ * Get FCM token
48
+ */
49
+ async getToken() {
50
+ if (!messaging) {
51
+ throw new Error('Firebase messaging is not installed');
52
+ }
53
+ try {
54
+ const token = await messaging().getToken();
55
+ console.log('FCM Token:', token);
56
+ return token;
57
+ }
58
+ catch (error) {
59
+ console.error('Error getting FCM token:', error);
60
+ throw error;
61
+ }
62
+ }
63
+ /**
64
+ * Listen for token refresh
65
+ */
66
+ onTokenRefresh(callback) {
67
+ if (!messaging)
68
+ return;
69
+ this.tokenRefreshCallback = callback;
70
+ messaging().onTokenRefresh((token) => {
71
+ console.log('FCM Token refreshed:', token);
72
+ if (this.tokenRefreshCallback) {
73
+ this.tokenRefreshCallback(token);
74
+ }
75
+ });
76
+ }
77
+ /**
78
+ * Listen for foreground messages
79
+ */
80
+ onMessage(callback) {
81
+ if (!messaging)
82
+ return;
83
+ this.messageCallback = callback;
84
+ messaging().onMessage(async (remoteMessage) => {
85
+ console.log('Foreground message received:', remoteMessage);
86
+ if (this.messageCallback) {
87
+ this.messageCallback(remoteMessage);
88
+ }
89
+ });
90
+ }
91
+ /**
92
+ * Listen for background messages
93
+ */
94
+ onBackgroundMessage(callback) {
95
+ if (!messaging)
96
+ return;
97
+ this.backgroundMessageCallback = callback;
98
+ messaging().setBackgroundMessageHandler(async (remoteMessage) => {
99
+ console.log('Background message received:', remoteMessage);
100
+ if (this.backgroundMessageCallback) {
101
+ this.backgroundMessageCallback(remoteMessage);
102
+ }
103
+ });
104
+ }
105
+ /**
106
+ * Check if device supports push notifications
107
+ */
108
+ static async isSupported() {
109
+ if (!messaging)
110
+ return false;
111
+ try {
112
+ return await messaging().isDeviceRegisteredForRemoteMessages();
113
+ }
114
+ catch (error) {
115
+ return false;
116
+ }
117
+ }
118
+ /**
119
+ * Delete FCM token
120
+ */
121
+ async deleteToken() {
122
+ if (!messaging) {
123
+ throw new Error('Firebase messaging is not installed');
124
+ }
125
+ try {
126
+ await messaging().deleteToken();
127
+ console.log('FCM token deleted');
128
+ }
129
+ catch (error) {
130
+ console.error('Error deleting FCM token:', error);
131
+ throw error;
132
+ }
133
+ }
134
+ /**
135
+ * Get initial notification (app opened from notification)
136
+ */
137
+ async getInitialNotification() {
138
+ if (!messaging)
139
+ return null;
140
+ try {
141
+ return await messaging().getInitialNotification();
142
+ }
143
+ catch (error) {
144
+ console.error('Error getting initial notification:', error);
145
+ return null;
146
+ }
147
+ }
148
+ /**
149
+ * Subscribe to topic
150
+ */
151
+ async subscribeToTopic(topic) {
152
+ if (!messaging) {
153
+ throw new Error('Firebase messaging is not installed');
154
+ }
155
+ try {
156
+ await messaging().subscribeToTopic(topic);
157
+ console.log(`Subscribed to topic: ${topic}`);
158
+ }
159
+ catch (error) {
160
+ console.error('Error subscribing to topic:', error);
161
+ throw error;
162
+ }
163
+ }
164
+ /**
165
+ * Unsubscribe from topic
166
+ */
167
+ async unsubscribeFromTopic(topic) {
168
+ if (!messaging) {
169
+ throw new Error('Firebase messaging is not installed');
170
+ }
171
+ try {
172
+ await messaging().unsubscribeFromTopic(topic);
173
+ console.log(`Unsubscribed from topic: ${topic}`);
174
+ }
175
+ catch (error) {
176
+ console.error('Error unsubscribing from topic:', error);
177
+ throw error;
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,9 @@
1
+ import { BasePushNotification } from './BasePushNotification';
2
+ /**
3
+ * PushNotification class
4
+ * Extends BasePushNotification
5
+ */
6
+ export declare class PushNotification extends BasePushNotification {
7
+ }
8
+ export type { IPushNotificationAdapter } from './PushNotification.types';
9
+ export default PushNotification;
@@ -0,0 +1,11 @@
1
+ // PushNotification.ts
2
+ // Main push notification export
3
+ import { BasePushNotification } from './BasePushNotification';
4
+ /**
5
+ * PushNotification class
6
+ * Extends BasePushNotification
7
+ */
8
+ export class PushNotification extends BasePushNotification {
9
+ }
10
+ // Default export
11
+ export default PushNotification;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Push notification adapter interface
3
+ */
4
+ export interface IPushNotificationAdapter {
5
+ requestPermission(options?: {
6
+ forceShow?: boolean;
7
+ }): Promise<void>;
8
+ getToken(): Promise<string>;
9
+ onTokenRefresh(callback: (token: string) => void): void;
10
+ onMessage(callback: (message: any) => void): void;
11
+ onBackgroundMessage(callback: (message: any) => void): void;
12
+ }
@@ -0,0 +1,3 @@
1
+ // PushNotification.types.ts
2
+ // Type definitions for push notification module
3
+ export {};
@@ -0,0 +1,3 @@
1
+ export { PushNotification } from './PushNotification';
2
+ export type { IPushNotificationAdapter } from './PushNotification.types';
3
+ export { default } from './PushNotification';
@@ -0,0 +1,3 @@
1
+ // Push Notification module exports
2
+ export { PushNotification } from './PushNotification';
3
+ export { default } from './PushNotification';