How hesprs/obsidian-webdav-sync works
1. What this repository is
- An Obsidian plugin that performs bidirectional sync between a user’s local vault and a remote WebDAV server.
- The architecture is centered on keeping three views of state in sync: current local files, current remote files, and the last recorded sync state.
2. Plugin boundary and host environment
- The code runs inside Obsidian, not as a standalone server or web app.
- The main entrypoint in src/index.ts wires the plugin into Obsidian’s lifecycle, settings system, commands, UI surfaces, and sync triggers.
3. Primary data flow
- Local vault content is scanned through a filesystem abstraction.
- Remote content is traversed through a WebDAV adapter.
- A sync record store tracks prior state, enabling incremental and conflict-aware decisions instead of blind mirroring.
4. Sync orchestration layer
- src/events defines the sync trigger surface, including manual sync, scheduled sync, and termination.
- src/services/sync-scheduler.service.ts and src/utils/launch-manual-sync.ts feed those triggers into the central sync execution path.
- src/services/sync-executor.service.ts is the orchestration hub that coordinates traversal, decision-making, task creation, and execution.
5. Decision engine
- The decision subsystem in src/sync/decision performs the core three-way comparison.
- It reconciles local state, remote state, and the recorded last-sync state to determine whether each path should be pushed, pulled, merged, created, or removed.
- Conflict policies such as smart merge, latest-survive, use remote, use local, and skip are applied here.
6. Task-based execution model
- The sync engine produces explicit tasks in src/sync/tasks rather than directly mutating files.
- Tasks cover file creation, directory creation, deletion, recursive cleanup, push/pull transfers, merge handling, and sync-record maintenance.
- Utility code in src/sync/utils optimizes, orders, merges, and chunks tasks to control concurrency and prevent pathological large-batch behavior.
7. Local and remote filesystem adapters
- src/fs/vault adapts Obsidian’s local vault filesystem into traversal and utility operations.
- src/fs/webdav adapts the remote WebDAV server, including API access, traversal, and remote-path utilities.
- src/fs/post-traversal.ts suggests a normalization step after walking either side before the sync engine consumes the results.
8. Persistence and incremental state
- src/storage holds durable local state for sync records and large-file chunk metadata.
- The record store is what makes “current vs. previous sync” comparisons possible across sessions.
- The chunk store supports resumable or staged transfer of large files, which is important for stability and memory control.
9. Encryption boundary
- Client-side encryption is built into the sync pipeline, not treated as a separate service.
- src/composable/encryption.ts, src/utils/encryption.ts, and src/platform/crypto.ts indicate a layered design: reusable encryption logic plus platform-specific crypto support.
- The remote side sees encrypted payloads and metadata sufficient to detect unintended remote modification or movement.
10. Rate limiting, batching, and resilience
- src/composable/api-limiter.ts and the WebDAV service layer manage request pacing and concurrency to avoid provider rate limits.
- Large-file and high-file-count cases are handled with chunking, task optimization, and retryable-error checks.
- This is a performance-sensitive architecture: network I/O, task concurrency, and memory usage are all controlled explicitly.
11. User interface and observability
- UI is composed of modals in src/components for confirmation, filters, remote directory selection, sync progress, and encryption reminders.
- The explorer and file-tree components provide a structured, selective sync view of pending changes.
- src/services/observability.service.ts and helpers in src/utils/logger.ts support status, notices, and log output for troubleshooting.
12. Configuration and extensibility
- Settings are organized under src/settings into account, common, filter, development, and plugin-instance concerns.
- The repository also includes i18n under src/i18n, so the user-facing surface is locale-aware rather than hardcoded in one language.
- src/webdav-patch.ts and src/platform/* show that some behavior is abstracted for environment-specific compatibility.
13. External boundaries
- The only major external dependencies in the runtime architecture are Obsidian itself, the user’s local vault filesystem, and the remote WebDAV server.
- Credentials are integrated with Obsidian’s keychain flow, so authentication is managed through the host app rather than a custom backend.
- There is no separate application server; the plugin is a client-only sync engine embedded in Obsidian.
Main entry points: sync-executor.service.ts Sync executor · sync/index.ts Sync core · src/index.ts Plugin entry · events/index.ts Sync events
Components 22
Plugin entry
Obsidian plugin lifecycle, commands, and sync triggers.
- Plugin entry · Wires settings, commands, UI surfaces, and sync lifecycle into Obsidian.
src/index.ts - Sync events · Defines manual sync, scheduled sync, and termination events.
src/events/index.ts - Scheduler · Runs periodic sync initiation and timing control.
src/services/sync-scheduler.service.ts - Manual launch · Starts a user-requested sync from commands or UI.
src/utils/launch-manual-sync.ts
Sync engine
Three-way comparison, task generation, and execution.
- Sync executor · Coordinates traversal, decisions, task creation, and task execution.
src/services/sync-executor.service.ts - Sync core · Shared sync flow and error handling around decision and task phases.
src/sync/index.ts - Decider · Compares local, remote, and last-sync state to decide actions.
src/sync/decision/two-way.decider.ts - Decide fn · Implements the decision logic used by the sync engine.
src/sync/decision/two-way.decider.function.ts - Tasks · Encodes file create, delete, push, pull, merge, and record updates.
src/sync/tasks/task.interface.ts - Task utils · Orders, merges, chunks, and limits task batches for safe execution.
src/sync/utils/optimize-tasks.ts
Filesystem adapters
Local vault and remote WebDAV traversal abstractions.
- Vault FS · Adapts Obsidian vault traversal and local file operations.
src/fs/vault/index.ts - WebDAV FS · Adapts remote WebDAV traversal, API access, and remote path handling.
src/fs/webdav/index.ts - Post traversal · Normalizes walked file state before the sync engine consumes it.
src/fs/post-traversal.ts
Persistent state
Durable sync records and transfer metadata.
- Record store · Persists prior sync state for incremental and conflict-aware comparison.
src/storage/sync-record.store.ts - Chunk store · Persists large-file chunk metadata for staged or resumable transfers.
src/storage/file-chunk.store.ts
UI and settings
User-facing modals, explorer views, and configuration.
- Settings · Bundles account, filter, common, development, and plugin-instance settings.
src/settings/index.ts - Modals · Confirmation, selection, progress, and reminder dialogs for sync workflows.
src/components/SyncProgressModal.ts - Explorer · Structured view of pending local and remote changes for selective sync.
src/components/explorer/index.tsx
Shared infrastructure
Encryption, rate limiting, platform, and logging support.
- Observability · Provides notices, status updates, and troubleshooting logs.
src/services/observability.service.ts - Encryption · Shared encryption logic plus platform crypto support for client-side encrypted sync.
src/composable/encryption.ts - API limiter · Paces remote requests and controls concurrency to avoid WebDAV limits.
src/composable/api-limiter.ts - Platform crypto · Host-specific cryptographic primitives and compatibility helpers.
src/platform/crypto.ts
Connections 24
- Plugin entry → Sync events: registers · Plugin startup wires sync triggers into Obsidian lifecycle.
- Plugin entry → Settings: loads · Plugin entry initializes user settings and configuration.
- Plugin entry → Modals: opens · Entry point connects commands and actions to modal UI.
- Plugin entry → Explorer: mounts · Entry point exposes the file-tree explorer surface.
- Sync events → Scheduler: schedules · Event surface feeds scheduled sync execution.
- Sync events → Manual launch: launches · Event surface includes manual sync initiation.
- Manual launch → Sync executor: starts · Manual sync hands control to the execution hub.
- Scheduler → Sync executor: starts · Scheduled sync hands control to the execution hub.
- Sync executor → Vault FS: scans · Executor traverses the local vault state.
- Sync executor → WebDAV FS: scans · Executor traverses the remote WebDAV state.
- Vault FS → Post traversal: normalizes · Local traversal results are normalized before comparison.
- WebDAV FS → Post traversal: normalizes · Remote traversal results are normalized before comparison.
- Sync executor → Record store: reads/writes · Executor consults and updates recorded sync state.
- Sync executor → Sync core: orchestrates · Executor delegates core sync flow to the sync pipeline.
- Sync core → Decider: compares · Core sync uses the decider for three-way reconciliation.
- Decider → Decide fn: implements · Decision object wraps the rules function.
- Sync core → Tasks: produces · Sync flow emits explicit execution tasks.
- Sync core → Task utils: optimizes · Task utilities batch and reorder tasks before execution.
- Task utils → Tasks: reorders · Optimization operates on the task model.
- Tasks → Chunk store: uses · Transfer tasks coordinate with chunk persistence for large files.
- Sync core → Encryption: applies · Encryption is embedded in the sync pipeline.
- Encryption → Platform crypto: delegates · Reusable encryption logic relies on platform crypto support.
- WebDAV FS → API limiter: throttles · Remote adapter controls request pacing and concurrency.
- Sync executor → Observability: reports · Execution path emits notices, status, and logs.