feat: implement TimeSafari integration services and improve code quality
- Add DailyNotificationService with circuit breaker and rate limiting - Add DatabaseIntegrationService with watermark management - Add TimeSafariIntegrationService with DID/VC support - Add TimeSafariCommunityIntegrationService with rate limiting - Add PlatformServiceMixin for Vue component integration - Add comprehensive TimeSafari integration example - Fix all linting issues (133 → 0 warnings) - Add .eslintignore to exclude dist/ from linting - Replace console statements with proper error handling - Replace 'any' types with 'unknown' for better type safety - Add explicit return types to all functions - Replace non-null assertions with proper null checks All tests passing (115 tests across 8 suites)
This commit is contained in:
311
src/utils/PlatformServiceMixin.ts
Normal file
311
src/utils/PlatformServiceMixin.ts
Normal file
@@ -0,0 +1,311 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/**
|
||||
* TimeSafari Platform Service Mixin
|
||||
*
|
||||
* TypeScript mixin for TimeSafari Daily Notification Plugin integration.
|
||||
* Provides type-safe service integration for Vue components and other frameworks.
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
import { DailyNotificationService, DailyNotificationServiceConfig } from '../services/DailyNotificationService';
|
||||
|
||||
/**
|
||||
* TimeSafari Daily Notification Mixin Interface
|
||||
*/
|
||||
export interface TimeSafariDailyNotificationMixin {
|
||||
// Service instance
|
||||
dailyNotificationService: DailyNotificationService;
|
||||
|
||||
// Service methods
|
||||
initializeDailyNotifications(config: DailyNotificationServiceConfig): Promise<void>;
|
||||
scheduleDailyNotification(options: {
|
||||
title: string;
|
||||
body: string;
|
||||
time: string;
|
||||
channel?: string;
|
||||
actions?: Array<{ id: string; title: string }>;
|
||||
}): Promise<void>;
|
||||
fetchCommunityData(): Promise<unknown>;
|
||||
getServiceStatus(): unknown;
|
||||
shutdownDailyNotifications(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* TimeSafari Daily Notification Mixin Implementation
|
||||
*/
|
||||
export class TimeSafariDailyNotificationMixin implements TimeSafariDailyNotificationMixin {
|
||||
// Service instance
|
||||
public dailyNotificationService: DailyNotificationService = DailyNotificationService.getInstance();
|
||||
|
||||
// Reactive state
|
||||
private _serviceInitialized = false;
|
||||
private _serviceError: string | null = null;
|
||||
private _serviceStatus: unknown = null;
|
||||
|
||||
/**
|
||||
* Initialize daily notification service
|
||||
*/
|
||||
async initializeDailyNotifications(config: DailyNotificationServiceConfig): Promise<void> {
|
||||
try {
|
||||
await this.dailyNotificationService.initialize(config);
|
||||
this._serviceInitialized = true;
|
||||
this._serviceError = null;
|
||||
this._serviceStatus = this.dailyNotificationService.getStatus();
|
||||
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
this._serviceInitialized = false;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a daily notification
|
||||
*/
|
||||
async scheduleDailyNotification(options: {
|
||||
title: string;
|
||||
body: string;
|
||||
time: string;
|
||||
channel?: string;
|
||||
actions?: Array<{ id: string; title: string }>;
|
||||
}): Promise<void> {
|
||||
if (!this._serviceInitialized) {
|
||||
throw new Error('Daily notification service not initialized');
|
||||
}
|
||||
|
||||
try {
|
||||
await this.dailyNotificationService.scheduleDailyNotification(options);
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch community data
|
||||
*/
|
||||
async fetchCommunityData(): Promise<unknown> {
|
||||
if (!this._serviceInitialized) {
|
||||
throw new Error('Daily notification service not initialized');
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await this.dailyNotificationService.fetchCommunityData();
|
||||
return data;
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service status
|
||||
*/
|
||||
getServiceStatus(): unknown {
|
||||
if (!this._serviceInitialized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this._serviceStatus = this.dailyNotificationService.getStatus();
|
||||
return this._serviceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown daily notification service
|
||||
*/
|
||||
async shutdownDailyNotifications(): Promise<void> {
|
||||
if (!this._serviceInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.dailyNotificationService.shutdown();
|
||||
this._serviceInitialized = false;
|
||||
this._serviceError = null;
|
||||
this._serviceStatus = null;
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service ready status
|
||||
*/
|
||||
isServiceReady(): boolean {
|
||||
return this._serviceInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service status
|
||||
*/
|
||||
getServiceStatusData(): unknown {
|
||||
return this._serviceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service error
|
||||
*/
|
||||
getServiceError(): string | null {
|
||||
return this._serviceError;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe decorator for components
|
||||
*/
|
||||
export function WithTimeSafariDailyNotifications<T extends Constructor>(Base: T): T {
|
||||
return class extends Base {
|
||||
public dailyNotificationService: DailyNotificationService = DailyNotificationService.getInstance();
|
||||
private _serviceInitialized = false;
|
||||
private _serviceError: string | null = null;
|
||||
private _serviceStatus: unknown = null;
|
||||
|
||||
async initializeDailyNotifications(config: DailyNotificationServiceConfig): Promise<void> {
|
||||
try {
|
||||
await this.dailyNotificationService.initialize(config);
|
||||
this._serviceInitialized = true;
|
||||
this._serviceError = null;
|
||||
this._serviceStatus = this.dailyNotificationService.getStatus();
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
this._serviceInitialized = false;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async scheduleDailyNotification(options: {
|
||||
title: string;
|
||||
body: string;
|
||||
time: string;
|
||||
channel?: string;
|
||||
actions?: Array<{ id: string; title: string }>;
|
||||
}): Promise<void> {
|
||||
if (!this._serviceInitialized) {
|
||||
throw new Error('Daily notification service not initialized');
|
||||
}
|
||||
|
||||
try {
|
||||
await this.dailyNotificationService.scheduleDailyNotification(options);
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async fetchCommunityData(): Promise<unknown> {
|
||||
if (!this._serviceInitialized) {
|
||||
throw new Error('Daily notification service not initialized');
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await this.dailyNotificationService.fetchCommunityData();
|
||||
return data;
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
getServiceStatus(): unknown {
|
||||
if (!this._serviceInitialized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this._serviceStatus = this.dailyNotificationService.getStatus();
|
||||
return this._serviceStatus;
|
||||
}
|
||||
|
||||
async shutdownDailyNotifications(): Promise<void> {
|
||||
if (!this._serviceInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.dailyNotificationService.shutdown();
|
||||
this._serviceInitialized = false;
|
||||
this._serviceError = null;
|
||||
this._serviceStatus = null;
|
||||
} catch (error) {
|
||||
this._serviceError = (error as Error).message;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
isServiceReady(): boolean {
|
||||
return this._serviceInitialized;
|
||||
}
|
||||
|
||||
getServiceStatusData(): unknown {
|
||||
return this._serviceStatus;
|
||||
}
|
||||
|
||||
getServiceError(): string | null {
|
||||
return this._serviceError;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor type for components
|
||||
* Note: any[] is required for TypeScript mixin pattern compatibility
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type Constructor<T = Record<string, unknown>> = new (...args: any[]) => T;
|
||||
|
||||
/**
|
||||
* Example component using the mixin
|
||||
*/
|
||||
export class TimeSafariDailyNotificationExample extends TimeSafariDailyNotificationMixin {
|
||||
private activeDid = 'did:example:timesafari-user-123';
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
try {
|
||||
// Initialize the service
|
||||
await this.initializeDailyNotifications({
|
||||
activeDid: this.activeDid,
|
||||
platform: 'android',
|
||||
logging: {
|
||||
level: 'info',
|
||||
enableStructuredLogging: true,
|
||||
enableEventIds: true,
|
||||
enablePerformanceMetrics: true
|
||||
}
|
||||
});
|
||||
|
||||
// Schedule a daily notification
|
||||
await this.scheduleDailyNotification({
|
||||
title: 'TimeSafari Community Update',
|
||||
body: 'New offers and project updates available',
|
||||
time: '09:00',
|
||||
channel: 'timesafari_community_updates'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to initialize daily notifications: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
async handleFetchCommunityData(): Promise<void> {
|
||||
try {
|
||||
await this.fetchCommunityData();
|
||||
// Community data fetched successfully
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to fetch community data: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
get serviceReady(): boolean {
|
||||
return this.isServiceReady();
|
||||
}
|
||||
|
||||
get serviceStatus(): unknown {
|
||||
return this.getServiceStatusData();
|
||||
}
|
||||
|
||||
get serviceError(): string | null {
|
||||
return this.getServiceError();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user