Browse Source
- Add example showing how CapacitorPlatformService handles activeDid changes - Show integration with existing TimeSafari PWA activeDid change detection system - Demonstrate plugin reconfiguration when user switches identities - Include change listener system and settings synchronization - Add comprehensive guide explaining activeDid change flow - Show how to extend existing updateActiveDid method for plugin integration This ensures the DailyNotification plugin automatically adapts to activeDid changes while maintaining existing TimeSafari PWA patterns.master
2 changed files with 1226 additions and 0 deletions
@ -0,0 +1,422 @@ |
|||||
|
# TimeSafari PWA - ActiveDid Change Integration Guide |
||||
|
|
||||
|
**Author**: Matthew Raymer |
||||
|
**Version**: 1.0.0 |
||||
|
**Created**: 2025-10-08 06:24:57 UTC |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
This guide explains how the DailyNotification plugin integrates with the existing TimeSafari PWA activeDid change detection system. The TimeSafari PWA has a sophisticated activeDid change management system that the plugin must integrate with. |
||||
|
|
||||
|
## TimeSafari PWA ActiveDid Change System |
||||
|
|
||||
|
### How ActiveDid Changes Work |
||||
|
|
||||
|
#### 1. Database Storage |
||||
|
```sql |
||||
|
-- ActiveDid is stored in active_identity table (single source of truth) |
||||
|
UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1 |
||||
|
``` |
||||
|
|
||||
|
#### 2. PlatformServiceMixin Change Detection |
||||
|
```typescript |
||||
|
// In PlatformServiceMixin.ts |
||||
|
watch: { |
||||
|
currentActiveDid: { |
||||
|
handler(newDid: string | null, oldDid: string | null) { |
||||
|
if (newDid !== oldDid) { |
||||
|
logger.debug(`[PlatformServiceMixin] ActiveDid changed from ${oldDid} to ${newDid}`); |
||||
|
// Clear caches that might be affected by the change |
||||
|
} |
||||
|
}, |
||||
|
immediate: true, |
||||
|
}, |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### 3. Update Method |
||||
|
```typescript |
||||
|
// In PlatformServiceMixin.ts |
||||
|
async $updateActiveDid(newDid: string | null): Promise<void> { |
||||
|
const oldDid = this._currentActiveDid; |
||||
|
this._currentActiveDid = newDid; |
||||
|
|
||||
|
if (newDid !== oldDid) { |
||||
|
// Write to active_identity table (single source of truth) |
||||
|
await this.$dbExec( |
||||
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
||||
|
[newDid || ""] |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### 4. Usage in Components |
||||
|
```typescript |
||||
|
// In IdentitySwitcherView.vue |
||||
|
async switchAccount(did?: string) { |
||||
|
// Update the active DID in the active_identity table |
||||
|
await this.$updateActiveDid(did); |
||||
|
|
||||
|
// Check if we need to load user-specific settings for the new DID |
||||
|
if (did) { |
||||
|
const newSettings = await this.$accountSettings(did); |
||||
|
// Update UI with new settings |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## DailyNotification Plugin Integration |
||||
|
|
||||
|
### How the Plugin Handles ActiveDid Changes |
||||
|
|
||||
|
#### 1. Enhanced updateActiveDid Method |
||||
|
```typescript |
||||
|
// In CapacitorPlatformService.ts |
||||
|
async updateActiveDid(did: string): Promise<void> { |
||||
|
const oldDid = this.currentActiveDid; |
||||
|
|
||||
|
// Update the database (existing TimeSafari pattern) |
||||
|
await this.dbExec( |
||||
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
||||
|
[did], |
||||
|
); |
||||
|
|
||||
|
// Update local tracking |
||||
|
this.currentActiveDid = did; |
||||
|
|
||||
|
// Notify listeners of the change |
||||
|
this.notifyActiveDidChange(did, oldDid); |
||||
|
|
||||
|
// Update DailyNotification plugin if initialized |
||||
|
if (this.dailyNotificationInitialized) { |
||||
|
await this.updateDailyNotificationActiveDid(did, oldDid); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### 2. Plugin Reconfiguration |
||||
|
```typescript |
||||
|
// In CapacitorPlatformService.ts |
||||
|
private async updateDailyNotificationActiveDid(newDid: string, oldDid: string | null): Promise<void> { |
||||
|
try { |
||||
|
logger.log(`[CapacitorPlatformService] Updating DailyNotification plugin activeDid from ${oldDid} to ${newDid}`); |
||||
|
|
||||
|
// Get new settings for the new activeDid |
||||
|
const newSettings = await this.getTimeSafariSettings(); |
||||
|
|
||||
|
// Reconfigure DailyNotification plugin with new activeDid |
||||
|
await DailyNotification.configure({ |
||||
|
timesafariConfig: { |
||||
|
activeDid: newDid, |
||||
|
endpoints: { |
||||
|
projectsLastUpdated: `${newSettings.apiServer}/api/v2/report/plansLastUpdatedBetween` |
||||
|
}, |
||||
|
starredProjectsConfig: { |
||||
|
enabled: true, |
||||
|
starredPlanHandleIds: newSettings.starredPlanHandleIds || [], |
||||
|
lastAckedJwtId: newSettings.lastAckedStarredPlanChangesJwtId || '', |
||||
|
fetchInterval: '0 8 * * *' |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Update TimeSafari Integration Service |
||||
|
if (this.integrationService) { |
||||
|
await this.integrationService.initialize({ |
||||
|
activeDid: newDid, |
||||
|
storageAdapter: this.getTimeSafariStorageAdapter(), |
||||
|
endorserApiBaseUrl: newSettings.apiServer || 'https://endorser.ch' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} catch (error) { |
||||
|
logger.error(`[CapacitorPlatformService] Failed to update DailyNotification plugin activeDid:`, error); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### 3. Change Listener System |
||||
|
```typescript |
||||
|
// In CapacitorPlatformService.ts |
||||
|
private activeDidChangeListeners: Array<(newDid: string | null, oldDid: string | null) => void> = []; |
||||
|
|
||||
|
addActiveDidChangeListener(listener: (newDid: string | null, oldDid: string | null) => void): void { |
||||
|
this.activeDidChangeListeners.push(listener); |
||||
|
} |
||||
|
|
||||
|
removeActiveDidChangeListener(listener: (newDid: string | null, oldDid: string | null) => void): void { |
||||
|
const index = this.activeDidChangeListeners.indexOf(listener); |
||||
|
if (index > -1) { |
||||
|
this.activeDidChangeListeners.splice(index, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private notifyActiveDidChange(newDid: string | null, oldDid: string | null): void { |
||||
|
this.activeDidChangeListeners.forEach(listener => { |
||||
|
try { |
||||
|
listener(newDid, oldDid); |
||||
|
} catch (error) { |
||||
|
logger.error('[CapacitorPlatformService] Error in activeDid change listener:', error); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## Integration Flow |
||||
|
|
||||
|
### 1. User Switches Identity |
||||
|
``` |
||||
|
User clicks "Switch Account" → IdentitySwitcherView.switchAccount() → |
||||
|
$updateActiveDid() → CapacitorPlatformService.updateActiveDid() → |
||||
|
DailyNotification plugin reconfiguration |
||||
|
``` |
||||
|
|
||||
|
### 2. Plugin Reconfiguration Process |
||||
|
``` |
||||
|
1. Update database (existing TimeSafari pattern) |
||||
|
2. Update local tracking |
||||
|
3. Notify change listeners |
||||
|
4. Reconfigure DailyNotification plugin |
||||
|
5. Update TimeSafari Integration Service |
||||
|
6. Log the change |
||||
|
``` |
||||
|
|
||||
|
### 3. Settings Update Process |
||||
|
``` |
||||
|
1. Get new settings for new activeDid |
||||
|
2. Update plugin configuration with new settings |
||||
|
3. Update integration service with new activeDid |
||||
|
4. Clear any cached data for old activeDid |
||||
|
5. Initialize new activeDid-specific data |
||||
|
``` |
||||
|
|
||||
|
## Required Changes to Existing Code |
||||
|
|
||||
|
### File: `src/services/platforms/CapacitorPlatformService.ts` |
||||
|
|
||||
|
#### 1. Add New Properties |
||||
|
```typescript |
||||
|
export class CapacitorPlatformService implements PlatformService { |
||||
|
// ... existing properties ... |
||||
|
|
||||
|
// ADD THESE NEW PROPERTIES |
||||
|
private dailyNotificationService: DailyNotification | null = null; |
||||
|
private integrationService: TimeSafariIntegrationService | null = null; |
||||
|
private dailyNotificationInitialized = false; |
||||
|
|
||||
|
// ActiveDid change tracking |
||||
|
private currentActiveDid: string | null = null; |
||||
|
private activeDidChangeListeners: Array<(newDid: string | null, oldDid: string | null) => void> = []; |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### 2. Modify Existing updateActiveDid Method |
||||
|
```typescript |
||||
|
async updateActiveDid(did: string): Promise<void> { |
||||
|
const oldDid = this.currentActiveDid; |
||||
|
|
||||
|
// Update the database (existing TimeSafari pattern) |
||||
|
await this.dbExec( |
||||
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
||||
|
[did], |
||||
|
); |
||||
|
|
||||
|
// Update local tracking |
||||
|
this.currentActiveDid = did; |
||||
|
|
||||
|
// Notify listeners of the change |
||||
|
this.notifyActiveDidChange(did, oldDid); |
||||
|
|
||||
|
// Update DailyNotification plugin if initialized |
||||
|
if (this.dailyNotificationInitialized) { |
||||
|
await this.updateDailyNotificationActiveDid(did, oldDid); |
||||
|
} |
||||
|
|
||||
|
logger.debug(`[CapacitorPlatformService] ActiveDid updated from ${oldDid} to ${did}`); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### 3. Add New Methods |
||||
|
```typescript |
||||
|
// Add these new methods to the class |
||||
|
private async updateDailyNotificationActiveDid(newDid: string, oldDid: string | null): Promise<void> { /* ... */ } |
||||
|
private async getCurrentActiveDid(): Promise<string | null> { /* ... */ } |
||||
|
addActiveDidChangeListener(listener: (newDid: string | null, oldDid: string | null) => void): void { /* ... */ } |
||||
|
removeActiveDidChangeListener(listener: (newDid: string | null, oldDid: string | null) => void): void { /* ... */ } |
||||
|
private notifyActiveDidChange(newDid: string | null, oldDid: string | null): void { /* ... */ } |
||||
|
``` |
||||
|
|
||||
|
## PlatformServiceMixin Integration |
||||
|
|
||||
|
### File: `src/utils/PlatformServiceMixin.ts` |
||||
|
|
||||
|
#### 1. Add DailyNotification Methods |
||||
|
```typescript |
||||
|
methods: { |
||||
|
// ... existing methods ... |
||||
|
|
||||
|
/** |
||||
|
* Initialize DailyNotification plugin (Capacitor only) |
||||
|
*/ |
||||
|
async $initializeDailyNotification(): Promise<void> { |
||||
|
if (this.isCapacitor) { |
||||
|
await this.platformService.initializeDailyNotification(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Enhanced loadNewStarredProjectChanges method |
||||
|
*/ |
||||
|
async $loadNewStarredProjectChanges(): Promise<StarredProjectsResponse> { |
||||
|
if (this.isCapacitor) { |
||||
|
return await this.platformService.loadNewStarredProjectChanges(); |
||||
|
} else { |
||||
|
// Fall back to existing web method |
||||
|
return await this.$loadNewStarredProjectChangesWeb(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## Vue Component Integration |
||||
|
|
||||
|
### File: `src/views/HomeView.vue` (or similar) |
||||
|
|
||||
|
#### 1. Add DailyNotification Initialization |
||||
|
```typescript |
||||
|
export default defineComponent({ |
||||
|
name: 'HomeView', |
||||
|
|
||||
|
mixins: [PlatformServiceMixin], |
||||
|
|
||||
|
async mounted() { |
||||
|
// Initialize DailyNotification (only on Capacitor) |
||||
|
if (this.isCapacitor) { |
||||
|
await this.$initializeDailyNotification(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
/** |
||||
|
* Enhanced loadNewStarredProjectChanges method |
||||
|
*/ |
||||
|
async loadNewStarredProjectChanges(): Promise<void> { |
||||
|
if (this.isCapacitor) { |
||||
|
// Use plugin-enhanced method on Capacitor |
||||
|
const result = await this.$loadNewStarredProjectChanges(); |
||||
|
this.numNewStarredProjectChanges = result.data.length; |
||||
|
this.newStarredProjectChangesHitLimit = result.hitLimit; |
||||
|
} else { |
||||
|
// Use existing web method in browser |
||||
|
await this.loadNewStarredProjectChangesWeb(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
``` |
||||
|
|
||||
|
## Key Benefits |
||||
|
|
||||
|
### 1. Seamless ActiveDid Change Handling |
||||
|
- **Automatic Reconfiguration**: Plugin automatically reconfigures when activeDid changes |
||||
|
- **Settings Synchronization**: New activeDid settings are automatically loaded and applied |
||||
|
- **Error Handling**: Robust error handling for activeDid change failures |
||||
|
- **Logging**: Comprehensive logging for debugging activeDid changes |
||||
|
|
||||
|
### 2. Integration with Existing Patterns |
||||
|
- **Uses Existing Methods**: Leverages existing `updateActiveDid` method |
||||
|
- **Database Consistency**: Uses existing `active_identity` table pattern |
||||
|
- **Change Detection**: Integrates with existing change detection system |
||||
|
- **Settings Management**: Uses existing settings retrieval patterns |
||||
|
|
||||
|
### 3. Enhanced Functionality |
||||
|
- **Background Fetching**: Continues to work with new activeDid |
||||
|
- **Notification Scheduling**: Updates notifications for new activeDid |
||||
|
- **Storage Management**: Manages storage for multiple activeDids |
||||
|
- **Observability**: Tracks activeDid changes in logs and metrics |
||||
|
|
||||
|
## Testing Strategy |
||||
|
|
||||
|
### 1. ActiveDid Change Testing |
||||
|
```typescript |
||||
|
// Test activeDid change handling |
||||
|
const testActiveDidChange = async () => { |
||||
|
// Switch to new activeDid |
||||
|
await platformService.updateActiveDid('new-did-123'); |
||||
|
|
||||
|
// Verify plugin is reconfigured |
||||
|
const status = await platformService.getDailyNotificationStatus(); |
||||
|
assert.equal(status.currentActiveDid, 'new-did-123'); |
||||
|
|
||||
|
// Test starred projects fetch with new activeDid |
||||
|
const result = await platformService.loadNewStarredProjectChanges(); |
||||
|
assert.ok(result.data !== undefined); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
### 2. Settings Synchronization Testing |
||||
|
```typescript |
||||
|
// Test settings synchronization |
||||
|
const testSettingsSynchronization = async () => { |
||||
|
// Switch activeDid |
||||
|
await platformService.updateActiveDid('new-did-123'); |
||||
|
|
||||
|
// Verify settings are loaded for new activeDid |
||||
|
const settings = await platformService.getTimeSafariSettings(); |
||||
|
assert.equal(settings.activeDid, 'new-did-123'); |
||||
|
|
||||
|
// Verify plugin configuration is updated |
||||
|
const config = await DailyNotification.getConfiguration(); |
||||
|
assert.equal(config.timesafariConfig.activeDid, 'new-did-123'); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
### 3. Error Handling Testing |
||||
|
```typescript |
||||
|
// Test error handling during activeDid changes |
||||
|
const testErrorHandling = async () => { |
||||
|
try { |
||||
|
// Switch to invalid activeDid |
||||
|
await platformService.updateActiveDid('invalid-did'); |
||||
|
|
||||
|
// Verify error is handled gracefully |
||||
|
const status = await platformService.getDailyNotificationStatus(); |
||||
|
assert.ok(status.initialized); // Plugin should remain initialized |
||||
|
|
||||
|
} catch (error) { |
||||
|
// Verify error is logged |
||||
|
assert.ok(error.message.includes('activeDid')); |
||||
|
} |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
## Common Issues and Solutions |
||||
|
|
||||
|
### Issue 1: Plugin Not Updating on ActiveDid Change |
||||
|
**Solution**: Ensure `updateDailyNotificationActiveDid` is called in the `updateActiveDid` method |
||||
|
|
||||
|
### Issue 2: Settings Not Loading for New ActiveDid |
||||
|
**Solution**: Verify `getTimeSafariSettings` uses the current activeDid from database |
||||
|
|
||||
|
### Issue 3: Cached Data from Old ActiveDid |
||||
|
**Solution**: Clear plugin caches when activeDid changes |
||||
|
|
||||
|
### Issue 4: Background Fetching with Wrong ActiveDid |
||||
|
**Solution**: Ensure plugin reconfiguration includes new activeDid in all requests |
||||
|
|
||||
|
## Conclusion |
||||
|
|
||||
|
The DailyNotification plugin integrates seamlessly with the existing TimeSafari PWA activeDid change system by: |
||||
|
|
||||
|
- **Extending the existing `updateActiveDid` method** to handle plugin reconfiguration |
||||
|
- **Using the existing change detection patterns** from PlatformServiceMixin |
||||
|
- **Maintaining database consistency** with the existing `active_identity` table |
||||
|
- **Providing robust error handling** for activeDid change failures |
||||
|
- **Supporting multiple activeDids** with proper isolation and cleanup |
||||
|
|
||||
|
The integration ensures that the plugin automatically adapts to activeDid changes while maintaining the same interface and behavior as the existing TimeSafari PWA code. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**Key Takeaway**: The CapacitorPlatformService **does know** when activeDid changes through the existing `updateActiveDid` method, and the DailyNotification plugin integrates with this system to automatically reconfigure when the user switches identities. |
@ -0,0 +1,804 @@ |
|||||
|
/** |
||||
|
* TimeSafari PWA - CapacitorPlatformService ActiveDid Integration Example |
||||
|
* |
||||
|
* This example shows how to extend the existing CapacitorPlatformService |
||||
|
* to handle activeDid changes and integrate with the DailyNotification plugin. |
||||
|
* |
||||
|
* This represents the ACTUAL CHANGES needed to handle activeDid changes |
||||
|
* in the existing TimeSafari PWA CapacitorPlatformService. |
||||
|
* |
||||
|
* @author Matthew Raymer |
||||
|
* @version 1.0.0 |
||||
|
*/ |
||||
|
|
||||
|
// =================================================
|
||||
|
// EXISTING TIMESAFARI PWA CODE (unchanged)
|
||||
|
// =================================================
|
||||
|
|
||||
|
import { Filesystem, Directory, Encoding } from "@capacitor/filesystem"; |
||||
|
import { |
||||
|
Camera, |
||||
|
CameraResultType, |
||||
|
CameraSource, |
||||
|
CameraDirection, |
||||
|
} from "@capacitor/camera"; |
||||
|
import { Capacitor } from "@capacitor/core"; |
||||
|
import { Share } from "@capacitor/share"; |
||||
|
import { |
||||
|
SQLiteConnection, |
||||
|
SQLiteDBConnection, |
||||
|
CapacitorSQLite, |
||||
|
DBSQLiteValues, |
||||
|
} from "@capacitor-community/sqlite"; |
||||
|
|
||||
|
import { runMigrations } from "@/db-sql/migration"; |
||||
|
import { QueryExecResult } from "@/interfaces/database"; |
||||
|
import { |
||||
|
ImageResult, |
||||
|
PlatformService, |
||||
|
PlatformCapabilities, |
||||
|
} from "../PlatformService"; |
||||
|
import { logger } from "../../utils/logger"; |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW IMPORTS FOR DAILYNOTIFICATION PLUGIN
|
||||
|
// =================================================
|
||||
|
|
||||
|
import { DailyNotification } from '@timesafari/daily-notification-plugin'; |
||||
|
import { TimeSafariIntegrationService } from '@timesafari/daily-notification-plugin'; |
||||
|
|
||||
|
// =================================================
|
||||
|
// EXISTING INTERFACES (unchanged)
|
||||
|
// =================================================
|
||||
|
|
||||
|
interface QueuedOperation { |
||||
|
type: "run" | "query" | "rawQuery"; |
||||
|
sql: string; |
||||
|
params: unknown[]; |
||||
|
resolve: (value: unknown) => void; |
||||
|
reject: (reason: unknown) => void; |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW INTERFACES FOR DAILYNOTIFICATION PLUGIN
|
||||
|
// =================================================
|
||||
|
|
||||
|
interface PlanSummaryAndPreviousClaim { |
||||
|
id: string; |
||||
|
title: string; |
||||
|
description: string; |
||||
|
lastUpdated: string; |
||||
|
previousClaim?: unknown; |
||||
|
} |
||||
|
|
||||
|
interface StarredProjectsResponse { |
||||
|
data: Array<PlanSummaryAndPreviousClaim>; |
||||
|
hitLimit: boolean; |
||||
|
} |
||||
|
|
||||
|
interface TimeSafariSettings { |
||||
|
accountDid?: string; |
||||
|
activeDid?: string; |
||||
|
apiServer?: string; |
||||
|
starredPlanHandleIds?: string[]; |
||||
|
lastAckedStarredPlanChangesJwtId?: string; |
||||
|
[key: string]: unknown; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* EXTENDED CapacitorPlatformService with DailyNotification and ActiveDid Integration |
||||
|
* |
||||
|
* This shows the ACTUAL CHANGES needed to the existing TimeSafari PWA |
||||
|
* CapacitorPlatformService class to handle activeDid changes and integrate |
||||
|
* with the DailyNotification plugin. |
||||
|
*/ |
||||
|
export class CapacitorPlatformService implements PlatformService { |
||||
|
// =================================================
|
||||
|
// EXISTING PROPERTIES (unchanged)
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** Current camera direction */ |
||||
|
private currentDirection: CameraDirection = CameraDirection.Rear; |
||||
|
|
||||
|
private sqlite: SQLiteConnection; |
||||
|
private db: SQLiteDBConnection | null = null; |
||||
|
private dbName = "timesafari.sqlite"; |
||||
|
private initialized = false; |
||||
|
private initializationPromise: Promise<void> | null = null; |
||||
|
private operationQueue: Array<QueuedOperation> = []; |
||||
|
private isProcessingQueue: boolean = false; |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW PROPERTIES FOR DAILYNOTIFICATION PLUGIN
|
||||
|
// =================================================
|
||||
|
|
||||
|
private dailyNotificationService: DailyNotification | null = null; |
||||
|
private integrationService: TimeSafariIntegrationService | null = null; |
||||
|
private dailyNotificationInitialized = false; |
||||
|
|
||||
|
// ActiveDid change tracking
|
||||
|
private currentActiveDid: string | null = null; |
||||
|
private activeDidChangeListeners: Array<(newDid: string | null, oldDid: string | null) => void> = []; |
||||
|
|
||||
|
// =================================================
|
||||
|
// EXISTING CONSTRUCTOR (unchanged)
|
||||
|
// =================================================
|
||||
|
|
||||
|
constructor() { |
||||
|
this.sqlite = new SQLiteConnection(CapacitorSQLite); |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// MODIFIED METHOD: Enhanced updateActiveDid with DailyNotification Integration
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Enhanced updateActiveDid method that handles DailyNotification plugin updates |
||||
|
* |
||||
|
* This method extends the existing updateActiveDid method to also update |
||||
|
* the DailyNotification plugin when the activeDid changes. |
||||
|
*/ |
||||
|
async updateActiveDid(did: string): Promise<void> { |
||||
|
const oldDid = this.currentActiveDid; |
||||
|
|
||||
|
// Update the database (existing TimeSafari pattern)
|
||||
|
await this.dbExec( |
||||
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
||||
|
[did], |
||||
|
); |
||||
|
|
||||
|
// Update local tracking
|
||||
|
this.currentActiveDid = did; |
||||
|
|
||||
|
// Notify listeners of the change
|
||||
|
this.notifyActiveDidChange(did, oldDid); |
||||
|
|
||||
|
// Update DailyNotification plugin if initialized
|
||||
|
if (this.dailyNotificationInitialized) { |
||||
|
await this.updateDailyNotificationActiveDid(did, oldDid); |
||||
|
} |
||||
|
|
||||
|
logger.debug( |
||||
|
`[CapacitorPlatformService] ActiveDid updated from ${oldDid} to ${did}` |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: Update DailyNotification Plugin ActiveDid
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Update DailyNotification plugin when activeDid changes |
||||
|
* |
||||
|
* This method reconfigures the DailyNotification plugin with the new |
||||
|
* activeDid and updates all related settings. |
||||
|
*/ |
||||
|
private async updateDailyNotificationActiveDid(newDid: string, oldDid: string | null): Promise<void> { |
||||
|
try { |
||||
|
logger.log(`[CapacitorPlatformService] Updating DailyNotification plugin activeDid from ${oldDid} to ${newDid}`); |
||||
|
|
||||
|
// Get new settings for the new activeDid
|
||||
|
const newSettings = await this.getTimeSafariSettings(); |
||||
|
|
||||
|
// Reconfigure DailyNotification plugin with new activeDid
|
||||
|
await DailyNotification.configure({ |
||||
|
timesafariConfig: { |
||||
|
activeDid: newDid, |
||||
|
endpoints: { |
||||
|
offersToPerson: `${newSettings.apiServer}/api/v2/offers/person`, |
||||
|
offersToPlans: `${newSettings.apiServer}/api/v2/offers/plans`, |
||||
|
projectsLastUpdated: `${newSettings.apiServer}/api/v2/report/plansLastUpdatedBetween` |
||||
|
}, |
||||
|
starredProjectsConfig: { |
||||
|
enabled: true, |
||||
|
starredPlanHandleIds: newSettings.starredPlanHandleIds || [], |
||||
|
lastAckedJwtId: newSettings.lastAckedStarredPlanChangesJwtId || '', |
||||
|
fetchInterval: '0 8 * * *' |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Update TimeSafari Integration Service
|
||||
|
if (this.integrationService) { |
||||
|
await this.integrationService.initialize({ |
||||
|
activeDid: newDid, |
||||
|
storageAdapter: this.getTimeSafariStorageAdapter(), |
||||
|
endorserApiBaseUrl: newSettings.apiServer || 'https://endorser.ch' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
logger.log(`[CapacitorPlatformService] DailyNotification plugin updated successfully for activeDid: ${newDid}`); |
||||
|
|
||||
|
} catch (error) { |
||||
|
logger.error(`[CapacitorPlatformService] Failed to update DailyNotification plugin activeDid:`, error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: ActiveDid Change Listener Management
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Add listener for activeDid changes |
||||
|
* |
||||
|
* This method allows components to register listeners that will be |
||||
|
* notified when the activeDid changes. |
||||
|
*/ |
||||
|
addActiveDidChangeListener(listener: (newDid: string | null, oldDid: string | null) => void): void { |
||||
|
this.activeDidChangeListeners.push(listener); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Remove listener for activeDid changes |
||||
|
*/ |
||||
|
removeActiveDidChangeListener(listener: (newDid: string | null, oldDid: string | null) => void): void { |
||||
|
const index = this.activeDidChangeListeners.indexOf(listener); |
||||
|
if (index > -1) { |
||||
|
this.activeDidChangeListeners.splice(index, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Notify all listeners of activeDid change |
||||
|
*/ |
||||
|
private notifyActiveDidChange(newDid: string | null, oldDid: string | null): void { |
||||
|
this.activeDidChangeListeners.forEach(listener => { |
||||
|
try { |
||||
|
listener(newDid, oldDid); |
||||
|
} catch (error) { |
||||
|
logger.error('[CapacitorPlatformService] Error in activeDid change listener:', error); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: Initialize DailyNotification Plugin
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Initialize DailyNotification plugin with TimeSafari configuration |
||||
|
* |
||||
|
* This method should be called after the database is initialized |
||||
|
* to set up the DailyNotification plugin with TimeSafari-specific settings. |
||||
|
*/ |
||||
|
async initializeDailyNotification(): Promise<void> { |
||||
|
if (this.dailyNotificationInitialized) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
logger.log("[CapacitorPlatformService] Initializing DailyNotification plugin..."); |
||||
|
|
||||
|
// Get current TimeSafari settings
|
||||
|
const settings = await this.getTimeSafariSettings(); |
||||
|
|
||||
|
// Get current activeDid
|
||||
|
const currentActiveDid = await this.getCurrentActiveDid(); |
||||
|
|
||||
|
// Configure DailyNotification plugin with TimeSafari data
|
||||
|
await DailyNotification.configure({ |
||||
|
// Basic plugin configuration
|
||||
|
storage: 'tiered', |
||||
|
ttlSeconds: 1800, |
||||
|
enableETagSupport: true, |
||||
|
enableErrorHandling: true, |
||||
|
enablePerformanceOptimization: true, |
||||
|
|
||||
|
// TimeSafari-specific configuration
|
||||
|
timesafariConfig: { |
||||
|
// Use current activeDid
|
||||
|
activeDid: currentActiveDid || '', |
||||
|
|
||||
|
// Use existing TimeSafari API endpoints
|
||||
|
endpoints: { |
||||
|
offersToPerson: `${settings.apiServer}/api/v2/offers/person`, |
||||
|
offersToPlans: `${settings.apiServer}/api/v2/offers/plans`, |
||||
|
projectsLastUpdated: `${settings.apiServer}/api/v2/report/plansLastUpdatedBetween` |
||||
|
}, |
||||
|
|
||||
|
// Configure starred projects fetching (matches existing TimeSafari pattern)
|
||||
|
starredProjectsConfig: { |
||||
|
enabled: true, |
||||
|
starredPlanHandleIds: settings.starredPlanHandleIds || [], |
||||
|
lastAckedJwtId: settings.lastAckedStarredPlanChangesJwtId || '', |
||||
|
fetchInterval: '0 8 * * *', // Daily at 8 AM
|
||||
|
maxResults: 50, |
||||
|
hitLimitHandling: 'warn' // Same as existing TimeSafari error handling
|
||||
|
}, |
||||
|
|
||||
|
// Sync configuration (optimized for TimeSafari use case)
|
||||
|
syncConfig: { |
||||
|
enableParallel: true, |
||||
|
maxConcurrent: 3, |
||||
|
batchSize: 10, |
||||
|
timeout: 30000, |
||||
|
retryAttempts: 3 |
||||
|
}, |
||||
|
|
||||
|
// Error policy (matches existing TimeSafari error handling)
|
||||
|
errorPolicy: { |
||||
|
maxRetries: 3, |
||||
|
backoffMultiplier: 2, |
||||
|
activeDidChangeRetries: 5, // Special retry for activeDid changes
|
||||
|
starredProjectsRetries: 3 |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Network configuration using existing TimeSafari patterns
|
||||
|
networkConfig: { |
||||
|
baseURL: settings.apiServer || 'https://endorser.ch', |
||||
|
timeout: 30000, |
||||
|
retryAttempts: 3, |
||||
|
retryDelay: 1000, |
||||
|
maxConcurrent: 5, |
||||
|
|
||||
|
// Headers matching TimeSafari pattern
|
||||
|
defaultHeaders: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Accept': 'application/json', |
||||
|
'User-Agent': 'TimeSafari-PWA/1.0.0' |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Content fetch configuration (replaces existing loadNewStarredProjectChanges)
|
||||
|
contentFetch: { |
||||
|
enabled: true, |
||||
|
schedule: '0 8 * * *', // Daily at 8 AM
|
||||
|
|
||||
|
// Use existing TimeSafari request pattern
|
||||
|
requestConfig: { |
||||
|
method: 'POST', |
||||
|
url: `${settings.apiServer}/api/v2/report/plansLastUpdatedBetween`, |
||||
|
headers: { |
||||
|
'Authorization': 'Bearer ${jwt}', |
||||
|
'X-User-DID': '${activeDid}', |
||||
|
'Content-Type': 'application/json' |
||||
|
}, |
||||
|
body: { |
||||
|
planIds: '${starredPlanHandleIds}', |
||||
|
afterId: '${lastAckedJwtId}' |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Callbacks that match TimeSafari error handling
|
||||
|
callbacks: { |
||||
|
onSuccess: this.handleStarredProjectsSuccess.bind(this), |
||||
|
onError: this.handleStarredProjectsError.bind(this), |
||||
|
onComplete: this.handleStarredProjectsComplete.bind(this) |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Initialize TimeSafari Integration Service
|
||||
|
this.integrationService = TimeSafariIntegrationService.getInstance(); |
||||
|
await this.integrationService.initialize({ |
||||
|
activeDid: currentActiveDid || '', |
||||
|
storageAdapter: this.getTimeSafariStorageAdapter(), |
||||
|
endorserApiBaseUrl: settings.apiServer || 'https://endorser.ch', |
||||
|
|
||||
|
// Use existing TimeSafari request patterns
|
||||
|
requestConfig: { |
||||
|
baseURL: settings.apiServer || 'https://endorser.ch', |
||||
|
timeout: 30000, |
||||
|
retryAttempts: 3 |
||||
|
}, |
||||
|
|
||||
|
// Configure starred projects fetching
|
||||
|
starredProjectsConfig: { |
||||
|
enabled: true, |
||||
|
starredPlanHandleIds: settings.starredPlanHandleIds || [], |
||||
|
lastAckedJwtId: settings.lastAckedStarredPlanChangesJwtId || '', |
||||
|
fetchInterval: '0 8 * * *', |
||||
|
maxResults: 50 |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Schedule daily notifications
|
||||
|
await DailyNotification.scheduleDailyNotification({ |
||||
|
title: 'TimeSafari Community Update', |
||||
|
body: 'You have new offers and project updates', |
||||
|
time: '09:00', |
||||
|
channel: 'timesafari_community_updates' |
||||
|
}); |
||||
|
|
||||
|
this.dailyNotificationInitialized = true; |
||||
|
this.currentActiveDid = currentActiveDid; |
||||
|
|
||||
|
logger.log("[CapacitorPlatformService] DailyNotification plugin initialized successfully"); |
||||
|
|
||||
|
} catch (error) { |
||||
|
logger.error("[CapacitorPlatformService] Failed to initialize DailyNotification plugin:", error); |
||||
|
throw error; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: Get Current ActiveDid
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Get current activeDid from the database |
||||
|
* |
||||
|
* This method retrieves the current activeDid from the active_identity table |
||||
|
* using the existing TimeSafari pattern. |
||||
|
*/ |
||||
|
private async getCurrentActiveDid(): Promise<string | null> { |
||||
|
try { |
||||
|
const result = await this.dbQuery( |
||||
|
"SELECT activeDid FROM active_identity WHERE id = 1" |
||||
|
); |
||||
|
|
||||
|
if (result?.values?.length) { |
||||
|
const activeDid = result.values[0][0] as string | null; |
||||
|
return activeDid; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} catch (error) { |
||||
|
logger.error("[CapacitorPlatformService] Error getting current activeDid:", error); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: Enhanced loadNewStarredProjectChanges
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Enhanced version of existing TimeSafari loadNewStarredProjectChanges method |
||||
|
* |
||||
|
* This method replaces the existing TimeSafari PWA method with plugin-enhanced |
||||
|
* functionality while maintaining the same interface and behavior. |
||||
|
*/ |
||||
|
async loadNewStarredProjectChanges(): Promise<StarredProjectsResponse> { |
||||
|
// Ensure DailyNotification is initialized
|
||||
|
if (!this.dailyNotificationInitialized) { |
||||
|
await this.initializeDailyNotification(); |
||||
|
} |
||||
|
|
||||
|
const settings = await this.getTimeSafariSettings(); |
||||
|
const currentActiveDid = await this.getCurrentActiveDid(); |
||||
|
|
||||
|
if (!currentActiveDid || !settings.starredPlanHandleIds?.length) { |
||||
|
return { data: [], hitLimit: false }; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
// Use plugin's enhanced fetching with same interface as existing TimeSafari code
|
||||
|
const starredProjectChanges = await this.integrationService!.getStarredProjectsWithChanges( |
||||
|
currentActiveDid, |
||||
|
settings.starredPlanHandleIds, |
||||
|
settings.lastAckedStarredPlanChangesJwtId |
||||
|
); |
||||
|
|
||||
|
// Enhanced logging (optional)
|
||||
|
logger.log("[CapacitorPlatformService] Starred projects loaded successfully:", { |
||||
|
count: starredProjectChanges.data.length, |
||||
|
hitLimit: starredProjectChanges.hitLimit, |
||||
|
planIds: settings.starredPlanHandleIds.length, |
||||
|
activeDid: currentActiveDid |
||||
|
}); |
||||
|
|
||||
|
return starredProjectChanges; |
||||
|
|
||||
|
} catch (error) { |
||||
|
// Same error handling as existing TimeSafari code
|
||||
|
logger.warn("[CapacitorPlatformService] Failed to load starred project changes:", error); |
||||
|
return { data: [], hitLimit: false }; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: Get TimeSafari Settings
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Get TimeSafari settings using existing database patterns |
||||
|
* |
||||
|
* This method uses the existing TimeSafari database patterns to retrieve |
||||
|
* settings that are needed for the DailyNotification plugin configuration. |
||||
|
*/ |
||||
|
private async getTimeSafariSettings(): Promise<TimeSafariSettings> { |
||||
|
try { |
||||
|
// Get current activeDid
|
||||
|
const currentActiveDid = await this.getCurrentActiveDid(); |
||||
|
|
||||
|
if (!currentActiveDid) { |
||||
|
return {}; |
||||
|
} |
||||
|
|
||||
|
// Use existing TimeSafari settings retrieval pattern
|
||||
|
const result = await this.dbQuery( |
||||
|
"SELECT * FROM settings WHERE accountDid = ?", |
||||
|
[currentActiveDid] |
||||
|
); |
||||
|
|
||||
|
if (!result?.values?.length) { |
||||
|
return {}; |
||||
|
} |
||||
|
|
||||
|
// Map database columns to values (existing TimeSafari pattern)
|
||||
|
const settings: TimeSafariSettings = {}; |
||||
|
result.columns.forEach((column, index) => { |
||||
|
if (column !== 'id') { |
||||
|
settings[column] = result.values[0][index]; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Set activeDid from current value
|
||||
|
settings.activeDid = currentActiveDid; |
||||
|
|
||||
|
// Handle JSON field parsing (existing TimeSafari pattern)
|
||||
|
if (settings.starredPlanHandleIds && typeof settings.starredPlanHandleIds === 'string') { |
||||
|
try { |
||||
|
settings.starredPlanHandleIds = JSON.parse(settings.starredPlanHandleIds); |
||||
|
} catch { |
||||
|
settings.starredPlanHandleIds = []; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return settings; |
||||
|
} catch (error) { |
||||
|
logger.error("[CapacitorPlatformService] Error getting TimeSafari settings:", error); |
||||
|
return {}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: Get TimeSafari Storage Adapter
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Get TimeSafari storage adapter using existing patterns |
||||
|
* |
||||
|
* This method creates a storage adapter that uses the existing TimeSafari |
||||
|
* database patterns for the DailyNotification plugin. |
||||
|
*/ |
||||
|
private getTimeSafariStorageAdapter(): unknown { |
||||
|
// Return existing TimeSafari storage adapter
|
||||
|
return { |
||||
|
// Use existing TimeSafari storage patterns
|
||||
|
store: async (key: string, value: unknown) => { |
||||
|
await this.dbExec( |
||||
|
"INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)", |
||||
|
[key, JSON.stringify(value)] |
||||
|
); |
||||
|
}, |
||||
|
|
||||
|
retrieve: async (key: string) => { |
||||
|
const result = await this.dbQuery( |
||||
|
"SELECT data FROM temp WHERE id = ?", |
||||
|
[key] |
||||
|
); |
||||
|
|
||||
|
if (result?.values?.length) { |
||||
|
try { |
||||
|
return JSON.parse(result.values[0][0] as string); |
||||
|
} catch { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHODS: Callback Handlers
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Callback handler for successful starred projects fetch |
||||
|
*/ |
||||
|
private async handleStarredProjectsSuccess(data: StarredProjectsResponse): Promise<void> { |
||||
|
// Enhanced logging (optional)
|
||||
|
logger.log("[CapacitorPlatformService] Starred projects success callback:", { |
||||
|
count: data.data.length, |
||||
|
hitLimit: data.hitLimit, |
||||
|
activeDid: this.currentActiveDid |
||||
|
}); |
||||
|
|
||||
|
// Store results in TimeSafari temp table for UI access
|
||||
|
await this.dbExec( |
||||
|
"INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)", |
||||
|
['starred_projects_latest', JSON.stringify(data)] |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Callback handler for starred projects fetch errors |
||||
|
*/ |
||||
|
private async handleStarredProjectsError(error: Error): Promise<void> { |
||||
|
// Same error handling as existing TimeSafari code
|
||||
|
logger.warn("[CapacitorPlatformService] Failed to load starred project changes:", error); |
||||
|
|
||||
|
// Store error in TimeSafari temp table for UI access
|
||||
|
await this.dbExec( |
||||
|
"INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)", |
||||
|
['starred_projects_error', JSON.stringify({ |
||||
|
error: error.message, |
||||
|
timestamp: Date.now(), |
||||
|
activeDid: this.currentActiveDid |
||||
|
})] |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Callback handler for starred projects fetch completion |
||||
|
*/ |
||||
|
private async handleStarredProjectsComplete(result: unknown): Promise<void> { |
||||
|
// Handle completion
|
||||
|
logger.log("[CapacitorPlatformService] Starred projects fetch completed:", { |
||||
|
result, |
||||
|
activeDid: this.currentActiveDid |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// NEW METHOD: Get DailyNotification Status
|
||||
|
// =================================================
|
||||
|
|
||||
|
/** |
||||
|
* Get DailyNotification plugin status for debugging |
||||
|
*/ |
||||
|
async getDailyNotificationStatus(): Promise<{ |
||||
|
initialized: boolean; |
||||
|
platform: string; |
||||
|
capabilities: PlatformCapabilities; |
||||
|
currentActiveDid: string | null; |
||||
|
}> { |
||||
|
return { |
||||
|
initialized: this.dailyNotificationInitialized, |
||||
|
platform: Capacitor.getPlatform(), |
||||
|
capabilities: this.getCapabilities(), |
||||
|
currentActiveDid: this.currentActiveDid |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// MODIFIED METHOD: Enhanced initializeDatabase
|
||||
|
// =================================================
|
||||
|
|
||||
|
private async initializeDatabase(): Promise<void> { |
||||
|
// If already initialized, return immediately
|
||||
|
if (this.initialized) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// If initialization is in progress, wait for it
|
||||
|
if (this.initializationPromise) { |
||||
|
return this.initializationPromise; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
// Start initialization
|
||||
|
this.initializationPromise = this._initialize(); |
||||
|
await this.initializationPromise; |
||||
|
|
||||
|
// NEW: Initialize DailyNotification after database is ready
|
||||
|
await this.initializeDailyNotification(); |
||||
|
|
||||
|
} catch (error) { |
||||
|
logger.error( |
||||
|
"[CapacitorPlatformService] Initialize database method failed:", |
||||
|
error, |
||||
|
); |
||||
|
this.initializationPromise = null; // Reset on failure
|
||||
|
throw error; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// =================================================
|
||||
|
// EXISTING METHODS (unchanged - showing key ones)
|
||||
|
// =================================================
|
||||
|
|
||||
|
private async _initialize(): Promise<void> { |
||||
|
if (this.initialized) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
// Create/Open database
|
||||
|
this.db = await this.sqlite.createConnection( |
||||
|
this.dbName, |
||||
|
false, |
||||
|
"no-encryption", |
||||
|
1, |
||||
|
false, |
||||
|
); |
||||
|
|
||||
|
await this.db.open(); |
||||
|
|
||||
|
// Run migrations
|
||||
|
await this.runCapacitorMigrations(); |
||||
|
|
||||
|
this.initialized = true; |
||||
|
logger.log( |
||||
|
"[CapacitorPlatformService] SQLite database initialized successfully", |
||||
|
); |
||||
|
|
||||
|
// Start processing the queue after initialization
|
||||
|
this.processQueue(); |
||||
|
} catch (error) { |
||||
|
logger.error( |
||||
|
"[CapacitorPlatformService] Error initializing SQLite database:", |
||||
|
error, |
||||
|
); |
||||
|
throw new Error( |
||||
|
"[CapacitorPlatformService] Failed to initialize database", |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ... (all other existing methods remain unchanged)
|
||||
|
|
||||
|
/** |
||||
|
* Gets the capabilities of the Capacitor platform |
||||
|
* @returns Platform capabilities object |
||||
|
*/ |
||||
|
getCapabilities(): PlatformCapabilities { |
||||
|
const platform = Capacitor.getPlatform(); |
||||
|
|
||||
|
return { |
||||
|
hasFileSystem: true, |
||||
|
hasCamera: true, |
||||
|
isMobile: true, // Capacitor is always mobile
|
||||
|
isIOS: platform === "ios", |
||||
|
hasFileDownload: false, // Mobile platforms need sharing
|
||||
|
needsFileHandlingInstructions: true, // Mobile needs instructions
|
||||
|
isNativeApp: true, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @see PlatformService.dbQuery |
||||
|
*/ |
||||
|
async dbQuery(sql: string, params?: unknown[]): Promise<QueryExecResult> { |
||||
|
await this.waitForInitialization(); |
||||
|
return this.queueOperation<QueryExecResult>("query", sql, params || []); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @see PlatformService.dbExec |
||||
|
*/ |
||||
|
async dbExec( |
||||
|
sql: string, |
||||
|
params?: unknown[], |
||||
|
): Promise<{ changes: number; lastId?: number }> { |
||||
|
await this.waitForInitialization(); |
||||
|
return this.queueOperation<{ changes: number; lastId?: number }>( |
||||
|
"run", |
||||
|
sql, |
||||
|
params || [], |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// ... (all other existing methods remain unchanged)
|
||||
|
|
||||
|
/** |
||||
|
* Checks if running on Capacitor platform. |
||||
|
* @returns true, as this is the Capacitor implementation |
||||
|
*/ |
||||
|
isCapacitor(): boolean { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Checks if running on Electron platform. |
||||
|
* @returns false, as this is Capacitor, not Electron |
||||
|
*/ |
||||
|
isElectron(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Checks if running on web platform. |
||||
|
* @returns false, as this is not web |
||||
|
*/ |
||||
|
isWeb(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// ... (all other existing methods remain unchanged)
|
||||
|
} |
Loading…
Reference in new issue