# TimeSafari Daily Notification Plugin API Reference **Author**: Matthew Raymer **Version**: 2.3.0 **Last Updated**: 2025-12-08 ## Overview This API reference provides comprehensive documentation for the TimeSafari Daily Notification Plugin, optimized for **native-first architecture** supporting Android, iOS, and Electron platforms. ### Platform Support - ✅ **Android**: WorkManager + AlarmManager + SQLite - ✅ **iOS**: BGTaskScheduler + UNUserNotificationCenter + Core Data - ✅ **Electron**: Desktop notifications + SQLite/LocalStorage - ❌ **Web (PWA)**: Removed for native-first focus ## DailyNotificationPlugin Interface ### Configuration #### `configure(options: ConfigureOptions): Promise` Configure the plugin with storage, TTL, and optimization settings. **Parameters:** - `options.storage`: `'shared'` | `'tiered'` - Storage mode - `options.ttlSeconds`: `number` - TTL in seconds (default: 1800) - `options.prefetchLeadMinutes`: `number` - Prefetch lead time (default: 15) - `options.enableETagSupport`: `boolean` - Enable ETag conditional requests - `options.enableErrorHandling`: `boolean` - Enable advanced error handling - `options.enablePerformanceOptimization`: `boolean` - Enable performance optimization ### Core Methods #### `scheduleDailyNotification(options: NotificationOptions): Promise` Schedule a daily notification with content fetching. **Parameters:** - `options.url`: `string` - Content endpoint URL - `options.time`: `string` - Time in HH:MM format - `options.title`: `string` - Notification title - `options.body`: `string` - Notification body - `options.sound`: `boolean` - Enable sound (optional) - `options.retryConfig`: `RetryConfiguration` - Custom retry settings (optional) #### `getLastNotification(): Promise` Get the last scheduled notification. #### `cancelAllNotifications(): Promise` Cancel all scheduled notifications. ### Platform-Specific Methods #### Android Only ##### `getExactAlarmStatus(): Promise` Get exact alarm permission and capability status. ##### `requestExactAlarmPermission(): Promise` Request exact alarm permission from user. ##### `openExactAlarmSettings(): Promise` Open exact alarm settings in system preferences. ##### `getRebootRecoveryStatus(): Promise` Get reboot recovery status and statistics. ##### `isAlarmScheduled(options: { triggerAtMillis: number }): Promise<{ scheduled: boolean; triggerAtMillis: number }>` Check if an alarm is scheduled for a specific trigger time. Useful for debugging and verification. **Parameters:** - `options.triggerAtMillis`: `number` - The trigger time in milliseconds (Unix timestamp) **Returns:** - `scheduled`: `boolean` - Whether the alarm is currently scheduled - `triggerAtMillis`: `number` - The trigger time that was checked **Example:** ```typescript const result = await DailyNotification.isAlarmScheduled({ triggerAtMillis: 1762421400000 }); console.log(`Alarm scheduled: ${result.scheduled}`); ``` ##### `getNextAlarmTime(): Promise<{ scheduled: boolean; triggerAtMillis?: number }>` Get the next scheduled alarm time from AlarmManager. Requires Android 5.0+ (API 21+). **Returns:** - `scheduled`: `boolean` - Whether any alarm is scheduled - `triggerAtMillis`: `number | undefined` - The next alarm trigger time (if scheduled) **Example:** ```typescript const result = await DailyNotification.getNextAlarmTime(); if (result.scheduled) { const nextAlarm = new Date(result.triggerAtMillis); console.log(`Next alarm: ${nextAlarm.toLocaleString()}`); } ``` ##### `testAlarm(options?: { secondsFromNow?: number }): Promise<{ scheduled: boolean; secondsFromNow: number; triggerAtMillis: number }>` Schedule a test alarm that fires in a few seconds. Useful for verifying alarm delivery works correctly. **Parameters:** - `options.secondsFromNow`: `number` (optional) - Seconds from now to fire the alarm (default: 5) **Returns:** - `scheduled`: `boolean` - Whether the alarm was scheduled successfully - `secondsFromNow`: `number` - The delay used - `triggerAtMillis`: `number` - The trigger time in milliseconds **Example:** ```typescript const result = await DailyNotification.testAlarm({ secondsFromNow: 10 }); console.log(`Test alarm scheduled for ${result.secondsFromNow} seconds`); ``` #### iOS Only ##### `getNotificationPermissionStatus(): Promise` Get notification permission status on iOS. Required before scheduling notifications. **Returns:** - `authorized`: `boolean` - Whether notifications are authorized - `denied`: `boolean` - Whether notifications are denied - `notDetermined`: `boolean` - Whether permission hasn't been requested yet - `provisional`: `boolean` - Whether provisional authorization is granted (iOS 12+) **Example:** ```typescript const status = await DailyNotification.getNotificationPermissionStatus(); if (!status.authorized) { await DailyNotification.requestNotificationPermission(); } ``` ##### `requestNotificationPermission(): Promise<{ granted: boolean }>` Request notification permission from user. Must be called before scheduling notifications. **Returns:** - `granted`: `boolean` - Whether permission was granted **Example:** ```typescript const result = await DailyNotification.requestNotificationPermission(); if (result.granted) { await DailyNotification.scheduleDailyNotification({ ... }); } ``` ##### `getPendingNotifications(): Promise<{ count: number; notifications: PendingNotification[] }>` Get all pending notifications from UNUserNotificationCenter. Useful for debugging and verification. **Returns:** - `count`: `number` - Number of pending notifications - `notifications`: `PendingNotification[]` - Array of pending notification details **Example:** ```typescript const result = await DailyNotification.getPendingNotifications(); console.log(`Pending notifications: ${result.count}`); result.notifications.forEach(notif => { console.log(`Notification: ${notif.identifier} at ${notif.triggerDate}`); }); ``` ##### `getBackgroundTaskStatus(): Promise` Get background task registration and execution status. Useful for debugging background prefetch. **Returns:** - `fetchTaskRegistered`: `boolean` - Whether fetch background task is registered - `notifyTaskRegistered`: `boolean` - Whether notify background task is registered - `lastFetchExecution`: `number | null` - Last fetch execution time (epoch ms) - `lastNotifyExecution`: `number | null` - Last notify execution time (epoch ms) - `backgroundRefreshEnabled`: `boolean` - Whether Background App Refresh is enabled **Example:** ```typescript const status = await DailyNotification.getBackgroundTaskStatus(); if (!status.backgroundRefreshEnabled) { console.warn('Background App Refresh is disabled. Enable in Settings.'); } ``` ##### `openNotificationSettings(): Promise` Open notification settings in iOS Settings app. Useful for guiding users to enable notifications. **Example:** ```typescript await DailyNotification.openNotificationSettings(); ``` ##### `openBackgroundAppRefreshSettings(): Promise` Open Background App Refresh settings in iOS Settings app. Useful for guiding users to enable background execution. **Example:** ```typescript await DailyNotification.openBackgroundAppRefreshSettings(); ``` ### Management Methods #### `maintainRollingWindow(): Promise` Manually trigger rolling window maintenance. #### `getRollingWindowStats(): Promise` Get rolling window statistics and status. ### Optimization Methods #### `optimizeDatabase(): Promise` Optimize database performance with indexes and settings. #### `optimizeMemory(): Promise` Optimize memory usage and perform cleanup. #### `optimizeBattery(): Promise` Optimize battery usage and background CPU. ### Metrics and Monitoring #### `getPerformanceMetrics(): Promise` Get comprehensive performance metrics. #### `getErrorMetrics(): Promise` Get error handling metrics and statistics. #### `getNetworkMetrics(): Promise` Get network efficiency metrics (ETag support). #### `getMemoryMetrics(): Promise` Get memory usage metrics and statistics. #### `getObjectPoolMetrics(): Promise` Get object pooling efficiency metrics. ### Utility Methods #### `resetPerformanceMetrics(): Promise` Reset all performance metrics to zero. #### `resetErrorMetrics(): Promise` Reset error handling metrics. #### `clearRetryStates(): Promise` Clear all retry states and operations. #### `cleanExpiredETags(): Promise` Clean expired ETag cache entries. ## Data Types ### ConfigureOptions ```typescript interface ConfigureOptions { storage?: 'shared' | 'tiered'; ttlSeconds?: number; prefetchLeadMinutes?: number; enableETagSupport?: boolean; enableErrorHandling?: boolean; enablePerformanceOptimization?: boolean; maxRetries?: number; baseRetryDelay?: number; maxRetryDelay?: number; backoffMultiplier?: number; memoryWarningThreshold?: number; memoryCriticalThreshold?: number; objectPoolSize?: number; maxObjectPoolSize?: number; } ``` ### NotificationOptions ```typescript interface NotificationOptions { url: string; time: string; title: string; body: string; sound?: boolean; retryConfig?: RetryConfiguration; } ``` ### ExactAlarmStatus (Android) ```typescript interface ExactAlarmStatus { supported: boolean; enabled: boolean; canSchedule: boolean; fallbackWindow: string; } ``` ### NotificationPermissionStatus (iOS) ```typescript interface NotificationPermissionStatus { authorized: boolean; denied: boolean; notDetermined: boolean; provisional: boolean; // iOS 12+ } ``` ### PendingNotification (iOS) ```typescript interface PendingNotification { identifier: string; title: string; body: string; triggerDate: number; // epoch ms triggerType: 'calendar' | 'timeInterval' | 'location'; repeats: boolean; } ``` ### BackgroundTaskStatus (iOS) ```typescript interface BackgroundTaskStatus { fetchTaskRegistered: boolean; notifyTaskRegistered: boolean; lastFetchExecution: number | null; // epoch ms lastNotifyExecution: number | null; // epoch ms backgroundRefreshEnabled: boolean; } ``` ### PerformanceMetrics ```typescript interface PerformanceMetrics { overallScore: number; databasePerformance: number; memoryEfficiency: number; batteryEfficiency: number; objectPoolEfficiency: number; totalDatabaseQueries: number; averageMemoryUsage: number; objectPoolHits: number; backgroundCpuUsage: number; totalNetworkRequests: number; recommendations: string[]; } ``` ### ErrorMetrics ```typescript interface ErrorMetrics { totalErrors: number; networkErrors: number; storageErrors: number; schedulingErrors: number; permissionErrors: number; configurationErrors: number; systemErrors: number; unknownErrors: number; cacheHitRatio: number; } ``` ## Error Handling All methods return promises that reject with descriptive error messages. The plugin includes comprehensive error categorization and retry logic. ### Common Error Types - **Network Errors**: Connection timeouts, DNS failures - **Storage Errors**: Database corruption, disk full - **Permission Errors**: Missing exact alarm permission (Android) or notification permission (iOS) - **Configuration Errors**: Invalid parameters, unsupported settings - **System Errors**: Out of memory, platform limitations ### Platform-Specific Errors #### Android - `EXACT_ALARM_PERMISSION_DENIED`: User denied exact alarm permission - `BOOT_RECEIVER_NOT_REGISTERED`: Boot receiver not properly registered - `ALARM_MANAGER_UNAVAILABLE`: AlarmManager service unavailable #### iOS - `NOTIFICATION_PERMISSION_DENIED`: User denied notification permission - `BACKGROUND_REFRESH_DISABLED`: Background App Refresh disabled in Settings - `PENDING_NOTIFICATION_LIMIT_EXCEEDED`: Exceeded 64 notification limit - `BG_TASK_NOT_REGISTERED`: Background task not registered in Info.plist - `BG_TASK_EXECUTION_FAILED`: Background task execution failed ## Platform Differences ### Android - Requires `SCHEDULE_EXACT_ALARM` permission for precise timing - Falls back to windowed alarms (±10m) if exact permission denied - Supports reboot recovery with broadcast receivers - Full performance optimization features - Alarms do NOT persist across reboot (must reschedule) - Force stop clears all alarms (cannot bypass) - App code CAN run when alarm fires (via PendingIntent) ### iOS - Uses `BGTaskScheduler` for background prefetch - Uses `UNUserNotificationCenter` for notification scheduling - Limited to 64 pending notifications (OS constraint) - Automatic background task management - Battery optimization built-in - Notifications persist across app termination and reboot (OS-guaranteed) - App code does NOT run when notification fires (only if user taps) - ±180 second timing tolerance for calendar-based notifications - Background execution severely limited (BGTaskScheduler only, system-controlled) - No user-facing "force stop" equivalent - Must request notification permission before scheduling ### Key Differences Summary | Feature | Android | iOS | | ------- | ------- | --- | | **Notification Persistence** | ❌ Must reschedule after reboot | ✅ Automatic (OS-guaranteed) | | **Code Execution on Fire** | ✅ Yes (PendingIntent) | ❌ No (only if user taps) | | **Background Execution** | ✅ WorkManager, JobScheduler | ⚠️ Limited (BGTaskScheduler) | | **Timing Accuracy** | ✅ Exact (with permission) | ⚠️ ±180 seconds tolerance | | **Force Stop** | ✅ User-facing option | ❌ No equivalent | | **Boot Recovery** | ✅ Must implement | ✅ Automatic (notifications persist) | | **Permission Model** | ✅ Runtime permission | ✅ Runtime permission | | **Pending Limit** | ✅ No limit | ❌ 64 notifications max | ### Electron - Desktop notification support - SQLite or LocalStorage fallback - Native desktop notification APIs - Cross-platform desktop compatibility ## TimeSafari-Specific Integration Examples ### Basic TimeSafari Integration ```typescript import { DailyNotification } from '@timesafari/daily-notification-plugin'; import { TimeSafariIntegrationService } from '@timesafari/daily-notification-plugin'; // Initialize TimeSafari integration const integrationService = TimeSafariIntegrationService.getInstance(); // Configure with TimeSafari-specific settings await integrationService.initialize({ activeDid: 'did:example:timesafari-user-123', storageAdapter: timeSafariStorageAdapter, endorserApiBaseUrl: 'https://endorser.ch/api/v1' }); // Schedule TimeSafari community notifications await DailyNotification.scheduleDailyNotification({ title: 'New Community Update', body: 'You have new offers and project updates', time: '09:00', channel: 'timesafari_community_updates' }); ``` ### TimeSafari Community Features ```typescript // Fetch community data with rate limiting const communityService = new TimeSafariCommunityIntegrationService(); await communityService.initialize({ maxRequestsPerMinute: 30, maxRequestsPerHour: 1000, basePollingIntervalMs: 300000, // 5 minutes adaptivePolling: true }); // Fetch community data const bundle = await communityService.fetchCommunityDataWithRateLimit({ activeDid: 'did:example:timesafari-user-123', fetchOffersToPerson: true, fetchOffersToProjects: true, fetchProjectUpdates: true, starredPlanIds: ['plan-1', 'plan-2', 'plan-3'] }); ``` ### DID-Signed Payloads ```typescript // Generate DID-signed notification payloads const samplePayloads = integrationService.generateSampleDidPayloads(); for (const payload of samplePayloads) { // Verify signature const isValid = await integrationService.verifyDidSignature( JSON.stringify(payload.payload), payload.signature ); console.log(`Payload ${payload.type} signature valid: ${isValid}`); } ``` ### Privacy-Preserving Storage ```typescript // Configure privacy-preserving storage const storageAdapter = new TimeSafariStorageAdapterImpl( nativeStorage, 'timesafari_notifications' ); // Store with TTL and redaction await storageAdapter.store('community_data', bundle, 3600); // 1 hour TTL // Get data retention policy const policy = integrationService.getDataRetentionPolicy(); console.log('Data retention policy:', policy); ```