simplify: Use activeDid-only approach for notifications
- Simplified authentication to use single activeDid instead of complex user management - Updated plugin interface to require only setActiveDid() method - Modified API requests to use activeDid as both issuer and recipient - Streamlined configuration to activeDid: string instead of complex credential object - Aligned JWT generation with simple DID-based authentication pattern - Reduced complexity while maintaining security through DID signing This assumption significantly simplifies the host application integration.
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
**Author**: Matthew Raymer
|
**Author**: Matthew Raymer
|
||||||
**Version**: 1.0.0
|
**Version**: 1.0.0
|
||||||
**Created**: 2025-10-02 07:47:04 UTC
|
**Created**: 2025-10-02 07:47:04 UTC
|
||||||
**Last Updated**: 2025-10-02 10:15:00 UTC
|
**Last Updated**: 2025-10-02 10:45:00 UTC
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ class JWTHelper {
|
|||||||
// Background HTTP Worker
|
// Background HTTP Worker
|
||||||
class DataFetchWorker : CoroutineWorker {
|
class DataFetchWorker : CoroutineWorker {
|
||||||
suspend fun doWork(): Result {
|
suspend fun doWork(): Result {
|
||||||
val jwt = generateJWT(userDid, 60)
|
val jwt = generateJWT(activeDid, 60)
|
||||||
val headers = mapOf(
|
val headers = mapOf(
|
||||||
"Authorization" to "Bearer $jwt",
|
"Authorization" to "Bearer $jwt",
|
||||||
"Content-Type" to "application/json"
|
"Content-Type" to "application/json"
|
||||||
@@ -78,7 +78,7 @@ class DataFetchWorker : CoroutineWorker {
|
|||||||
|
|
||||||
val offersResponse = httpClient.get("$apiServer/api/v2/report/offers") {
|
val offersResponse = httpClient.get("$apiServer/api/v2/report/offers") {
|
||||||
headers { headers.forEach { append(it.key, it.value) } }
|
headers { headers.forEach { append(it.key, it.value) } }
|
||||||
parameter("recipientDid", userDid)
|
parameter("recipientId", activeDid) // Use activeDid for recipient filtering
|
||||||
parameter("afterId", lastKnownOfferId)
|
parameter("afterId", lastKnownOfferId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ class JWTHelper {
|
|||||||
// Background HTTP Task
|
// Background HTTP Task
|
||||||
class DataFetchTask {
|
class DataFetchTask {
|
||||||
func fetchData() async {
|
func fetchData() async {
|
||||||
let jwt = generateJWT(userDid: userDid, expiresInSeconds: 60)
|
let jwt = generateJWT(userDid: activeDid, expiresInSeconds: 60)
|
||||||
var request = URLRequest(url: apiURL)
|
var request = URLRequest(url: apiURL)
|
||||||
request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
|
request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
|
||||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
@@ -173,7 +173,7 @@ interface PluginConfig {
|
|||||||
jwtExpirationSeconds: number;
|
jwtExpirationSeconds: number;
|
||||||
requestTimeoutMs: number;
|
requestTimeoutMs: number;
|
||||||
retryAttempts: number;
|
retryAttempts: number;
|
||||||
userDid: string;
|
activeDid: string; // Simplified to single active DID
|
||||||
lastKnownOfferId?: string;
|
lastKnownOfferId?: string;
|
||||||
lastKnownPlanId?: string;
|
lastKnownPlanId?: string;
|
||||||
}
|
}
|
||||||
@@ -203,11 +203,22 @@ interface PluginConfig {
|
|||||||
|
|
||||||
### Data Persistence
|
### Data Persistence
|
||||||
|
|
||||||
- **Android Room database** for caching API responses
|
#### **Platform-Specific Storage Architecture**
|
||||||
- **iOS Core Data** for persistent storage
|
|
||||||
- **Web IndexedDB** for web platform caching
|
**Android/Electron Platforms:**
|
||||||
- **TTL enforcement** for cached data freshness
|
- **@capacitor-community/sqlite** plugin integration for native SQLite access
|
||||||
- **SQLite integration** via @capacitor-community/sqlite for unified storage across platforms
|
- **Shared plugin database** - Plugin manages its own SQLite database instance
|
||||||
|
- **Direct SQL execution** via plugin's `dbExec()` methods for complex queries
|
||||||
|
- **Background worker integration** for database operations during content fetch
|
||||||
|
|
||||||
|
**Web Platform:**
|
||||||
|
- **absurd-sql** for SQLite support in browser (managed by host application)
|
||||||
|
- **Plugin delegation pattern** - Plugin provides SQL queries, host executes them
|
||||||
|
- **IndexedDB fallback** for basic caching when SQLite unavailable
|
||||||
|
|
||||||
|
**iOS Platform:**
|
||||||
|
- **Core Data integration** via native Swift implementation
|
||||||
|
- **Background task compatibility** with iOS background refresh constraints
|
||||||
|
|
||||||
### State Synchronization
|
### State Synchronization
|
||||||
|
|
||||||
@@ -243,11 +254,78 @@ Based on TimeSafari's optimization patterns:
|
|||||||
|
|
||||||
## Integration Points
|
## Integration Points
|
||||||
|
|
||||||
### Existing Plugin APIs
|
### Enhanced Plugin Interface for Host Application Integration
|
||||||
|
|
||||||
- **Extend** `DailyNotification.configure()` to include API server settings
|
#### **Database Integration Patterns**
|
||||||
- **Add** new methods: `setUserCredentials()`, `fetchActivityData()`, `getCachedData()`
|
|
||||||
- **Trigger** notifications based on fetched data differences
|
**Android/Electron: Plugin-Managed SQLite**
|
||||||
|
```typescript
|
||||||
|
// Plugin handles database operations directly
|
||||||
|
await plugin.configure({
|
||||||
|
dbPath: 'daily_notifications.db',
|
||||||
|
storage: 'shared'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Plugin provides database access methods
|
||||||
|
const results = await plugin.executeContentFetch(config);
|
||||||
|
await plugin.cacheContentData(results);
|
||||||
|
|
||||||
|
// Host application accesses cached data via plugin
|
||||||
|
const cachedData = await plugin.getContentCache();
|
||||||
|
```
|
||||||
|
|
||||||
|
**Web: Host-Managed Database**
|
||||||
|
```typescript
|
||||||
|
// Host application manages absurd-sql database
|
||||||
|
import { openDatabase } from 'absurd-sql';
|
||||||
|
|
||||||
|
const db = await openDatabase('daily_notifications.db');
|
||||||
|
|
||||||
|
// Plugin provides SQL queries, host executes them
|
||||||
|
const query = await plugin.getContentFetchQuery(apiEndpoint, credentials);
|
||||||
|
const results = await db.exec(query);
|
||||||
|
|
||||||
|
// Plugin receives results for processing
|
||||||
|
await plugin.processContentData(results);
|
||||||
|
```
|
||||||
|
|
||||||
|
**iOS: Hybrid Approach**
|
||||||
|
```typescript
|
||||||
|
// Plugin manages Core Data operations on background thread
|
||||||
|
await plugin.scheduleContentFetch(config);
|
||||||
|
|
||||||
|
// Host application accesses stored data via plugin APIs
|
||||||
|
const notificationData = await plugin.getLastNotification();
|
||||||
|
const cachedContent = await plugin.getContentHistory();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **New Plugin Methods Required**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface EnhancedDailyNotificationPlugin {
|
||||||
|
// Database configuration
|
||||||
|
configureDatabase(options: {
|
||||||
|
storageType: 'plugin-managed' | 'host-managed';
|
||||||
|
dbPath?: string;
|
||||||
|
encryption?: boolean;
|
||||||
|
}): Promise<void>;
|
||||||
|
|
||||||
|
// Content fetch with database integration
|
||||||
|
fetchAndStoreContent(config: ContentFetchConfig): Promise<ContentFetchResult>;
|
||||||
|
|
||||||
|
// Credential management - simplified to activeDid only
|
||||||
|
setActiveDid(activeDid: string): Promise<void>;
|
||||||
|
|
||||||
|
// Data access for host application
|
||||||
|
getStoredContent(query: string, params?: any[]): Promise<any[]>;
|
||||||
|
clearStoredContent(options?: { olderThan?: number }): Promise<void>;
|
||||||
|
|
||||||
|
// Background task coordination
|
||||||
|
getBackgroundTaskStatus(): Promise<BackgroundTaskStatus>;
|
||||||
|
pauseBackgroundTasks(): Promise<void>;
|
||||||
|
resumeBackgroundTasks(): Promise<void>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Background Scheduling
|
### Background Scheduling
|
||||||
|
|
||||||
@@ -343,8 +421,9 @@ GET {apiServer}/api/v2/report/offersToPlansOwnedByMe?afterId={jwtId}&beforeId={j
|
|||||||
|
|
||||||
### Token Generation
|
### Token Generation
|
||||||
|
|
||||||
- Accept user DID as input
|
- Accept activeDid as input
|
||||||
- Generate appropriate authentication token based on user's credential type
|
- Generate JWT authentication token using DID signing
|
||||||
|
- Include activeDid as both issuer (`iss`) and subject (`sub`)
|
||||||
- Return token for immediate use or caching
|
- Return token for immediate use or caching
|
||||||
|
|
||||||
### Request Execution
|
### Request Execution
|
||||||
@@ -374,7 +453,11 @@ GET {apiServer}/api/v2/report/offersToPlansOwnedByMe?afterId={jwtId}&beforeId={j
|
|||||||
- Implement DID-based authentication
|
- Implement DID-based authentication
|
||||||
- Integrate API endpoint calls
|
- Integrate API endpoint calls
|
||||||
- Add response parsing and validation
|
- Add response parsing and validation
|
||||||
- Implement basic caching
|
- Implement platform-specific database integration:
|
||||||
|
- **Android/Electron**: Direct @capacitor-community/sqlite integration
|
||||||
|
- **Web**: Plugin delegation pattern with absurd-sql coordination
|
||||||
|
- **iOS**: Core Data background thread integration
|
||||||
|
- Implement simplified activeDid-based authentication and API calls
|
||||||
|
|
||||||
### Phase 3: Background Integration (Weeks 5-6)
|
### Phase 3: Background Integration (Weeks 5-6)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user