# Arquitetura Plugin Obsidian (TypeScript) que sincroniza vaults com serviços de armazenamento remoto (WebDAV, S3, Dropbox, OneDrive, etc). ## Estrutura ``` src/ código público (MIT) ├── main.ts entry point, estende Plugin do Obsidian (~2k linhas) ├── settings.ts UI de settings (~3k linhas) ├── fsAll.ts abstração FakeFs — interface comum dos backends ├── fsGetter.ts roteamento backend → instância (switch por tipo) ├── fs.ts implementações: S3, WebDAV, Dropbox, OneDrive, Webdis, Local, Encrypt ├── localdb.ts IndexedDB via LocalForage — state local ├── configPersist.ts serialização da config no disco do plugin ├── i18n.ts Mustache + moment, idiomas em src/langs/ └── ... pro/ código tier pago (PolyForm Strict License) ├── src/ │ ├── sync.ts motor de sincronização (~2k linhas, doActualSync + dispatchDecision) │ ├── fs.ts GoogleDrive, Box, pCloud, YandexDisk, Koofr, Azure, OnedriveFull │ └── ... └── tests/ tests/ testes Mocha (estrutura básica, sem cobertura do core) docs/ documentação .github/workflows/ CI ``` ## Abstração FakeFs Todo backend implementa a classe abstrata `FakeFs` (`src/fsAll.ts`): ```typescript abstract class FakeFs { walk() / walkPartial() / stat() / mkdir() / writeFile() readFile() / rename() / rm() checkConnect() / getUserDisplayName() / revokeAuth() / allowEmptyFile() } ``` `fsGetter.ts` faz o roteamento via switch — ao adicionar backend novo, registrar nele. ## Fluxo de sincronização 1. `main.ts` dispara sync (manual, auto-sync, evento de save) 2. `pro/src/sync.ts:doActualSync()` carrega árvore local + remota 3. Diff 3-way usando snapshot anterior (`prevSyncRecordsTbl` em IndexedDB) 4. `dispatchDecision()` aplica decisão por entry (copy, merge, delete, skip) 5. Conflitos: 3-way merge via `node-diff3` (apenas Markdown < 1MB, tier pro) 6. Erros agregados em `AggregateError`; falha até 3x antes de abortar ## State LocalForage (IndexedDB) com 8 tabelas em `src/localdb.ts`: - `prevSyncRecordsTbl` — snapshot da última sync - `fileContentHistoryTbl` — histórico de conteúdo (smart conflict) - `syncPlansTbl` — log das operações planejadas - `versionTbl`, `loggerOutputTbl`, `profilerResultsTbl` — metadados Config persiste via API do Obsidian em `/.obsidian/plugins/remotely-save/data.json`, com obfuscação base64 reverse (decorativa, não criptográfica). ## Pontos de atenção - **mtime no WebDAV**: padrão WebDAV não define mtime — Nextcloud expõe via header custom (`OC-LastModified`). Inconsistência pode causar falsa detecção de modificação. - **OAuth2 duplicado**: cada backend implementa fluxo próprio (~100-300 linhas duplicadas). Sem extração comum. - **Sem retry HTTP**: 429/503 quebram sync. PR upstream #1034 propõe retry para WebDAV. - **141 `: any` residuais**: concentrados em callbacks de error e payloads OAuth2.