refactor: Switch to Option A host-provided activeDid approach
- Implemented Option A from DATABASE_ACCESS_CLARIFICATION.md - Simplified architecture: Host ALWAYS provides activeDid to plugin - Removed database sharing complexity and hostDbPath requirements - Updated all platform integrations: * Android/Electron: Plugin-managed storage, no host database access * Web: Host-managed storage delegation, plugin doesn't access absurd-sql * iOS: Plugin-managed Core Data, no host database access - Streamlined plugin interface to remove hybrid complexity - Enhanced separation of concerns: * Host: Owns active_identity table and user management * Plugin: Owns notification caching and background tasks - Updated testing strategy to verify database isolation - Simplified implementation phases and dependencies This approach eliminates database access conflicts and provides clearer architectural boundaries between TimeSafari host and notification plugin.
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 11:30:00 UTC
|
**Last Updated**: 2025-10-02 12:30:00 UTC
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -258,81 +258,72 @@ Based on TimeSafari's optimization patterns:
|
|||||||
|
|
||||||
#### **Database Integration Patterns**
|
#### **Database Integration Patterns**
|
||||||
|
|
||||||
**Android/Electron: Hybrid activeDid Approach**
|
**Android/Electron: Host-Provided activeDid Approach (Option A)**
|
||||||
```typescript
|
```typescript
|
||||||
// TimeSafari integration with hybrid activeDid management
|
// Host queries its own database and provides activeDid
|
||||||
await plugin.configureDatabase({
|
const activeIdentity = await this.$getActiveIdentity(); // Uses host's CapacitorSQLite
|
||||||
platform: 'android',
|
|
||||||
storageType: 'hybrid',
|
|
||||||
hostDbPath: 'timesafari.sqlite' // Access TimeSafari's active_identity
|
|
||||||
});
|
|
||||||
|
|
||||||
// Host provides current activeDid
|
|
||||||
const activeIdentity = await this.$getActiveIdentity();
|
|
||||||
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
||||||
|
|
||||||
// CRITICAL: Set up activeDid change listener
|
// Plugin configures its own isolated database
|
||||||
|
await plugin.configureDatabase({
|
||||||
|
platform: 'android',
|
||||||
|
storageType: 'plugin-managed' // Plugin owns its storage
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up activeDid change listener for future changes
|
||||||
plugin.onActiveDidChange(async (newActiveDid) => {
|
plugin.onActiveDidChange(async (newActiveDid) => {
|
||||||
await plugin.clearCacheForNewIdentity();
|
await plugin.clearCacheForNewIdentity();
|
||||||
await plugin.refreshAuthenticationForNewIdentity(newActiveDid);
|
await plugin.refreshAuthenticationForNewIdentity(newActiveDid);
|
||||||
logger.info(`[TimeSafari] ActiveDid changed to: ${newActiveDid}`);
|
logger.info(`[TimeSafari] ActiveDid changed to: ${newActiveDid}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable automatic background lookup
|
|
||||||
await plugin.enableAutoActiveDidMode();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Web: Host-Managed Database with Hybrid activeDid**
|
**Web: Host-Provided activeDid Approach (Option A)**
|
||||||
```typescript
|
```typescript
|
||||||
// Host application manages absurd-sql database
|
// Host queries its absurd-sql database and provides activeDid
|
||||||
|
const activeIdentity = await this.$getActiveIdentity(); // Uses host's absurd-sql
|
||||||
|
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
||||||
|
|
||||||
|
// Plugin uses host-delegated storage for its own data
|
||||||
await plugin.configureDatabase({
|
await plugin.configureDatabase({
|
||||||
platform: 'web',
|
platform: 'web',
|
||||||
storageType: 'hybrid'
|
storageType: 'host-managed' // Plugin delegates to host for storage
|
||||||
});
|
});
|
||||||
|
|
||||||
// Host provides activeDid (plugin doesn't access web database)
|
// Plugin operates independently with provided activeDid
|
||||||
const activeIdentity = await this.$getActiveIdentity();
|
const results = await plugin.executeContentFetch(contentConfig);
|
||||||
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
|
||||||
|
|
||||||
// Plugin delegates SQL operations to host
|
|
||||||
const query = await plugin.getContentFetchQuery(apiEndpoint, activeDid);
|
|
||||||
const results = await hostDatabase.exec(query);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**iOS: Hybrid Approach with Active Identity Access**
|
**iOS: Host-Provided activeDid Approach (Option A)**
|
||||||
```typescript
|
```typescript
|
||||||
// Plugin manages Core Data + reads TimeSafari's active_identity
|
// Host queries its CapacitorSQLite database and provides activeDid
|
||||||
await plugin.configureDatabase({
|
const activeIdentity = await this.$getActiveIdentity(); // Uses host's CapacitorSQLite
|
||||||
platform: 'ios',
|
|
||||||
storageType: 'hybrid',
|
|
||||||
hostDbPath: 'timesafari.sqlite'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Host provides activeDid initially
|
|
||||||
const activeIdentity = await this.$getActiveIdentity();
|
|
||||||
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
||||||
|
|
||||||
// Plugin can refresh activeDid in background tasks
|
// Plugin configures its own Core Data storage
|
||||||
await plugin.enableAutoActiveDidMode();
|
await plugin.configureDatabase({
|
||||||
|
platform: 'ios',
|
||||||
|
storageType: 'plugin-managed' // Plugin owns Core Data storage
|
||||||
|
});
|
||||||
|
|
||||||
|
// Plugin operates with provided activeDid, no database sharing needed
|
||||||
|
const results = await plugin.executeBackgroundContentFetch();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### **New Plugin Methods Required**
|
#### **New Plugin Methods Required**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface EnhancedDailyNotificationPlugin {
|
interface EnhancedDailyNotificationPlugin {
|
||||||
// Database configuration - Platform-aware based on TimeSafari integration
|
// Database configuration - Simplified Option A approach
|
||||||
configureDatabase(options: {
|
configureDatabase(options: {
|
||||||
platform: 'android' | 'ios' | 'web' | 'electron';
|
platform: 'android' | 'ios' | 'web' | 'electron';
|
||||||
storageType: 'plugin-managed' | 'host-managed' | 'hybrid';
|
storageType: 'plugin-managed' | 'host-managed';
|
||||||
dbPath?: string;
|
dbPath?: string;
|
||||||
encryption?: boolean;
|
encryption?: boolean;
|
||||||
hostDbPath?: string; // Path to TimeSafari's active_identity database
|
|
||||||
}): Promise<void>;
|
}): Promise<void>;
|
||||||
|
|
||||||
// Hybrid activeDid Management (Option 3 Implementation)
|
// Host-provided activeDid Management (Option A Implementation)
|
||||||
setActiveDidFromHost(activeDid: string): Promise<void>;
|
setActiveDidFromHost(activeDid: string): Promise<void>;
|
||||||
refreshActiveDidFromDatabase(): Promise<string>;
|
|
||||||
enableAutoActiveDidMode(): Promise<void>;
|
|
||||||
|
|
||||||
// Content fetch with database integration
|
// Content fetch with database integration
|
||||||
fetchAndStoreContent(config: ContentFetchConfig): Promise<ContentFetchResult>;
|
fetchAndStoreContent(config: ContentFetchConfig): Promise<ContentFetchResult>;
|
||||||
@@ -362,15 +353,15 @@ interface EnhancedDailyNotificationPlugin {
|
|||||||
- **Integrate** with existing WorkManager/BGTaskScheduler
|
- **Integrate** with existing WorkManager/BGTaskScheduler
|
||||||
- **Coordinate** API fetch timing with notification schedules
|
- **Coordinate** API fetch timing with notification schedules
|
||||||
- **Handle** app lifecycle events (background/foreground)
|
- **Handle** app lifecycle events (background/foreground)
|
||||||
- **Implement** dual-mode activeDid access:
|
- **Implement** host-provided activeDid access (Option A):
|
||||||
- **Foreground**: Host provides activeDid via `setActiveDidFromHost()`
|
- **Always**: Host provides activeDid via `setActiveDidFromHost()`
|
||||||
- **Background**: Plugin looks up activeDid via `refreshActiveDidFromDatabase()`
|
- **No Database Sharing**: Plugin never accesses TimeSafari's active_identity table
|
||||||
- **Critical**: Plugin **MUST** know when activeDid changes for:
|
- **Critical**: Plugin **MUST** know when activeDid changes for:
|
||||||
- **Event-Based Notification**: Listen for `activeDidChanged` events from TimeSafari
|
- **Event-Based Notification**: Host dispatches `activeDidChanged` events
|
||||||
- **Cache Invalidation**: Clear cached content when user switches identity
|
- **Cache Invalidation**: Clear cached content when user switches identity
|
||||||
- **Token Refresh**: Generate new JWT tokens with updated active Did
|
- **Token Refresh**: Generate new JWT tokens with updated active Did
|
||||||
- **Background Task Coordination**: Stop/restart tasks with new identity context
|
- **Background Task Coordination**: Restart tasks with new identity context
|
||||||
- **Coordinate** with TimeSafari's PlatformServiceMixin for identity changes
|
- **Maintain** clear separation: Host owns identity management, plugin owns notifications
|
||||||
|
|
||||||
## Migration & Testing Strategy
|
## Migration & Testing Strategy
|
||||||
|
|
||||||
@@ -381,16 +372,16 @@ interface EnhancedDailyNotificationPlugin {
|
|||||||
3. **Phase 3**: Integrate with notification scheduling
|
3. **Phase 3**: Integrate with notification scheduling
|
||||||
4. **Phase 4**: Add passkey authentication support
|
4. **Phase 4**: Add passkey authentication support
|
||||||
|
|
||||||
### Testing Approach with Hybrid activeDid Management
|
### Testing Approach with Host-Provided activeDid Management
|
||||||
|
|
||||||
- **Unit tests** for JWT generation and HTTP clients with activeDid
|
- **Unit tests** for JWT generation and HTTP clients with activeDid
|
||||||
- **Integration tests** for API endpoint interactions using TimeSafari active_identity patterns
|
- **Integration tests** for API endpoint interactions using TimeSafari active_identity patterns
|
||||||
- **Hybrid activeDid testing**:
|
- **Host-provided activeDid testing**:
|
||||||
- Test `setActiveDidFromHost()` with TimeSafari PlatformServiceMixin
|
- Test `setActiveDidFromHost()` with TimeSafari PlatformServiceMixin
|
||||||
- Test `refreshActiveDidFromDatabase()` with background tasks
|
- Test host event dispatch and plugin event listening
|
||||||
- Test `enableAutoActiveDidMode()` for automatic synchronization
|
|
||||||
- **Critical**: Test `onActiveDidChange()` listener with identity switches
|
- **Critical**: Test `onActiveDidChange()` listener with identity switches
|
||||||
- Test cache invalidation and token refresh during activeDid changes
|
- Test cache invalidation and token refresh during activeDid changes
|
||||||
|
- Verify database isolation between host and plugin
|
||||||
- **Background testing** on real devices (doze mode, app backgrounding)
|
- **Background testing** on real devices (doze mode, app backgrounding)
|
||||||
- **Authentication testing** with actual DID credentials from TimeSafari active_identity table
|
- **Authentication testing** with actual DID credentials from TimeSafari active_identity table
|
||||||
- **Cross-platform testing** for Android/Electron (SQLite access) vs Web (host delegation) patterns
|
- **Cross-platform testing** for Android/Electron (SQLite access) vs Web (host delegation) patterns
|
||||||
@@ -494,18 +485,17 @@ GET {apiServer}/api/v2/report/offersToPlansOwnedByMe?afterId={jwtId}&beforeId={j
|
|||||||
- Create plugin configuration interfaces
|
- Create plugin configuration interfaces
|
||||||
- Set up basic error handling
|
- Set up basic error handling
|
||||||
|
|
||||||
### Phase 2: Hybrid activeDid Integration & API Access (Weeks 3-4)
|
### Phase 2: Host-Provided activeDid Integration & API Access (Weeks 3-4)
|
||||||
|
|
||||||
- Implement hybrid activeDid management (Option 3 approach)
|
- Implement host-provided activeDid management (Option A approach)
|
||||||
- Add `setActiveDidFromHost()` and `refreshActiveDidFromDatabase()` methods
|
- Add `setActiveDidFromHost()` method (no database access needed)
|
||||||
- Implement TimeSafari active_identity table access
|
- Remove database sharing complexity - host always provides activeDid
|
||||||
- Integrate API endpoint calls with activeDid-based authentication
|
- Integrate API endpoint calls with activeDid-based authentication
|
||||||
- Add response parsing and validation
|
- Add response parsing and validation
|
||||||
- Implement platform-specific database integration:
|
- Implement platform-specific database integration:
|
||||||
- **Android/Electron**: Direct @capacitor-community/sqlite integration with active_identity access
|
- **Android/Electron**: Plugin-managed @capacitor-community/sqlite (no host database access)
|
||||||
- **Web**: Plugin delegation pattern with host-provided activeDid
|
- **Web**: Host-managed storage delegation (plugin doesn't access absurd-sql directly)
|
||||||
- **iOS**: Core Data background thread integration with TimeSafari database access
|
- **iOS**: Plugin-managed Core Data (no host database access)
|
||||||
- Add `enableAutoActiveDidMode()` for automatic identity synchronization
|
|
||||||
|
|
||||||
### Phase 3: Background Integration (Weeks 5-6)
|
### Phase 3: Background Integration (Weeks 5-6)
|
||||||
|
|
||||||
@@ -550,12 +540,12 @@ GET {apiServer}/api/v2/report/offersToPlansOwnedByMe?afterId={jwtId}&beforeId={j
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Status**: Hybrid activeDid implementation plan - Ready for implementation
|
**Status**: Host-provided activeDid implementation plan (Option A) - Ready for implementation
|
||||||
**Next Steps**: Begin Phase 1 implementation with Android HTTP client setup
|
**Next Steps**: Begin Phase 1 implementation with Android HTTP client setup
|
||||||
**Dependencies**: Android Studio, Xcode, Capacitor CLI, existing plugin infrastructure, @capacitor-community/sqlite, TimeSafari active_identity table access
|
**Dependencies**: Android Studio, Xcode, Capacitor CLI, existing plugin infrastructure, @capacitor-community/sqlite
|
||||||
**Hybrid Features**:
|
**Option A Features**:
|
||||||
- **Option 3 Implementation**: Dual-mode activeDid access (host-provided + background lookup)
|
- **Simplified Architecture**: Host always provides activeDid, no database sharing
|
||||||
- **TimeSafari Integration**: PlatformServiceMixin coordination and active_identity table access
|
- **TimeSafari Integration**: PlatformServiceMixin coordination without database access
|
||||||
- **Cross-Platform**: Android/Electron SQLite access, Web host delegation, iOS Core Data hybrid
|
- **Cross-Platform**: Android/Electron plugin-managed SQLite, Web host-managed storage, iOS plugin-managed Core Data
|
||||||
- **Authentication**: DID-based JWT with activeDid from TimeSafari's identity system
|
- **Authentication**: DID-based JWT with host-provided activeDid
|
||||||
- **Background Tasks**: Automatic activeDid synchronization across app lifecycle states
|
- **Background Tasks**: Event-based activeDid changes, clear separation of concerns
|
||||||
|
|||||||
208
doc/DATABASE_ACCESS_CLARIFICATION.md
Normal file
208
doc/DATABASE_ACCESS_CLARIFICATION.md
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
# Database Access Pattern Clarification
|
||||||
|
|
||||||
|
**Author**: Matthew Raymer
|
||||||
|
**Version**: 1.0.0
|
||||||
|
**Created**: 2025-10-02 12:15:00 UTC
|
||||||
|
**Last Updated**: 2025-10-02 12:15:00 UTC
|
||||||
|
|
||||||
|
## Current Problem: Unclear Database Access Patterns
|
||||||
|
|
||||||
|
The current hybrid scheme has **conflicting** database access patterns that would be difficult to implement practically.
|
||||||
|
|
||||||
|
## Reality Check: What Actually Works
|
||||||
|
|
||||||
|
### **Option A: Host Always Provides activeDid (Recommended)**
|
||||||
|
|
||||||
|
**Implementation**: Host application **always** provides activeDid to plugin
|
||||||
|
|
||||||
|
**Android/Electron:**
|
||||||
|
```typescript
|
||||||
|
// Host queries its own database
|
||||||
|
const activeIdentity = await this.$getActiveIdentity(); // Uses host's database access
|
||||||
|
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
||||||
|
|
||||||
|
// Plugin uses its own isolated database
|
||||||
|
await plugin.configureDatabase({
|
||||||
|
platform: 'android',
|
||||||
|
storageType: 'plugin-managed', // Plugin owns its storage
|
||||||
|
encryption: false
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Web:**
|
||||||
|
```typescript
|
||||||
|
// Host queries its absurd-sql database
|
||||||
|
const activeIdentity = await this.$getActiveIdentity();
|
||||||
|
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
||||||
|
|
||||||
|
// Plugin uses host-delegated storage
|
||||||
|
await plugin.configureDatabase({
|
||||||
|
platform: 'web',
|
||||||
|
storageType: 'host-managed' // Plugin delegates to host
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**iOS:**
|
||||||
|
```typescript
|
||||||
|
// Host uses its CapacitorSQLite
|
||||||
|
const activeIdentity = await this.$getActiveIdentity();
|
||||||
|
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
||||||
|
|
||||||
|
// Plugin uses Core Data
|
||||||
|
await plugin.configureDatabase({
|
||||||
|
platform: 'ios',
|
||||||
|
storageType: 'plugin-managed' // Plugin owns Core Data
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Option B: Plugin Polls Host Database (Backup Only)**
|
||||||
|
|
||||||
|
**Implementation**: Plugin periodically checks for activeDid changes
|
||||||
|
|
||||||
|
**Android/Electron:**
|
||||||
|
```typescript
|
||||||
|
// Plugin could theoretically access host database
|
||||||
|
await plugin.configureDatabase({
|
||||||
|
platform: 'android',
|
||||||
|
storageType: 'hybrid',
|
||||||
|
hostDatabaseConnection: 'shared_connection', // Requires host coordination
|
||||||
|
pollingInterval: 30000 // Check every 30 seconds
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Issues with Option B:**
|
||||||
|
- Requires careful database connection sharing
|
||||||
|
- Potential for database locking conflicts
|
||||||
|
- Race conditions during activeDid changes
|
||||||
|
- Security concerns with plugin accessing host data
|
||||||
|
|
||||||
|
## **Recommended Implementation: Option A**
|
||||||
|
|
||||||
|
### **Why Option A Works Better:**
|
||||||
|
|
||||||
|
1. **Clear Separation**: Host owns identity management, plugin owns notification storage
|
||||||
|
2. **Security**: No shared database access between host and plugin
|
||||||
|
3. **Reliability**: Fewer moving parts, clearer failure modes
|
||||||
|
4. **Maintainability**: Easier to test and debug
|
||||||
|
|
||||||
|
### **Implementation Details:**
|
||||||
|
|
||||||
|
#### **Host Application Responsibilities:**
|
||||||
|
```typescript
|
||||||
|
class TimeSafariNotificationService {
|
||||||
|
async initialize(): Promise<void> {
|
||||||
|
// 1. Host queries its own database for activeDid
|
||||||
|
const activeIdentity = await this.$getActiveIdentity();
|
||||||
|
|
||||||
|
// 2. Host provides activeDid to plugin immediately
|
||||||
|
await this.plugin.setActiveDidFromHost(activeIdentity.activeDid);
|
||||||
|
|
||||||
|
// 3. Host sets up change listener
|
||||||
|
this.plugin.onActiveDidChange((newActiveDid) => {
|
||||||
|
this.handleActiveDidChange(newActiveDid);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Plugin configures its own independent storage
|
||||||
|
await this.plugin.configureDatabase({
|
||||||
|
platform: this.getCurrentPlatform(),
|
||||||
|
storageType: 'plugin-managed'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeSafari PlatformServiceMixin integration
|
||||||
|
async $updateActiveDid(newDid: string): Promise<void> {
|
||||||
|
// Update TimeSafari's active_identity table
|
||||||
|
await this.$dbExec(
|
||||||
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = ? WHERE id = 1",
|
||||||
|
[newDid, new Date().toISOString()]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Immediately notify plugin of change
|
||||||
|
await this.plugin.refreshActiveDidFromHost(newDid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **Plugin Responsibilities:**
|
||||||
|
```typescript
|
||||||
|
class DailyNotificationPlugin {
|
||||||
|
private currentActiveDid: string | null = null;
|
||||||
|
|
||||||
|
async setActiveDidFromHost(activeDid: string): Promise<void> {
|
||||||
|
this.currentActiveDid = activeDid;
|
||||||
|
await this.clearCacheForIdentityChange();
|
||||||
|
await this.refreshAuthenticationTokens();
|
||||||
|
}
|
||||||
|
|
||||||
|
async onActiveDidChange(callback: (newActiveDid: string) => Promise<void>): Promise<void> {
|
||||||
|
this.activeDidChangeCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async refreshActiveDidFromHost(newActiveDid: string): Promise<void> {
|
||||||
|
await this.refreshAuthenticationForNewIdentity(newActiveDid);
|
||||||
|
this.activeDidChangeCallback?.(newActiveDid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Database Isolation:**
|
||||||
|
|
||||||
|
**Plugin Storage (Independent):**
|
||||||
|
- Cached notification content
|
||||||
|
- Authentication tokens
|
||||||
|
- Background task state
|
||||||
|
- Plugin configuration
|
||||||
|
|
||||||
|
**Host Storage (TimeSafari Owns):**
|
||||||
|
- active_identity table
|
||||||
|
- User settings
|
||||||
|
- Application data
|
||||||
|
- Authentication credentials
|
||||||
|
|
||||||
|
## **Backup Pattern for Background Tasks**
|
||||||
|
|
||||||
|
For cases where plugin needs to handle activeDid changes when app is closed:
|
||||||
|
|
||||||
|
### **Token-Based Backup:**
|
||||||
|
```typescript
|
||||||
|
interface PluginConfig {
|
||||||
|
activeDid: string;
|
||||||
|
refreshToken: string; // Encrypted token that can decode new activeDid
|
||||||
|
fallbackExpiryTime: number; // When to stop using fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin can validate if activeDid hasn't expired
|
||||||
|
await plugin.validateActiveDidNotExpired(config);
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Lightweight Backup Check:**
|
||||||
|
```typescript
|
||||||
|
// Plugin could make lightweight API call to check current activeDid
|
||||||
|
async checkCurrentActiveDid(): Promise<string | null> {
|
||||||
|
try {
|
||||||
|
const response = await this.fetch('/api/internal/active-identity', {
|
||||||
|
headers: { 'Authorization': 'Bearer ' + this.backgroundToken }
|
||||||
|
});
|
||||||
|
return response.json().activeDid;
|
||||||
|
} catch (error) {
|
||||||
|
return null; // Fail safely
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## **Key Takeaway**
|
||||||
|
|
||||||
|
**The host application should ALWAYS provide activeDid to the plugin.** The plugin should never directly access TimeSafari's database unless there's a very specific architectural reason (which there isn't in this case).
|
||||||
|
|
||||||
|
This approach:
|
||||||
|
- ✅ Maintains clear separation of concerns
|
||||||
|
- ✅ Avoids database access conflicts
|
||||||
|
- ✅ Ensures reliable activeDid change detection
|
||||||
|
- ✅ Simplifies implementation and testing
|
||||||
|
- ✅ Maintains security isolation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status**: Clarification complete - Option A recommended
|
||||||
|
**Next Steps**: Update implementation plan to use host-provided activeDid only
|
||||||
|
**Impact**: Simplified architecture with clearer responsibilities
|
||||||
Reference in New Issue
Block a user