native-update
Version:
Foundation package for building a comprehensive update system for Capacitor apps. Provides architecture and interfaces but requires backend implementation.
195 lines • 7.08 kB
JavaScript
import { Logger } from '../core/logger';
import { ReviewConditionsChecker } from './review-conditions-checker';
import { ReviewRateLimiter } from './review-rate-limiter';
import { PlatformReviewHandler } from './platform-review-handler';
export class AppReviewManager {
constructor(config) {
this.listeners = new Map();
this.config = config;
this.logger = new Logger('AppReviewManager');
this.conditionsChecker = new ReviewConditionsChecker(config);
this.rateLimiter = new ReviewRateLimiter(config);
this.platformHandler = new PlatformReviewHandler(config);
}
async requestReview(options) {
try {
this.logger.log('Requesting app review', options);
// Check if we can request review (unless forced)
if (!(options === null || options === void 0 ? void 0 : options.force)) {
const availability = await this.canRequestReview();
if (!availability.canRequest) {
return {
displayed: false,
reason: availability.reason || 'Rate limiting active',
};
}
}
// Request review based on platform
const result = await this.platformHandler.requestReview(options);
// Update rate limiting data
if (result.displayed) {
await this.rateLimiter.recordRequest();
// Emit event
this.emit('reviewPromptDisplayed', {
platform: this.platformHandler.getPlatform(),
method: (options === null || options === void 0 ? void 0 : options.useCustomUI) ? 'custom' : 'in-app',
timestamp: Date.now(),
});
}
return result;
}
catch (error) {
this.logger.error('Failed to request review', error);
throw error;
}
}
async canRequestReview() {
try {
this.logger.log('Checking review availability');
// Check rate limits
const rateLimitCheck = await this.rateLimiter.canRequestReview();
if (!rateLimitCheck.canRequest) {
return rateLimitCheck;
}
// Check conditions
const conditionsCheck = await this.conditionsChecker.checkConditions();
if (!conditionsCheck.canRequest) {
return conditionsCheck;
}
// Check platform availability
const platformCheck = await this.platformHandler.isReviewAvailable();
if (!platformCheck) {
return {
canRequest: false,
reason: 'Review not available on this platform',
};
}
return {
canRequest: true,
};
}
catch (error) {
this.logger.error('Failed to check review availability', error);
return {
canRequest: false,
reason: 'Error checking availability',
};
}
}
async openStoreReview() {
try {
this.logger.log('Opening store review page');
const storeUrl = await this.getStoreReviewUrl();
await this.platformHandler.openUrl(storeUrl.url);
// Emit event
this.emit('reviewPromptDisplayed', {
platform: storeUrl.platform,
method: 'store-redirect',
timestamp: Date.now(),
});
}
catch (error) {
this.logger.error('Failed to open store review', error);
throw error;
}
}
async getStoreReviewUrl() {
try {
this.logger.log('Getting store review URL');
return await this.platformHandler.getStoreReviewUrl();
}
catch (error) {
this.logger.error('Failed to get store review URL', error);
throw error;
}
}
async resetReviewPrompts() {
try {
this.logger.log('Resetting review prompts');
await this.rateLimiter.reset();
await this.conditionsChecker.reset();
}
catch (error) {
this.logger.error('Failed to reset review prompts', error);
throw error;
}
}
async setReviewConditions(conditions) {
try {
this.logger.log('Setting review conditions', conditions);
await this.conditionsChecker.setConditions(conditions);
}
catch (error) {
this.logger.error('Failed to set review conditions', error);
throw error;
}
}
async trackSignificantEvent(eventName) {
try {
this.logger.log('Tracking significant event', eventName);
await this.conditionsChecker.trackEvent(eventName);
// Check if we should prompt for review after this event
if (this.config.promptAfterPositiveEvents) {
const canRequest = await this.canRequestReview();
if (canRequest.canRequest) {
// Delay the prompt slightly for better UX
setTimeout(() => {
this.requestReview();
}, 2000);
}
}
}
catch (error) {
this.logger.error('Failed to track significant event', error);
throw error;
}
}
async getReviewMetrics() {
try {
this.logger.log('Getting review metrics');
const metrics = await this.rateLimiter.getMetrics();
const conditions = await this.conditionsChecker.getStatus();
return Object.assign(Object.assign({}, metrics), conditions);
}
catch (error) {
this.logger.error('Failed to get review metrics', error);
throw error;
}
}
addListener(eventName, listenerFunc) {
if (!this.listeners.has(eventName)) {
this.listeners.set(eventName, new Set());
}
this.listeners.get(eventName).add(listenerFunc);
return {
remove: async () => {
const listeners = this.listeners.get(eventName);
if (listeners) {
listeners.delete(listenerFunc);
}
},
};
}
removeAllListeners(eventName) {
if (eventName) {
this.listeners.delete(eventName);
}
else {
this.listeners.clear();
}
}
emit(eventName, data) {
const listeners = this.listeners.get(eventName);
if (listeners) {
listeners.forEach((listener) => {
try {
listener(data);
}
catch (error) {
this.logger.error(`Error in ${eventName} listener`, error);
}
});
}
}
}
//# sourceMappingURL=app-review-manager.js.map