Sync System
Page reflects current state — file-sync subsystem removed
This page was previously documented a manifest-based file-sync subsystem (@takazudo/sync-client). That subsystem has been removed. The page now reflects the current cloud-only architecture. For the full technical detail — WebSocket protocol, E2E encryption, conflict resolution, offline queue — see Sync Architecture.
Overview
The active sync system uses @takazudo/cloud-sync for real-time push/pull with E2E encryption, Better Auth for identity, and @takazudo/cloud-crypto for key derivation. Under the cloud-primary model this workspace is the storage layer, not an opt-in mirror of local files.
Settings (enabled) → SyncContext → getBackend().cloudSync → Cloud Sync Server
↑ ↓
Auth check triggerSync()
↓
Status UI (cloudStatus)Sync requires a Pro subscription (30-day free trial). The app works fully offline — sync is opt-in.
SyncContext Provider
The SyncProvider (renderer/) wraps the app and provides sync state to all components via useSyncContext().
State
| Field | Type | Description |
|---|---|---|
cloudStatus | CloudSyncStatusInfo | Current cloud sync status |
isConfigured | boolean | Live workspace binding: authenticated + a bound workspace id + encryption armed |
isAuthenticated | boolean | Whether the user is signed in |
authState | AuthState | User info (name, email) |
isSyncing | boolean | Whether a sync is in progress |
syncLog | SyncLogEntry[] | Recent sync history (max 10) |
canSync | boolean | Subscription grants access AND isConfigured |
syncNow Flow
Guard: exit early if
!canSyncor already syncingSet
isSyncing = trueCall
getBackend().cloudSync.triggerSync()— push + pull via the cloud bridgeUpdate
cloudStatusfrom the resultAppend a
SyncLogEntry(success or error)Finally: set
isSyncing = false
Configuration Derivation
Desktop and browser share one definition — bridge truth: isAuthenticated && getWorkspaceId() !== "" && isEncryptionReady(). Settings play no part. The desktop-only sync.enabled opt-in was deleted in #4515: post cloud-primary it gated UI discoverability while sync traffic flowed regardless, so an armed workspace binding is the whole answer to "is sync live on this device".
SyncSettings Fields
Defined in packages/:
interface SyncSettings {
cloudDeviceId: string;
cloudDeviceName: string;
cloudRealtimeEnabled: boolean;
}Workspace identity, encryption readiness, and the sync-server URL are runtime binding/auth state rather than persisted settings.
Authentication
Auth state is managed through the BackendAPI.auth domain:
interface BackendAPI {
auth: {
getState: () => Promise<AuthState>;
login: () => Promise<void>;
logout: () => Promise<void>;
onStateChanged: (callback: (state: AuthState) => void) => () => void;
};
}SyncContext subscribes to auth.onStateChanged on mount and keeps authState in sync. The canSync flag gates all sync operations.
The Better Auth authority is supplied at build time as VITE_BETTER_AUTH_URL; it is intentionally absent from SyncSettings. See Better Auth for session refresh and service-JWT minting.
Sync Log
SyncContext maintains an in-memory log of recent sync operations (capped at 10 entries, newest first):
interface SyncLogEntry {
timestamp: string;
status: "synced" | "error";
filesUploaded: number;
filesDownloaded: number;
conflictsCount: number;
error?: string;
}Mock Adapter
In dev:mock mode, the mock adapter simulates sync and auth behavior:
cloudSync.triggerSync()— sets status to"syncing", then resolves with a mock resultauth.login()— waits 500ms, then setsisAuthenticated: truewith a mock userauth.logout()— immediately resets to the default unauthenticated state
For the full architecture — WebSocket real-time sync, E2E encryption, conflict resolution, and offline queue — see Sync Architecture.