riuve-rn 1.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.
- package/LICENSE +21 -0
- package/README.md +848 -0
- package/dist/Riuve.d.ts +91 -0
- package/dist/Riuve.d.ts.map +1 -0
- package/dist/Riuve.js +402 -0
- package/dist/Rive.d.ts +91 -0
- package/dist/Rive.d.ts.map +1 -0
- package/dist/Rive.js +402 -0
- package/dist/adapters/deviceInfo/ExpoDeviceInfo.d.ts +13 -0
- package/dist/adapters/deviceInfo/ExpoDeviceInfo.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/ExpoDeviceInfo.js +91 -0
- package/dist/adapters/deviceInfo/FallbackDeviceInfo.d.ts +13 -0
- package/dist/adapters/deviceInfo/FallbackDeviceInfo.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/FallbackDeviceInfo.js +36 -0
- package/dist/adapters/deviceInfo/NativeDeviceInfo.d.ts +17 -0
- package/dist/adapters/deviceInfo/NativeDeviceInfo.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/NativeDeviceInfo.js +83 -0
- package/dist/adapters/deviceInfo/index.d.ts +14 -0
- package/dist/adapters/deviceInfo/index.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/index.js +38 -0
- package/dist/adapters/deviceInfo/types.d.ts +25 -0
- package/dist/adapters/deviceInfo/types.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/types.js +7 -0
- package/dist/adapters/network/ExpoNetworkManager.d.ts +20 -0
- package/dist/adapters/network/ExpoNetworkManager.d.ts.map +1 -0
- package/dist/adapters/network/ExpoNetworkManager.js +114 -0
- package/dist/adapters/network/FallbackNetworkManager.d.ts +15 -0
- package/dist/adapters/network/FallbackNetworkManager.d.ts.map +1 -0
- package/dist/adapters/network/FallbackNetworkManager.js +27 -0
- package/dist/adapters/network/NativeNetworkManager.d.ts +20 -0
- package/dist/adapters/network/NativeNetworkManager.d.ts.map +1 -0
- package/dist/adapters/network/NativeNetworkManager.js +68 -0
- package/dist/adapters/network/index.d.ts +14 -0
- package/dist/adapters/network/index.d.ts.map +1 -0
- package/dist/adapters/network/index.js +38 -0
- package/dist/adapters/network/types.d.ts +28 -0
- package/dist/adapters/network/types.d.ts.map +1 -0
- package/dist/adapters/network/types.js +7 -0
- package/dist/adapters/utils/moduleDetector.d.ts +17 -0
- package/dist/adapters/utils/moduleDetector.d.ts.map +1 -0
- package/dist/adapters/utils/moduleDetector.js +32 -0
- package/dist/constants.d.ts +41 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +43 -0
- package/dist/core/ApiClient.d.ts +49 -0
- package/dist/core/ApiClient.d.ts.map +1 -0
- package/dist/core/ApiClient.js +184 -0
- package/dist/core/DeviceInfo.d.ts +27 -0
- package/dist/core/DeviceInfo.d.ts.map +1 -0
- package/dist/core/DeviceInfo.js +69 -0
- package/dist/core/EventQueue.d.ts +71 -0
- package/dist/core/EventQueue.d.ts.map +1 -0
- package/dist/core/EventQueue.js +216 -0
- package/dist/core/Storage.d.ts +29 -0
- package/dist/core/Storage.d.ts.map +1 -0
- package/dist/core/Storage.js +88 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/managers/BatchManager.d.ts +50 -0
- package/dist/managers/BatchManager.d.ts.map +1 -0
- package/dist/managers/BatchManager.js +277 -0
- package/dist/managers/IdentityManager.d.ts +47 -0
- package/dist/managers/IdentityManager.d.ts.map +1 -0
- package/dist/managers/IdentityManager.js +135 -0
- package/dist/managers/NetworkManager.d.ts +32 -0
- package/dist/managers/NetworkManager.d.ts.map +1 -0
- package/dist/managers/NetworkManager.js +67 -0
- package/dist/types/api.d.ts +65 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +15 -0
- package/dist/types/config.d.ts +32 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/events.d.ts +63 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +5 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/storage.d.ts +26 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +5 -0
- package/dist/utils/fetchWithTimeout.d.ts +6 -0
- package/dist/utils/fetchWithTimeout.d.ts.map +1 -0
- package/dist/utils/fetchWithTimeout.js +28 -0
- package/dist/utils/logger.d.ts +21 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +39 -0
- package/dist/utils/retry.d.ts +29 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +78 -0
- package/dist/utils/uuid.d.ts +12 -0
- package/dist/utils/uuid.d.ts.map +1 -0
- package/dist/utils/uuid.js +27 -0
- package/dist/utils/validators.d.ts +32 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +68 -0
- package/package.json +65 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Storage Layer - AsyncStorage Wrapper
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.storage = void 0;
|
|
10
|
+
const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
|
|
11
|
+
const constants_1 = require("../constants");
|
|
12
|
+
const logger_1 = require("../utils/logger");
|
|
13
|
+
class Storage {
|
|
14
|
+
/**
|
|
15
|
+
* Sets a value in storage
|
|
16
|
+
*/
|
|
17
|
+
async set(key, value) {
|
|
18
|
+
try {
|
|
19
|
+
const storageKey = constants_1.STORAGE_KEYS[key];
|
|
20
|
+
const serialized = JSON.stringify(value);
|
|
21
|
+
await async_storage_1.default.setItem(storageKey, serialized);
|
|
22
|
+
// Removed verbose debug logging for production
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
logger_1.logger.error(`Storage set failed for ${key}:`, error);
|
|
26
|
+
throw new Error(`${constants_1.ERROR_MESSAGES.STORAGE_ERROR}: ${error.message}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Gets a value from storage
|
|
31
|
+
*/
|
|
32
|
+
async get(key) {
|
|
33
|
+
try {
|
|
34
|
+
const storageKey = constants_1.STORAGE_KEYS[key];
|
|
35
|
+
const serialized = await async_storage_1.default.getItem(storageKey);
|
|
36
|
+
if (serialized === null) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const value = JSON.parse(serialized);
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger_1.logger.error(`Storage get failed for ${key}:`, error);
|
|
44
|
+
throw new Error(`${constants_1.ERROR_MESSAGES.STORAGE_ERROR}: ${error.message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Removes a value from storage
|
|
49
|
+
*/
|
|
50
|
+
async remove(key) {
|
|
51
|
+
try {
|
|
52
|
+
const storageKey = constants_1.STORAGE_KEYS[key];
|
|
53
|
+
await async_storage_1.default.removeItem(storageKey);
|
|
54
|
+
// Removed verbose debug logging for production
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
logger_1.logger.error(`Storage remove failed for ${key}:`, error);
|
|
58
|
+
throw new Error(`${constants_1.ERROR_MESSAGES.STORAGE_ERROR}: ${error.message}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Clears all SDK-related storage
|
|
63
|
+
*/
|
|
64
|
+
async clear() {
|
|
65
|
+
try {
|
|
66
|
+
const keys = Object.values(constants_1.STORAGE_KEYS);
|
|
67
|
+
await async_storage_1.default.multiRemove(keys);
|
|
68
|
+
// Removed verbose info logging for production
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
logger_1.logger.error('Storage clear failed:', error);
|
|
72
|
+
throw new Error(`${constants_1.ERROR_MESSAGES.STORAGE_ERROR}: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a key exists in storage
|
|
77
|
+
*/
|
|
78
|
+
async has(key) {
|
|
79
|
+
try {
|
|
80
|
+
const value = await this.get(key);
|
|
81
|
+
return value !== null;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.storage = new Storage();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Riuve React Native SDK
|
|
3
|
+
* Main export file
|
|
4
|
+
*/
|
|
5
|
+
import Riuve from './Riuve';
|
|
6
|
+
export default Riuve;
|
|
7
|
+
export type { RiuveConfig, RiuveConfigInput, Event, DeviceInfo, EventBatch, FailedBatch, InitializeRequest, InitializeResponse, IdentifyRequest, IdentifyResponse, TrackRequest, TrackResponse, SetFcmTokenRequest, SetFcmTokenResponse, ApiError, ErrorType, } from './types';
|
|
8
|
+
export { DEFAULT_CONFIG, ERROR_MESSAGES } from './constants';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,SAAS,CAAC;AAG5B,eAAe,KAAK,CAAC;AAGrB,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,KAAK,EACL,UAAU,EACV,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,QAAQ,EACR,SAAS,GACV,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Riuve React Native SDK
|
|
4
|
+
* Main export file
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ERROR_MESSAGES = exports.DEFAULT_CONFIG = void 0;
|
|
11
|
+
const Riuve_1 = __importDefault(require("./Riuve"));
|
|
12
|
+
// Export the SDK instance as default
|
|
13
|
+
exports.default = Riuve_1.default;
|
|
14
|
+
// Export constants for advanced users
|
|
15
|
+
var constants_1 = require("./constants");
|
|
16
|
+
Object.defineProperty(exports, "DEFAULT_CONFIG", { enumerable: true, get: function () { return constants_1.DEFAULT_CONFIG; } });
|
|
17
|
+
Object.defineProperty(exports, "ERROR_MESSAGES", { enumerable: true, get: function () { return constants_1.ERROR_MESSAGES; } });
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch Manager - Orchestrates batch sending and offline queue
|
|
3
|
+
*/
|
|
4
|
+
import { EventQueue } from '../core/EventQueue';
|
|
5
|
+
import { ApiClient } from '../core/ApiClient';
|
|
6
|
+
import { NetworkManager } from './NetworkManager';
|
|
7
|
+
import { IdentityManager } from './IdentityManager';
|
|
8
|
+
import type { Event } from '../types';
|
|
9
|
+
export declare class BatchManager {
|
|
10
|
+
private eventQueue;
|
|
11
|
+
private apiClient;
|
|
12
|
+
private networkManager;
|
|
13
|
+
private identityManager;
|
|
14
|
+
private isFlushing;
|
|
15
|
+
private eventRetentionDays;
|
|
16
|
+
constructor(eventQueue: EventQueue, apiClient: ApiClient, networkManager: NetworkManager, identityManager: IdentityManager, eventRetentionDays: number);
|
|
17
|
+
/**
|
|
18
|
+
* Sends a batch of events to the API
|
|
19
|
+
*/
|
|
20
|
+
sendBatch(events: Event[]): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Saves a failed batch for later retry
|
|
23
|
+
*/
|
|
24
|
+
private saveFailedBatch;
|
|
25
|
+
/**
|
|
26
|
+
* Flushes the offline queue (retries failed batches)
|
|
27
|
+
*/
|
|
28
|
+
flushOfflineQueue(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Validates UUID format (8-4-4-4-12 hex characters)
|
|
31
|
+
*/
|
|
32
|
+
private isValidUUID;
|
|
33
|
+
/**
|
|
34
|
+
* Fixes invalid event IDs in a batch
|
|
35
|
+
*/
|
|
36
|
+
private fixEventIds;
|
|
37
|
+
/**
|
|
38
|
+
* Processes and retries failed batches
|
|
39
|
+
*/
|
|
40
|
+
private processFailedBatches;
|
|
41
|
+
/**
|
|
42
|
+
* Gets the count of failed batches
|
|
43
|
+
*/
|
|
44
|
+
getFailedBatchCount(): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Clears all failed batches
|
|
47
|
+
*/
|
|
48
|
+
clearFailedBatches(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=BatchManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchManager.d.ts","sourceRoot":"","sources":["../../src/managers/BatchManager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,UAAU,CAAC;AAGnD,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,kBAAkB,CAAS;gBAGjC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,cAAc,EAC9B,eAAe,EAAE,eAAe,EAChC,kBAAkB,EAAE,MAAM;IAsB5B;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsF/C;;OAEG;YACW,eAAe;IAoC7B;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAYxC;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;OAEG;IACH,OAAO,CAAC,WAAW;IAqBnB;;OAEG;YACW,oBAAoB;IAuElC;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAU5C;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ1C"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Batch Manager - Orchestrates batch sending and offline queue
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BatchManager = void 0;
|
|
7
|
+
const uuid_1 = require("../utils/uuid");
|
|
8
|
+
const Storage_1 = require("../core/Storage");
|
|
9
|
+
const logger_1 = require("../utils/logger");
|
|
10
|
+
class BatchManager {
|
|
11
|
+
constructor(eventQueue, apiClient, networkManager, identityManager, eventRetentionDays) {
|
|
12
|
+
this.isFlushing = false;
|
|
13
|
+
this.eventQueue = eventQueue;
|
|
14
|
+
this.apiClient = apiClient;
|
|
15
|
+
this.networkManager = networkManager;
|
|
16
|
+
this.identityManager = identityManager;
|
|
17
|
+
this.eventRetentionDays = eventRetentionDays;
|
|
18
|
+
// Set flush callback on event queue
|
|
19
|
+
this.eventQueue.setFlushCallback((events) => this.sendBatch(events));
|
|
20
|
+
// Listen for network status changes
|
|
21
|
+
this.networkManager.onStatusChange((isOnline) => {
|
|
22
|
+
if (isOnline) {
|
|
23
|
+
logger_1.logger.info('Network came online, processing offline queue...');
|
|
24
|
+
this.flushOfflineQueue().catch((error) => {
|
|
25
|
+
logger_1.logger.error('Failed to flush offline queue:', error);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sends a batch of events to the API
|
|
32
|
+
*/
|
|
33
|
+
async sendBatch(events) {
|
|
34
|
+
if (events.length === 0) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Check if online
|
|
38
|
+
if (!this.networkManager.isConnected()) {
|
|
39
|
+
logger_1.logger.warn('Offline, events will be stored for later');
|
|
40
|
+
logger_1.logger.warn(` Events not sent: ${events.length} events`);
|
|
41
|
+
events.forEach((event, index) => {
|
|
42
|
+
logger_1.logger.warn(` ${index + 1}. ${event.name} (id: ${event.id}, timestamp: ${new Date(event.timestamp).toISOString()})`);
|
|
43
|
+
});
|
|
44
|
+
await this.saveFailedBatch(events, 'Network offline');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Prevent concurrent flushes
|
|
48
|
+
if (this.isFlushing) {
|
|
49
|
+
logger_1.logger.debug('Already flushing, skipping...');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.isFlushing = true;
|
|
53
|
+
const startTime = Date.now();
|
|
54
|
+
try {
|
|
55
|
+
logger_1.logger.info(`Sending batch: ${events.length} events`);
|
|
56
|
+
if (events.length <= 5) {
|
|
57
|
+
logger_1.logger.info(` Events:`);
|
|
58
|
+
events.forEach((event, index) => {
|
|
59
|
+
logger_1.logger.info(` ${index + 1}. ${event.name} (id: ${event.id.substring(0, 8)}...)`);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
logger_1.logger.info(` Events: ${events.map(e => e.name).join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
const anonymousId = this.identityManager.getAnonymousId();
|
|
66
|
+
const externalUserId = this.identityManager.getExternalUserId();
|
|
67
|
+
if (!anonymousId) {
|
|
68
|
+
throw new Error('Anonymous ID not set');
|
|
69
|
+
}
|
|
70
|
+
logger_1.logger.info(` Anonymous ID: ${anonymousId}`);
|
|
71
|
+
if (externalUserId) {
|
|
72
|
+
logger_1.logger.info(` External User ID: ${externalUserId}`);
|
|
73
|
+
}
|
|
74
|
+
// Send to API
|
|
75
|
+
const response = await this.apiClient.track({
|
|
76
|
+
anonymous_id: anonymousId,
|
|
77
|
+
external_user_id: externalUserId || undefined,
|
|
78
|
+
events,
|
|
79
|
+
});
|
|
80
|
+
const responseTime = Date.now() - startTime;
|
|
81
|
+
logger_1.logger.info(`Batch sent successfully`);
|
|
82
|
+
logger_1.logger.info(` Processed: ${response.processed}/${events.length} events`);
|
|
83
|
+
logger_1.logger.info(` Response time: ${responseTime}ms`);
|
|
84
|
+
if (response.processed < events.length) {
|
|
85
|
+
logger_1.logger.warn(` Warning: Only ${response.processed} out of ${events.length} events were processed`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
const responseTime = Date.now() - startTime;
|
|
90
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
91
|
+
logger_1.logger.error(`Failed to send batch (${responseTime}ms): ${errorMessage}`);
|
|
92
|
+
if (events.length <= 5) {
|
|
93
|
+
logger_1.logger.error(` Events not sent:`);
|
|
94
|
+
events.forEach((event, index) => {
|
|
95
|
+
logger_1.logger.error(` ${index + 1}. ${event.name} (id: ${event.id.substring(0, 8)}...)`);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
logger_1.logger.error(` Events not sent: ${events.length} events (${events.map(e => e.name).join(', ')})`);
|
|
100
|
+
}
|
|
101
|
+
// Save as failed batch for retry
|
|
102
|
+
await this.saveFailedBatch(events, errorMessage);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
this.isFlushing = false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Saves a failed batch for later retry
|
|
111
|
+
*/
|
|
112
|
+
async saveFailedBatch(events, errorMessage) {
|
|
113
|
+
try {
|
|
114
|
+
const failedBatch = {
|
|
115
|
+
id: (0, uuid_1.generateUUID)(),
|
|
116
|
+
events,
|
|
117
|
+
failedAt: Date.now(),
|
|
118
|
+
retryCount: 0,
|
|
119
|
+
lastError: errorMessage,
|
|
120
|
+
};
|
|
121
|
+
// Get existing failed batches
|
|
122
|
+
const existingBatches = (await Storage_1.storage.get('FAILED_BATCHES')) || [];
|
|
123
|
+
// Add new failed batch
|
|
124
|
+
existingBatches.push(failedBatch);
|
|
125
|
+
// Save back to storage
|
|
126
|
+
await Storage_1.storage.set('FAILED_BATCHES', existingBatches);
|
|
127
|
+
logger_1.logger.warn(`Saved failed batch: ${failedBatch.id.substring(0, 8)}...`);
|
|
128
|
+
logger_1.logger.warn(` Events: ${events.length} events`);
|
|
129
|
+
logger_1.logger.warn(` Error: ${errorMessage}`);
|
|
130
|
+
if (events.length <= 5) {
|
|
131
|
+
logger_1.logger.warn(` Events in failed batch:`);
|
|
132
|
+
events.forEach((event, index) => {
|
|
133
|
+
logger_1.logger.warn(` ${index + 1}. ${event.name} (id: ${event.id.substring(0, 8)}...)`);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
logger_1.logger.warn(` Events: ${events.map(e => e.name).join(', ')}`);
|
|
138
|
+
}
|
|
139
|
+
logger_1.logger.warn(` Total failed batches: ${existingBatches.length}`);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
logger_1.logger.error('Failed to save failed batch:', error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Flushes the offline queue (retries failed batches)
|
|
147
|
+
*/
|
|
148
|
+
async flushOfflineQueue() {
|
|
149
|
+
// First, process any failed batches
|
|
150
|
+
await this.processFailedBatches();
|
|
151
|
+
// Then, flush any events in the current queue
|
|
152
|
+
try {
|
|
153
|
+
await this.eventQueue.flush();
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
logger_1.logger.error('Failed to flush event queue:', error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Validates UUID format (8-4-4-4-12 hex characters)
|
|
161
|
+
*/
|
|
162
|
+
isValidUUID(uuid) {
|
|
163
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
164
|
+
return uuidRegex.test(uuid);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Fixes invalid event IDs in a batch
|
|
168
|
+
*/
|
|
169
|
+
fixEventIds(events) {
|
|
170
|
+
let fixedCount = 0;
|
|
171
|
+
const fixedEvents = events.map((event) => {
|
|
172
|
+
if (!this.isValidUUID(event.id)) {
|
|
173
|
+
logger_1.logger.warn(`Invalid event ID detected: ${event.id}. Generating new ID.`);
|
|
174
|
+
fixedCount++;
|
|
175
|
+
return {
|
|
176
|
+
...event,
|
|
177
|
+
id: (0, uuid_1.generateUUID)(),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return event;
|
|
181
|
+
});
|
|
182
|
+
if (fixedCount > 0) {
|
|
183
|
+
logger_1.logger.info(`Fixed ${fixedCount} invalid event IDs in batch`);
|
|
184
|
+
}
|
|
185
|
+
return fixedEvents;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Processes and retries failed batches
|
|
189
|
+
*/
|
|
190
|
+
async processFailedBatches() {
|
|
191
|
+
try {
|
|
192
|
+
const failedBatches = (await Storage_1.storage.get('FAILED_BATCHES')) || [];
|
|
193
|
+
if (failedBatches.length === 0) {
|
|
194
|
+
logger_1.logger.debug('No failed batches to process');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
logger_1.logger.info(`Processing ${failedBatches.length} failed batches...`);
|
|
198
|
+
const successfulBatches = [];
|
|
199
|
+
const updatedBatches = [];
|
|
200
|
+
let discardedCount = 0;
|
|
201
|
+
for (const batch of failedBatches) {
|
|
202
|
+
// Check if batch is too old (exceeded retention period)
|
|
203
|
+
const age = Date.now() - batch.failedAt;
|
|
204
|
+
const maxAge = this.eventRetentionDays * 24 * 60 * 60 * 1000;
|
|
205
|
+
if (age > maxAge) {
|
|
206
|
+
const ageDays = Math.floor(age / (24 * 60 * 60 * 1000));
|
|
207
|
+
logger_1.logger.warn(`Batch ${batch.id} is too old (${ageDays} days), discarding`);
|
|
208
|
+
logger_1.logger.warn(` Events discarded: ${batch.events.length} events`);
|
|
209
|
+
batch.events.forEach((event, index) => {
|
|
210
|
+
logger_1.logger.warn(` ${index + 1}. ${event.name} (id: ${event.id})`);
|
|
211
|
+
});
|
|
212
|
+
discardedCount++;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
logger_1.logger.info(`Retrying failed batch: ${batch.id}`);
|
|
216
|
+
logger_1.logger.info(` Previous error: ${batch.lastError}`);
|
|
217
|
+
logger_1.logger.info(` Retry attempt: ${batch.retryCount + 1}`);
|
|
218
|
+
logger_1.logger.info(` Events: ${batch.events.length} events`);
|
|
219
|
+
// Fix invalid event IDs before retrying
|
|
220
|
+
const fixedEvents = this.fixEventIds(batch.events);
|
|
221
|
+
// Try to send the batch
|
|
222
|
+
try {
|
|
223
|
+
await this.sendBatch(fixedEvents);
|
|
224
|
+
successfulBatches.push(batch.id);
|
|
225
|
+
logger_1.logger.info(`Successfully retried batch ${batch.id}`);
|
|
226
|
+
logger_1.logger.info(` Events sent: ${batch.events.length} events`);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
// Update retry count and error, but use fixed events
|
|
230
|
+
batch.retryCount += 1;
|
|
231
|
+
batch.lastError = error instanceof Error ? error.message : 'Unknown error';
|
|
232
|
+
batch.events = fixedEvents; // Update with fixed events
|
|
233
|
+
updatedBatches.push(batch);
|
|
234
|
+
logger_1.logger.warn(`Failed to retry batch ${batch.id} (attempt ${batch.retryCount}):`, error);
|
|
235
|
+
logger_1.logger.warn(` Error: ${batch.lastError}`);
|
|
236
|
+
logger_1.logger.warn(` Events still failed: ${batch.events.length} events`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Update storage with remaining failed batches
|
|
240
|
+
await Storage_1.storage.set('FAILED_BATCHES', updatedBatches);
|
|
241
|
+
logger_1.logger.info(`Processed failed batches:`);
|
|
242
|
+
logger_1.logger.info(` Succeeded: ${successfulBatches.length}`);
|
|
243
|
+
logger_1.logger.info(` Still failed: ${updatedBatches.length}`);
|
|
244
|
+
logger_1.logger.info(` Discarded (too old): ${discardedCount}`);
|
|
245
|
+
logger_1.logger.info(` Total processed: ${failedBatches.length}`);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
logger_1.logger.error('Failed to process failed batches:', error);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Gets the count of failed batches
|
|
253
|
+
*/
|
|
254
|
+
async getFailedBatchCount() {
|
|
255
|
+
try {
|
|
256
|
+
const failedBatches = (await Storage_1.storage.get('FAILED_BATCHES')) || [];
|
|
257
|
+
return failedBatches.length;
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
logger_1.logger.error('Failed to get failed batch count:', error);
|
|
261
|
+
return 0;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Clears all failed batches
|
|
266
|
+
*/
|
|
267
|
+
async clearFailedBatches() {
|
|
268
|
+
try {
|
|
269
|
+
await Storage_1.storage.set('FAILED_BATCHES', []);
|
|
270
|
+
logger_1.logger.info('Cleared all failed batches');
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
logger_1.logger.error('Failed to clear failed batches:', error);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
exports.BatchManager = BatchManager;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Manager - Manages user identity
|
|
3
|
+
*/
|
|
4
|
+
export declare class IdentityManager {
|
|
5
|
+
private anonymousId;
|
|
6
|
+
private externalUserId;
|
|
7
|
+
private userProperties;
|
|
8
|
+
/**
|
|
9
|
+
* Validates UUID format (8-4-4-4-12 hex characters)
|
|
10
|
+
*/
|
|
11
|
+
private isValidUUID;
|
|
12
|
+
/**
|
|
13
|
+
* Initializes the identity manager
|
|
14
|
+
* Generates or loads anonymous ID from storage
|
|
15
|
+
*/
|
|
16
|
+
initialize(): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Identifies a user with an external user ID and optional properties
|
|
19
|
+
*/
|
|
20
|
+
identify(externalUserId: string, properties?: Record<string, any>): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Resets the user identity
|
|
23
|
+
* Generates a new anonymous ID and clears external user ID and properties
|
|
24
|
+
*/
|
|
25
|
+
reset(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Updates user properties (merges with existing)
|
|
28
|
+
*/
|
|
29
|
+
updateUserProperties(properties: Record<string, any>): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Gets the anonymous ID
|
|
32
|
+
*/
|
|
33
|
+
getAnonymousId(): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Gets the external user ID
|
|
36
|
+
*/
|
|
37
|
+
getExternalUserId(): string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Gets user properties
|
|
40
|
+
*/
|
|
41
|
+
getUserProperties(): Record<string, any>;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if the user is identified
|
|
44
|
+
*/
|
|
45
|
+
isIdentified(): boolean;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=IdentityManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IdentityManager.d.ts","sourceRoot":"","sources":["../../src/managers/IdentityManager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,qBAAa,eAAe;IAC1B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,cAAc,CAA2B;IAEjD;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAkCnC;;OAEG;IACG,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC;IAyBhB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B;;OAEG;IACG,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAY1E;;OAEG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,iBAAiB,IAAI,MAAM,GAAG,IAAI;IAIlC;;OAEG;IACH,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAIxC;;OAEG;IACH,YAAY,IAAI,OAAO;CAGxB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Identity Manager - Manages user identity
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.IdentityManager = void 0;
|
|
7
|
+
const uuid_1 = require("../utils/uuid");
|
|
8
|
+
const Storage_1 = require("../core/Storage");
|
|
9
|
+
const logger_1 = require("../utils/logger");
|
|
10
|
+
const validators_1 = require("../utils/validators");
|
|
11
|
+
class IdentityManager {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.anonymousId = null;
|
|
14
|
+
this.externalUserId = null;
|
|
15
|
+
this.userProperties = {};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validates UUID format (8-4-4-4-12 hex characters)
|
|
19
|
+
*/
|
|
20
|
+
isValidUUID(uuid) {
|
|
21
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
22
|
+
return uuidRegex.test(uuid);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Initializes the identity manager
|
|
26
|
+
* Generates or loads anonymous ID from storage
|
|
27
|
+
*/
|
|
28
|
+
async initialize() {
|
|
29
|
+
// Try to load existing anonymous ID from storage
|
|
30
|
+
const storedAnonymousId = await Storage_1.storage.get('ANONYMOUS_ID');
|
|
31
|
+
if (storedAnonymousId && this.isValidUUID(storedAnonymousId)) {
|
|
32
|
+
logger_1.logger.info(`Loaded existing anonymous ID: ${storedAnonymousId}`);
|
|
33
|
+
this.anonymousId = storedAnonymousId;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Generate new anonymous ID if none exists or if stored one is invalid
|
|
37
|
+
if (storedAnonymousId && !this.isValidUUID(storedAnonymousId)) {
|
|
38
|
+
logger_1.logger.warn(`Invalid UUID format detected: ${storedAnonymousId}. Generating new UUID.`);
|
|
39
|
+
}
|
|
40
|
+
this.anonymousId = (0, uuid_1.generateUUID)();
|
|
41
|
+
await Storage_1.storage.set('ANONYMOUS_ID', this.anonymousId);
|
|
42
|
+
logger_1.logger.info(`Generated new anonymous ID: ${this.anonymousId}`);
|
|
43
|
+
}
|
|
44
|
+
// Load external user ID if it exists
|
|
45
|
+
const storedExternalUserId = await Storage_1.storage.get('EXTERNAL_USER_ID');
|
|
46
|
+
if (storedExternalUserId) {
|
|
47
|
+
this.externalUserId = storedExternalUserId;
|
|
48
|
+
logger_1.logger.info(`Loaded external user ID: ${this.externalUserId}`);
|
|
49
|
+
}
|
|
50
|
+
// Load user properties if they exist
|
|
51
|
+
const storedUserProperties = await Storage_1.storage.get('USER_PROPERTIES');
|
|
52
|
+
if (storedUserProperties) {
|
|
53
|
+
this.userProperties = storedUserProperties;
|
|
54
|
+
logger_1.logger.info('Loaded user properties');
|
|
55
|
+
}
|
|
56
|
+
return this.anonymousId;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Identifies a user with an external user ID and optional properties
|
|
60
|
+
*/
|
|
61
|
+
async identify(externalUserId, properties) {
|
|
62
|
+
// Validate inputs
|
|
63
|
+
(0, validators_1.validateUserId)(externalUserId);
|
|
64
|
+
if (properties) {
|
|
65
|
+
(0, validators_1.validateUserProperties)(properties);
|
|
66
|
+
}
|
|
67
|
+
// Store external user ID
|
|
68
|
+
this.externalUserId = externalUserId;
|
|
69
|
+
await Storage_1.storage.set('EXTERNAL_USER_ID', externalUserId);
|
|
70
|
+
logger_1.logger.info(`User identified: ${externalUserId}`);
|
|
71
|
+
// Merge user properties
|
|
72
|
+
if (properties) {
|
|
73
|
+
this.userProperties = {
|
|
74
|
+
...this.userProperties,
|
|
75
|
+
...properties,
|
|
76
|
+
};
|
|
77
|
+
await Storage_1.storage.set('USER_PROPERTIES', this.userProperties);
|
|
78
|
+
logger_1.logger.info('User properties updated');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resets the user identity
|
|
83
|
+
* Generates a new anonymous ID and clears external user ID and properties
|
|
84
|
+
*/
|
|
85
|
+
async reset() {
|
|
86
|
+
logger_1.logger.info('Resetting user identity...');
|
|
87
|
+
// Generate new anonymous ID
|
|
88
|
+
this.anonymousId = (0, uuid_1.generateUUID)();
|
|
89
|
+
await Storage_1.storage.set('ANONYMOUS_ID', this.anonymousId);
|
|
90
|
+
// Clear external user ID
|
|
91
|
+
this.externalUserId = null;
|
|
92
|
+
await Storage_1.storage.remove('EXTERNAL_USER_ID');
|
|
93
|
+
// Clear user properties
|
|
94
|
+
this.userProperties = {};
|
|
95
|
+
await Storage_1.storage.remove('USER_PROPERTIES');
|
|
96
|
+
logger_1.logger.info(`Identity reset. New anonymous ID: ${this.anonymousId}`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Updates user properties (merges with existing)
|
|
100
|
+
*/
|
|
101
|
+
async updateUserProperties(properties) {
|
|
102
|
+
(0, validators_1.validateUserProperties)(properties);
|
|
103
|
+
this.userProperties = {
|
|
104
|
+
...this.userProperties,
|
|
105
|
+
...properties,
|
|
106
|
+
};
|
|
107
|
+
await Storage_1.storage.set('USER_PROPERTIES', this.userProperties);
|
|
108
|
+
logger_1.logger.info('User properties updated');
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Gets the anonymous ID
|
|
112
|
+
*/
|
|
113
|
+
getAnonymousId() {
|
|
114
|
+
return this.anonymousId;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Gets the external user ID
|
|
118
|
+
*/
|
|
119
|
+
getExternalUserId() {
|
|
120
|
+
return this.externalUserId;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Gets user properties
|
|
124
|
+
*/
|
|
125
|
+
getUserProperties() {
|
|
126
|
+
return { ...this.userProperties };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Checks if the user is identified
|
|
130
|
+
*/
|
|
131
|
+
isIdentified() {
|
|
132
|
+
return this.externalUserId !== null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.IdentityManager = IdentityManager;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network Manager - Monitors network connectivity
|
|
3
|
+
*
|
|
4
|
+
* Uses the adapter pattern to automatically select the best network implementation
|
|
5
|
+
* based on available modules (Native > Expo > Fallback)
|
|
6
|
+
*/
|
|
7
|
+
export type NetworkStatusCallback = (isOnline: boolean) => void;
|
|
8
|
+
export declare class NetworkManager {
|
|
9
|
+
private adapter;
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Initializes the network manager and starts monitoring
|
|
13
|
+
*/
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Adds a listener for network status changes
|
|
17
|
+
*/
|
|
18
|
+
onStatusChange(callback: NetworkStatusCallback): () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if currently online
|
|
21
|
+
*/
|
|
22
|
+
isConnected(): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Manually refreshes network status
|
|
25
|
+
*/
|
|
26
|
+
refresh(): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Cleans up the network manager
|
|
29
|
+
*/
|
|
30
|
+
cleanup(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=NetworkManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NetworkManager.d.ts","sourceRoot":"","sources":["../../src/managers/NetworkManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;AAEhE,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAiB;;IAMhC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI;IAoB3D;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAOjC;;OAEG;IACH,OAAO,IAAI,IAAI;CAIhB"}
|