@magicpixel/rn-mp-client-sdk 1.13.0 → 1.13.20
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 +163 -14
- package/lib/commonjs/common/app-types.js.map +1 -1
- package/lib/commonjs/common/constants.js +11 -2
- package/lib/commonjs/common/constants.js.map +1 -1
- package/lib/commonjs/common/data-store.js +13 -30
- package/lib/commonjs/common/data-store.js.map +1 -1
- package/lib/commonjs/common/deeplink-helper.js +174 -0
- package/lib/commonjs/common/deeplink-helper.js.map +1 -0
- package/lib/commonjs/common/device-info-helper.js +168 -0
- package/lib/commonjs/common/device-info-helper.js.map +1 -0
- package/lib/commonjs/common/event-bus.js +39 -0
- package/lib/commonjs/common/event-bus.js.map +1 -1
- package/lib/commonjs/common/network-service.js +119 -15
- package/lib/commonjs/common/network-service.js.map +1 -1
- package/lib/commonjs/common/reporter.js +28 -10
- package/lib/commonjs/common/reporter.js.map +1 -1
- package/lib/commonjs/common/storage-helper.js +227 -0
- package/lib/commonjs/common/storage-helper.js.map +1 -0
- package/lib/commonjs/common/utils.js +20 -2
- package/lib/commonjs/common/utils.js.map +1 -1
- package/lib/commonjs/eedl/eedl.js +198 -44
- package/lib/commonjs/eedl/eedl.js.map +1 -1
- package/lib/commonjs/index.js +290 -48
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/mp-client-sdk.js +17 -10
- package/lib/commonjs/models/mp-client-sdk.js.map +1 -1
- package/lib/commonjs/processors/data-element.processor.js +51 -7
- package/lib/commonjs/processors/data-element.processor.js.map +1 -1
- package/lib/commonjs/processors/visit-id.processor.js +78 -15
- package/lib/commonjs/processors/visit-id.processor.js.map +1 -1
- package/lib/module/common/app-types.js.map +1 -1
- package/lib/module/common/constants.js +11 -2
- package/lib/module/common/constants.js.map +1 -1
- package/lib/module/common/data-store.js +13 -30
- package/lib/module/common/data-store.js.map +1 -1
- package/lib/module/common/deeplink-helper.js +168 -0
- package/lib/module/common/deeplink-helper.js.map +1 -0
- package/lib/module/common/device-info-helper.js +161 -0
- package/lib/module/common/device-info-helper.js.map +1 -0
- package/lib/module/common/event-bus.js +39 -0
- package/lib/module/common/event-bus.js.map +1 -1
- package/lib/module/common/network-service.js +119 -15
- package/lib/module/common/network-service.js.map +1 -1
- package/lib/module/common/reporter.js +29 -10
- package/lib/module/common/reporter.js.map +1 -1
- package/lib/module/common/storage-helper.js +221 -0
- package/lib/module/common/storage-helper.js.map +1 -0
- package/lib/module/common/utils.js +20 -2
- package/lib/module/common/utils.js.map +1 -1
- package/lib/module/eedl/eedl.js +198 -44
- package/lib/module/eedl/eedl.js.map +1 -1
- package/lib/module/index.js +279 -47
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/mp-client-sdk.js +16 -9
- package/lib/module/models/mp-client-sdk.js.map +1 -1
- package/lib/module/processors/data-element.processor.js +51 -7
- package/lib/module/processors/data-element.processor.js.map +1 -1
- package/lib/module/processors/visit-id.processor.js +78 -15
- package/lib/module/processors/visit-id.processor.js.map +1 -1
- package/lib/typescript/{common → src/common}/app-types.d.ts +29 -9
- package/lib/typescript/{common → src/common}/constants.d.ts +0 -1
- package/lib/typescript/{common → src/common}/data-store.d.ts +3 -8
- package/lib/typescript/src/common/deeplink-helper.d.ts +60 -0
- package/lib/typescript/src/common/device-info-helper.d.ts +54 -0
- package/lib/typescript/src/common/event-bus.d.ts +21 -0
- package/lib/typescript/src/common/network-service.d.ts +32 -0
- package/lib/typescript/src/common/storage-helper.d.ts +47 -0
- package/lib/typescript/{common → src/common}/utils.d.ts +7 -0
- package/lib/typescript/{eedl → src/eedl}/eedl.d.ts +43 -1
- package/lib/typescript/{index.d.ts → src/index.d.ts} +39 -5
- package/lib/typescript/{models → src/models}/mp-client-sdk.d.ts +7 -0
- package/lib/typescript/src/processors/visit-id.processor.d.ts +23 -0
- package/package.json +26 -37
- package/src/common/app-types.ts +32 -10
- package/src/common/constants.ts +0 -6
- package/src/common/data-store.ts +8 -30
- package/src/common/deeplink-helper.ts +181 -0
- package/src/common/device-info-helper.ts +190 -0
- package/src/common/event-bus.ts +39 -0
- package/src/common/network-service.ts +154 -21
- package/src/common/reporter.ts +31 -10
- package/src/common/storage-helper.ts +266 -0
- package/src/common/utils.ts +20 -2
- package/src/eedl/eedl.ts +225 -51
- package/src/index.tsx +332 -67
- package/src/models/mp-client-sdk.ts +8 -0
- package/src/processors/data-element.processor.ts +85 -7
- package/src/processors/visit-id.processor.ts +92 -22
- package/lib/commonjs/processors/trans-function.processor.js +0 -73
- package/lib/commonjs/processors/trans-function.processor.js.map +0 -1
- package/lib/module/processors/trans-function.processor.js +0 -66
- package/lib/module/processors/trans-function.processor.js.map +0 -1
- package/lib/typescript/common/event-bus.d.ts +0 -6
- package/lib/typescript/common/network-service.d.ts +0 -8
- package/lib/typescript/processors/trans-function.processor.d.ts +0 -12
- package/lib/typescript/processors/visit-id.processor.d.ts +0 -9
- package/src/processors/trans-function.processor.ts +0 -85
- /package/lib/typescript/{common → src/common}/logger.d.ts +0 -0
- /package/lib/typescript/{common → src/common}/reporter.d.ts +0 -0
- /package/lib/typescript/{models → src/models}/geo-api-response.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/data-element.processor.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/geo-location.processor.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/qc.processor.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/tag.processor.d.ts +0 -0
package/src/common/reporter.ts
CHANGED
|
@@ -4,6 +4,9 @@ import { DataStore } from './data-store';
|
|
|
4
4
|
import { Utils } from './utils';
|
|
5
5
|
import { NetworkService } from './network-service';
|
|
6
6
|
|
|
7
|
+
// Maximum number of reports to keep in memory
|
|
8
|
+
const MAX_REPORTS = 500;
|
|
9
|
+
|
|
7
10
|
export class Reporter {
|
|
8
11
|
static reportMap: MapLike<Report> = {};
|
|
9
12
|
|
|
@@ -20,6 +23,20 @@ export class Reporter {
|
|
|
20
23
|
clientSdkVersion: string,
|
|
21
24
|
initialItems: ReportTagItem[] = []
|
|
22
25
|
): void {
|
|
26
|
+
// Evict oldest reports if at capacity
|
|
27
|
+
const reportKeys = Object.keys(this.reportMap);
|
|
28
|
+
if (reportKeys.length >= MAX_REPORTS) {
|
|
29
|
+
// Remove oldest report (first key in object)
|
|
30
|
+
const oldestKey = reportKeys[0];
|
|
31
|
+
if (oldestKey) {
|
|
32
|
+
delete this.reportMap[oldestKey];
|
|
33
|
+
Logger.logDbg(
|
|
34
|
+
`Report map at capacity (${MAX_REPORTS}), evicted oldest report:`,
|
|
35
|
+
oldestKey
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
23
40
|
this.reportMap[evtId] = {
|
|
24
41
|
envName,
|
|
25
42
|
envId,
|
|
@@ -66,6 +83,9 @@ export class Reporter {
|
|
|
66
83
|
Logger.logDbg('Posting Info: ', postUrl);
|
|
67
84
|
data.debugId = DataStore.getDebugId();
|
|
68
85
|
NetworkService.sendPostRequest(postUrl, data);
|
|
86
|
+
|
|
87
|
+
// Clean up report from memory after publishing
|
|
88
|
+
delete this.reportMap[evtId];
|
|
69
89
|
}
|
|
70
90
|
|
|
71
91
|
static reportError(methodMetaData: string, err: any): void {
|
|
@@ -90,17 +110,18 @@ export class Reporter {
|
|
|
90
110
|
eventName: string,
|
|
91
111
|
evtId: string
|
|
92
112
|
): Promise<void> {
|
|
93
|
-
data
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
// Clone data to avoid mutating the shared dataElements object
|
|
114
|
+
const payload: MapLike = { ...data };
|
|
115
|
+
payload.env = envName;
|
|
116
|
+
payload.envId = envId;
|
|
117
|
+
payload.evtName = eventName;
|
|
118
|
+
payload.dws = serverTagDownStream;
|
|
119
|
+
payload.debugId = DataStore.getDebugId();
|
|
120
|
+
payload.dm = 'n/a';
|
|
121
|
+
payload.v = DataStore.getCoreVersion();
|
|
101
122
|
NetworkService.sendPostRequest(
|
|
102
|
-
`${DataStore.getSSTUrl()}/${
|
|
103
|
-
|
|
123
|
+
`${DataStore.getSSTUrl()}/${payload.dws ?? 'n'}/${evtId}`,
|
|
124
|
+
payload
|
|
104
125
|
);
|
|
105
126
|
}
|
|
106
127
|
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage helper for data element storage duration
|
|
3
|
+
* Handles SESSION (in-memory) and VISITOR (AsyncStorage with 30-day expiry) storage
|
|
4
|
+
*/
|
|
5
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
6
|
+
import { DeStorageDuration } from '../models/mp-client-sdk';
|
|
7
|
+
import { Logger } from './logger';
|
|
8
|
+
|
|
9
|
+
// AsyncStorage key for visitor-scoped data elements
|
|
10
|
+
const VISITOR_STORE_KEY = '_mp_de_visitor_store';
|
|
11
|
+
|
|
12
|
+
// 30 days in milliseconds
|
|
13
|
+
const VISITOR_EXPIRY_MS = 30 * 24 * 60 * 60 * 1000;
|
|
14
|
+
|
|
15
|
+
// Interface for stored visitor values (includes timestamp for expiry check)
|
|
16
|
+
interface StoredVisitorValue {
|
|
17
|
+
value: any;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class StorageHelper {
|
|
22
|
+
// In-memory store for SESSION-scoped values (cleared on app restart)
|
|
23
|
+
private static sessionStore: Record<string, any> = {};
|
|
24
|
+
|
|
25
|
+
// In-memory cache of visitor store (loaded from AsyncStorage on init)
|
|
26
|
+
private static visitorStoreCache: Record<string, StoredVisitorValue> = {};
|
|
27
|
+
|
|
28
|
+
// Flag to track if initialized
|
|
29
|
+
private static isInitialized = false;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the storage helper
|
|
33
|
+
* Loads visitor store from AsyncStorage and cleans expired values
|
|
34
|
+
* Should be called once during SDK initialization
|
|
35
|
+
*/
|
|
36
|
+
static async initialize(): Promise<void> {
|
|
37
|
+
if (this.isInitialized) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// Load visitor store from AsyncStorage
|
|
43
|
+
const storedData = await AsyncStorage.getItem(VISITOR_STORE_KEY);
|
|
44
|
+
if (storedData) {
|
|
45
|
+
this.visitorStoreCache = JSON.parse(storedData);
|
|
46
|
+
Logger.logDbg(
|
|
47
|
+
'StorageHelper: Loaded visitor store with',
|
|
48
|
+
Object.keys(this.visitorStoreCache).length,
|
|
49
|
+
'items'
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Clean expired visitor data
|
|
54
|
+
await this.clearExpiredVisitorData();
|
|
55
|
+
|
|
56
|
+
this.isInitialized = true;
|
|
57
|
+
Logger.logDbg('StorageHelper: Initialized successfully');
|
|
58
|
+
} catch (err) {
|
|
59
|
+
Logger.logError('StorageHelper: Error initializing', err);
|
|
60
|
+
// Reset to empty state on error
|
|
61
|
+
this.visitorStoreCache = {};
|
|
62
|
+
this.isInitialized = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Clear visitor-scoped values older than 30 days
|
|
68
|
+
*/
|
|
69
|
+
static async clearExpiredVisitorData(): Promise<void> {
|
|
70
|
+
try {
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
const keysToRemove: string[] = [];
|
|
73
|
+
|
|
74
|
+
for (const key of Object.keys(this.visitorStoreCache)) {
|
|
75
|
+
const entry = this.visitorStoreCache[key];
|
|
76
|
+
if (entry && now - entry.timestamp > VISITOR_EXPIRY_MS) {
|
|
77
|
+
keysToRemove.push(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (keysToRemove.length > 0) {
|
|
82
|
+
for (const key of keysToRemove) {
|
|
83
|
+
delete this.visitorStoreCache[key];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Persist the cleaned store
|
|
87
|
+
await this.persistVisitorStore();
|
|
88
|
+
|
|
89
|
+
Logger.logDbg(
|
|
90
|
+
'StorageHelper: Cleared',
|
|
91
|
+
keysToRemove.length,
|
|
92
|
+
'expired visitor values'
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
Logger.logError('StorageHelper: Error clearing expired data', err);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Persist the visitor store cache to AsyncStorage
|
|
102
|
+
*/
|
|
103
|
+
private static async persistVisitorStore(): Promise<void> {
|
|
104
|
+
try {
|
|
105
|
+
await AsyncStorage.setItem(
|
|
106
|
+
VISITOR_STORE_KEY,
|
|
107
|
+
JSON.stringify(this.visitorStoreCache)
|
|
108
|
+
);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
Logger.logError('StorageHelper: Error persisting visitor store', err);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if a value is defined (not null, undefined, or empty string)
|
|
116
|
+
*/
|
|
117
|
+
private static isDefined(value: any): boolean {
|
|
118
|
+
return value !== null && value !== undefined && value !== '';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Store a data element value based on storage duration
|
|
123
|
+
* @param deKey - The data element key
|
|
124
|
+
* @param value - The value to store
|
|
125
|
+
* @param storageDuration - The storage duration type
|
|
126
|
+
*/
|
|
127
|
+
static deStorageDurationSet(
|
|
128
|
+
deKey: string,
|
|
129
|
+
value: any,
|
|
130
|
+
storageDuration: DeStorageDuration
|
|
131
|
+
): void {
|
|
132
|
+
try {
|
|
133
|
+
if (!this.isDefined(deKey) || !this.isDefined(value)) {
|
|
134
|
+
// Key and value are required
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!storageDuration) {
|
|
139
|
+
storageDuration = DeStorageDuration.EVENT;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
switch (storageDuration) {
|
|
143
|
+
case DeStorageDuration.SESSION:
|
|
144
|
+
// Store in memory (cleared on app restart)
|
|
145
|
+
this.sessionStore[deKey] = value;
|
|
146
|
+
Logger.logDbg(
|
|
147
|
+
'StorageHelper: Stored SESSION value for',
|
|
148
|
+
deKey
|
|
149
|
+
);
|
|
150
|
+
break;
|
|
151
|
+
|
|
152
|
+
case DeStorageDuration.VISITOR:
|
|
153
|
+
// Store in AsyncStorage cache with timestamp
|
|
154
|
+
this.visitorStoreCache[deKey] = {
|
|
155
|
+
value: value,
|
|
156
|
+
timestamp: Date.now(),
|
|
157
|
+
};
|
|
158
|
+
// Persist to AsyncStorage in background
|
|
159
|
+
this.persistVisitorStore().catch((err) => {
|
|
160
|
+
Logger.logError(
|
|
161
|
+
'StorageHelper: Error persisting visitor value',
|
|
162
|
+
err
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
Logger.logDbg(
|
|
166
|
+
'StorageHelper: Stored VISITOR value for',
|
|
167
|
+
deKey
|
|
168
|
+
);
|
|
169
|
+
break;
|
|
170
|
+
|
|
171
|
+
case DeStorageDuration.EVENT:
|
|
172
|
+
case DeStorageDuration.NONE:
|
|
173
|
+
default:
|
|
174
|
+
// No persistence needed for EVENT or NONE
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
} catch (err) {
|
|
178
|
+
Logger.logError('StorageHelper: Error in deStorageDurationSet', err);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Retrieve a data element value based on storage duration
|
|
184
|
+
* @param deKey - The data element key
|
|
185
|
+
* @param defaultValue - Default value if not found
|
|
186
|
+
* @param storageDuration - The storage duration type
|
|
187
|
+
* @returns The stored value or default value
|
|
188
|
+
*/
|
|
189
|
+
static deStorageDurationGet(
|
|
190
|
+
deKey: string,
|
|
191
|
+
defaultValue: any,
|
|
192
|
+
storageDuration: DeStorageDuration
|
|
193
|
+
): any {
|
|
194
|
+
try {
|
|
195
|
+
if (!this.isDefined(deKey)) {
|
|
196
|
+
return defaultValue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!storageDuration) {
|
|
200
|
+
storageDuration = DeStorageDuration.EVENT;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
switch (storageDuration) {
|
|
204
|
+
case DeStorageDuration.SESSION: {
|
|
205
|
+
// Get from in-memory session store
|
|
206
|
+
const sessionValue = this.sessionStore[deKey];
|
|
207
|
+
if (this.isDefined(sessionValue)) {
|
|
208
|
+
return sessionValue;
|
|
209
|
+
}
|
|
210
|
+
return defaultValue;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
case DeStorageDuration.VISITOR: {
|
|
214
|
+
// Get from visitor store cache
|
|
215
|
+
const visitorEntry = this.visitorStoreCache[deKey];
|
|
216
|
+
if (visitorEntry && this.isDefined(visitorEntry.value)) {
|
|
217
|
+
// Check if not expired
|
|
218
|
+
if (Date.now() - visitorEntry.timestamp <= VISITOR_EXPIRY_MS) {
|
|
219
|
+
return visitorEntry.value;
|
|
220
|
+
} else {
|
|
221
|
+
// Value is expired, remove it
|
|
222
|
+
delete this.visitorStoreCache[deKey];
|
|
223
|
+
this.persistVisitorStore().catch((err) => {
|
|
224
|
+
Logger.logError(
|
|
225
|
+
'StorageHelper: Error removing expired value',
|
|
226
|
+
err
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return defaultValue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
case DeStorageDuration.EVENT:
|
|
235
|
+
case DeStorageDuration.NONE:
|
|
236
|
+
default:
|
|
237
|
+
// No retrieval for EVENT or NONE
|
|
238
|
+
return defaultValue;
|
|
239
|
+
}
|
|
240
|
+
} catch (err) {
|
|
241
|
+
Logger.logError('StorageHelper: Error in deStorageDurationGet', err);
|
|
242
|
+
return defaultValue;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Clear all session-scoped values (called on new session if needed)
|
|
248
|
+
*/
|
|
249
|
+
static clearSessionStore(): void {
|
|
250
|
+
this.sessionStore = {};
|
|
251
|
+
Logger.logDbg('StorageHelper: Cleared session store');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Clear all visitor-scoped values
|
|
256
|
+
*/
|
|
257
|
+
static async clearVisitorStore(): Promise<void> {
|
|
258
|
+
try {
|
|
259
|
+
this.visitorStoreCache = {};
|
|
260
|
+
await AsyncStorage.removeItem(VISITOR_STORE_KEY);
|
|
261
|
+
Logger.logDbg('StorageHelper: Cleared visitor store');
|
|
262
|
+
} catch (err) {
|
|
263
|
+
Logger.logError('StorageHelper: Error clearing visitor store', err);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
package/src/common/utils.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { EventBus } from './event-bus';
|
|
|
11
11
|
import { Dimensions, ScaledSize } from 'react-native';
|
|
12
12
|
import { URL } from 'react-native-url-polyfill';
|
|
13
13
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
14
|
+
import { ulid } from 'ulid';
|
|
14
15
|
|
|
15
16
|
export class Utils {
|
|
16
17
|
static triggerEvent(eventName: string, payload: any): void {
|
|
@@ -136,7 +137,7 @@ export class Utils {
|
|
|
136
137
|
if (tfItem.eTyp === 'URL_ENC') {
|
|
137
138
|
paramValue = encodeURIComponent(paramValue);
|
|
138
139
|
} else if (tfItem.eTyp === 'BASE64') {
|
|
139
|
-
paramValue =
|
|
140
|
+
paramValue = this.toBase64(paramValue);
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
}
|
|
@@ -204,8 +205,25 @@ export class Utils {
|
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Encode string to Base64 - React Native compatible
|
|
210
|
+
* Works with both ASCII and UTF-8 strings
|
|
211
|
+
* @param str String to encode
|
|
212
|
+
* @returns Base64 encoded string
|
|
213
|
+
*/
|
|
214
|
+
static toBase64(str: string): string {
|
|
215
|
+
try {
|
|
216
|
+
// Handle UTF-8 strings properly using encodeURIComponent + unescape trick
|
|
217
|
+
// This works in all JavaScript engines including React Native's Hermes/JSC
|
|
218
|
+
return btoa(unescape(encodeURIComponent(str)));
|
|
219
|
+
} catch (err) {
|
|
220
|
+
Logger.logError('Error encoding to Base64:', err);
|
|
221
|
+
return str; // Return original value if encoding fails
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
207
225
|
static getUniqueID(): string {
|
|
208
|
-
return
|
|
226
|
+
return ulid();
|
|
209
227
|
}
|
|
210
228
|
|
|
211
229
|
/**
|