chore: removed sync engine since we go for filesystem based syncing

This commit is contained in:
2026-02-14 18:15:28 +01:00
parent daac97824d
commit 34eb0d3781
17 changed files with 766 additions and 838 deletions

View File

@@ -30,8 +30,6 @@ export const posts = sqliteTable('posts', {
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
publishedAt: integer('published_at', { mode: 'timestamp' }),
filePath: text('file_path').notNull().default(''), // Empty for never-published drafts
syncStatus: text('sync_status', { enum: ['pending', 'synced', 'conflict'] }).notNull().default('pending'),
syncedAt: integer('synced_at', { mode: 'timestamp' }),
checksum: text('checksum'),
tags: text('tags'), // JSON array stored as text
categories: text('categories'), // JSON array stored as text
@@ -62,24 +60,10 @@ export const media = sqliteTable('media', {
sidecarPath: text('sidecar_path').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
syncStatus: text('sync_status', { enum: ['pending', 'synced', 'conflict'] }).notNull().default('pending'),
syncedAt: integer('synced_at', { mode: 'timestamp' }),
checksum: text('checksum'),
tags: text('tags'), // JSON array stored as text
});
// Sync log - tracks sync operations
export const syncLog = sqliteTable('sync_log', {
id: text('id').primaryKey(),
entityType: text('entity_type', { enum: ['post', 'media'] }).notNull(),
entityId: text('entity_id').notNull(),
operation: text('operation', { enum: ['create', 'update', 'delete'] }).notNull(),
status: text('status', { enum: ['pending', 'completed', 'failed'] }).notNull().default('pending'),
timestamp: integer('timestamp', { mode: 'timestamp' }).notNull(),
errorMessage: text('error_message'),
retryCount: integer('retry_count').notNull().default(0),
});
// App settings - stores application configuration
export const settings = sqliteTable('settings', {
key: text('key').primaryKey(),
@@ -162,8 +146,6 @@ export type Post = typeof posts.$inferSelect;
export type NewPost = typeof posts.$inferInsert;
export type Media = typeof media.$inferSelect;
export type NewMedia = typeof media.$inferInsert;
export type SyncLogEntry = typeof syncLog.$inferSelect;
export type NewSyncLogEntry = typeof syncLog.$inferInsert;
export type Setting = typeof settings.$inferSelect;
export type NewSetting = typeof settings.$inferInsert;
export type PostLink = typeof postLinks.$inferSelect;

View File

@@ -520,7 +520,6 @@ export class MediaEngine extends EventEmitter {
sidecarPath,
createdAt: mediaData.createdAt,
updatedAt: mediaData.updatedAt,
syncStatus: 'pending',
checksum,
tags: JSON.stringify(mediaData.tags),
};
@@ -566,7 +565,6 @@ export class MediaEngine extends EventEmitter {
alt: updated.alt,
caption: updated.caption,
updatedAt: updated.updatedAt,
syncStatus: 'pending',
tags: JSON.stringify(updated.tags),
})
.where(eq(media.id, id));
@@ -933,7 +931,6 @@ export class MediaEngine extends EventEmitter {
sidecarPath,
createdAt: new Date(metadata.createdAt),
updatedAt: new Date(metadata.updatedAt),
syncStatus: 'pending',
checksum,
tags: JSON.stringify(metadata.tags),
});

View File

@@ -328,7 +328,6 @@ export class PostEngine extends EventEmitter {
updatedAt: post.updatedAt,
publishedAt: post.publishedAt,
filePath: '',
syncStatus: 'pending',
checksum,
tags: JSON.stringify(post.tags),
categories: JSON.stringify(post.categories),
@@ -404,7 +403,6 @@ export class PostEngine extends EventEmitter {
author: updated.author,
updatedAt: updated.updatedAt,
publishedAt: updated.publishedAt,
syncStatus: 'pending',
checksum,
tags: JSON.stringify(updated.tags),
categories: JSON.stringify(updated.categories),
@@ -851,7 +849,6 @@ export class PostEngine extends EventEmitter {
updatedAt: published.updatedAt,
publishedAt: published.publishedAt,
filePath: newFilePath,
syncStatus: 'pending',
checksum,
tags: JSON.stringify(published.tags),
categories: JSON.stringify(published.categories),
@@ -1105,7 +1102,6 @@ export class PostEngine extends EventEmitter {
updatedAt: postData.updatedAt,
publishedAt: postData.publishedAt || postData.updatedAt,
filePath,
syncStatus: 'pending',
checksum,
tags: JSON.stringify(postData.tags),
categories: JSON.stringify(postData.categories),

View File

@@ -1,168 +0,0 @@
import { EventEmitter } from 'events';
import { v4 as uuidv4 } from 'uuid';
import { eq } from 'drizzle-orm';
import { getDatabase } from '../database';
import { syncLog, posts, media, NewSyncLogEntry } from '../database/schema';
export type SyncDirection = 'push' | 'pull' | 'bidirectional';
export type SyncStatus = 'idle' | 'syncing' | 'error';
export interface SyncConfig {
autoSync: boolean;
syncInterval: number; // in minutes
}
export interface SyncResult {
success: boolean;
pushed: number;
pulled: number;
conflicts: number;
errors: string[];
}
export class SyncEngine extends EventEmitter {
private syncStatus: SyncStatus = 'idle';
private syncConfig: SyncConfig | null = null;
private syncIntervalId: NodeJS.Timeout | null = null;
constructor() {
super();
}
getSyncStatus(): SyncStatus {
return this.syncStatus;
}
/**
* Check if sync is configured.
* Currently returns false as cloud sync is not implemented.
*/
isConfigured(): boolean {
return false;
}
async configure(config: SyncConfig): Promise<void> {
this.syncConfig = config;
// Stop existing auto-sync
if (this.syncIntervalId) {
clearInterval(this.syncIntervalId);
this.syncIntervalId = null;
}
// Auto-sync is disabled as cloud sync is not implemented
this.emit('configured', config);
}
private async logSyncOperation(
entityId: string,
entityType: 'post' | 'media',
operation: 'create' | 'update' | 'delete',
status: 'pending' | 'completed' | 'failed',
errorMessage?: string
): Promise<void> {
const db = getDatabase().getLocal();
const logEntry: NewSyncLogEntry = {
id: uuidv4(),
entityType,
entityId,
operation,
status,
timestamp: new Date(),
errorMessage,
retryCount: 0,
};
await db.insert(syncLog).values(logEntry);
}
async getPendingChangesCount(): Promise<{ posts: number; media: number }> {
const db = getDatabase().getLocal();
const pendingPosts = await db
.select()
.from(posts)
.where(eq(posts.syncStatus, 'pending'))
.all();
const pendingMedia = await db
.select()
.from(media)
.where(eq(media.syncStatus, 'pending'))
.all();
return {
posts: pendingPosts.length,
media: pendingMedia.length,
};
}
async getSyncLog(limit = 50): Promise<Array<{
id: string;
entityType: string;
entityId: string;
operation: string;
status: string;
timestamp: Date;
errorMessage?: string;
}>> {
const db = getDatabase().getLocal();
const logs = await db
.select()
.from(syncLog)
.orderBy(syncLog.timestamp)
.limit(limit)
.all();
return logs.map(log => ({
id: log.id,
entityType: log.entityType,
entityId: log.entityId,
operation: log.operation,
status: log.status,
timestamp: log.timestamp,
errorMessage: log.errorMessage || undefined,
}));
}
stopAutoSync(): void {
if (this.syncIntervalId) {
clearInterval(this.syncIntervalId);
this.syncIntervalId = null;
}
this.emit('autoSyncStopped');
}
/**
* Sync alias for fullSync for backward compatibility
*/
async sync(direction: SyncDirection = 'bidirectional'): Promise<SyncResult> {
return this.fullSync(direction);
}
/**
* Full sync is not currently implemented.
* Returns a result indicating sync is not configured.
*/
async fullSync(_direction: SyncDirection = 'bidirectional'): Promise<SyncResult> {
return {
success: false,
pushed: 0,
pulled: 0,
conflicts: 0,
errors: ['Cloud sync not configured'],
};
}
}
// Singleton instance
let syncEngine: SyncEngine | null = null;
export function getSyncEngine(): SyncEngine {
if (!syncEngine) {
syncEngine = new SyncEngine();
}
return syncEngine;
}

View File

@@ -2,7 +2,6 @@ export { TaskManager, taskManager, type Task, type TaskProgress, type TaskStatus
export { PostEngine, getPostEngine, type PostData, type PostFilter, type SearchResult, type PaginatedResult, type PaginationOptions } from './PostEngine';
export { MediaEngine, getMediaEngine, type MediaData } from './MediaEngine';
export { PostMediaEngine, getPostMediaEngine, postMediaEngine, type PostMediaLinkData } from './PostMediaEngine';
export { SyncEngine, getSyncEngine, type SyncConfig, type SyncResult, type SyncDirection, type SyncStatus } from './SyncEngine';
export { ProjectEngine, getProjectEngine, type ProjectData } from './ProjectEngine';
export { MetaEngine, getMetaEngine, type ProjectMetadata, DEFAULT_CATEGORIES } from './MetaEngine';
export {

View File

@@ -4,7 +4,6 @@ import * as fsPromises from 'fs/promises';
import { eq } from 'drizzle-orm';
import { getPostEngine, PostData, PostFilter, PaginationOptions } from '../engine/PostEngine';
import { getMediaEngine, MediaData } from '../engine/MediaEngine';
import { getSyncEngine, SyncConfig, SyncDirection } from '../engine/SyncEngine';
import { getProjectEngine, ProjectData } from '../engine/ProjectEngine';
import { getMetaEngine } from '../engine/MetaEngine';
import { getTagEngine } from '../engine/TagEngine';
@@ -432,43 +431,6 @@ export function registerIpcHandlers(): void {
return engine.regenerateMissingThumbnails();
});
// ============ Sync Handlers ============
safeHandle('sync:configure', async (_, config: SyncConfig) => {
const engine = getSyncEngine();
return engine.configure(config);
});
safeHandle('sync:start', async (_, direction: SyncDirection = 'bidirectional') => {
const engine = getSyncEngine();
return engine.fullSync(direction);
});
safeHandle('sync:getStatus', async () => {
const engine = getSyncEngine();
return engine.getSyncStatus();
});
safeHandle('sync:isConfigured', async () => {
const engine = getSyncEngine();
return engine.isConfigured();
});
safeHandle('sync:getPendingCount', async () => {
const engine = getSyncEngine();
return engine.getPendingChangesCount();
});
safeHandle('sync:getLog', async (_, limit?: number) => {
const engine = getSyncEngine();
return engine.getSyncLog(limit);
});
safeHandle('sync:stopAutoSync', async () => {
const engine = getSyncEngine();
return engine.stopAutoSync();
});
// ============ Task Handlers ============
safeHandle('tasks:getAll', async () => {
@@ -880,7 +842,6 @@ export function registerIpcHandlers(): void {
// Forward engine events to renderer
const postEngine = getPostEngine();
const mediaEngine = getMediaEngine();
const syncEngine = getSyncEngine();
const projectEngine = getProjectEngine();
const metaEngine = getMetaEngine();
const tagEngine = getTagEngine();
@@ -926,10 +887,6 @@ export function registerIpcHandlers(): void {
postMediaEngine.on('mediaReordered', forwardEvent('postMedia:reordered'));
postMediaEngine.on('rebuilt', forwardEvent('postMedia:rebuilt'));
syncEngine.on('syncStarted', forwardEvent('sync:started'));
syncEngine.on('syncCompleted', forwardEvent('sync:completed'));
syncEngine.on('syncFailed', forwardEvent('sync:failed'));
taskManager.on('taskCreated', forwardEvent('task:created'));
taskManager.on('taskStarted', forwardEvent('task:started'));
taskManager.on('taskProgress', forwardEvent('task:progress'));

View File

@@ -255,43 +255,6 @@ function createApplicationMenu(): Menu {
},
],
},
{
label: 'Sync',
submenu: [
{
label: 'Sync Now',
accelerator: 'CmdOrCtrl+Shift+S',
click: () => {
mainWindow?.webContents.send('menu:syncNow');
},
},
{
label: 'Push Changes',
click: () => {
mainWindow?.webContents.send('menu:pushChanges');
},
},
{
label: 'Pull Changes',
click: () => {
mainWindow?.webContents.send('menu:pullChanges');
},
},
{ type: 'separator' },
{
label: 'Configure Sync...',
click: () => {
mainWindow?.webContents.send('menu:configureSync');
},
},
{
label: 'View Sync Log',
click: () => {
mainWindow?.webContents.send('menu:viewSyncLog');
},
},
],
},
{
label: 'Help',
submenu: [

View File

@@ -78,17 +78,6 @@ contextBridge.exposeInMainWorld('electronAPI', {
rebuild: () => ipcRenderer.invoke('postMedia:rebuild'),
},
// Sync
sync: {
configure: (config: unknown) => ipcRenderer.invoke('sync:configure', config),
start: (direction?: string) => ipcRenderer.invoke('sync:start', direction),
getStatus: () => ipcRenderer.invoke('sync:getStatus'),
isConfigured: () => ipcRenderer.invoke('sync:isConfigured'),
getPendingCount: () => ipcRenderer.invoke('sync:getPendingCount'),
getLog: (limit?: number) => ipcRenderer.invoke('sync:getLog', limit),
stopAutoSync: () => ipcRenderer.invoke('sync:stopAutoSync'),
},
// Tasks
tasks: {
getAll: () => ipcRenderer.invoke('tasks:getAll'),
@@ -273,15 +262,6 @@ export interface ElectronAPI {
getAll: () => Promise<unknown[]>;
rebuildFromFiles: () => Promise<void>;
};
sync: {
configure: (config: unknown) => Promise<void>;
start: (direction?: string) => Promise<unknown>;
getStatus: () => Promise<string>;
isConfigured: () => Promise<boolean>;
getPendingCount: () => Promise<{ posts: number; media: number }>;
getLog: (limit?: number) => Promise<unknown[]>;
stopAutoSync: () => Promise<void>;
};
dropbox: {
configure: (config: unknown) => Promise<void>;
isConfigured: () => Promise<boolean>;