mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
* feat(sync-core): drop shared-schema vector-clock compat re-export and app enum - Remove the shared-schema → sync-core compatibility re-export of vector-clock types/functions; retarget app files (vector-clock.ts,operation-log.const.ts) and the server (sync.types.ts) to import from @sp/sync-core directly - Add @sp/sync-core to super-sync-server/package.json deps (it was load-bearing through the re-export) - Convert VectorClockComparison from a bare type to an as const object + derived type in sync-core,drop the app-side enum copy and the as cast - Update spec imports and pa ckage-boundaries.md * docs: remove stale shared-schema vector-clock references - Update comments in vector-clocks.md, client vector-clock.ts, and server sync.types.ts to reference @sp/sync-core directly - Remove @sp/sync-core dependency from shared-schema/package.json - Regenerate package-lock.json to reflect the removed edge * docs(sync): fix orphaned VectorClockComparison comment The comment block describing VectorClockComparison was left dangling above no declaration after the app-side enum was removed, and still claimed 'Uses enum for client-side ergonomics'. Move it above the re-export it documents and correct the wording. --------- Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
163 lines
6.8 KiB
Markdown
163 lines
6.8 KiB
Markdown
# Sync Package Boundaries
|
|
|
|
**Status:** Active
|
|
**Last Updated:** May 13, 2026
|
|
|
|
This note documents the package split used by the operation-log sync stack. The
|
|
goal is to keep reusable sync logic framework-agnostic while leaving Super
|
|
Productivity domain wiring in the app.
|
|
|
|
## Dependency Direction
|
|
|
|
Allowed direction:
|
|
|
|
```text
|
|
src/app
|
|
-> @sp/sync-providers
|
|
-> @sp/sync-core
|
|
|
|
src/app
|
|
-> @sp/sync-core
|
|
|
|
packages/super-sync-server
|
|
-> @sp/sync-core
|
|
-> @sp/shared-schema
|
|
```
|
|
|
|
Rules:
|
|
|
|
- `@sp/sync-core` must not import Angular, NgRx, `src/app`, `@sp/shared-schema`,
|
|
`@sp/sync-providers`, or provider-specific code.
|
|
- `@sp/sync-providers` may import only public `@sp/sync-core` exports. It must
|
|
not deep-import `@sp/sync-core/*`, Angular, NgRx, `src/app`, or
|
|
`@sp/shared-schema`.
|
|
- The app may import both packages and is responsible for Angular dependency
|
|
injection, NgRx, Electron/Capacitor bridges, config UI, OAuth routing, and
|
|
Super Productivity-specific model wiring.
|
|
- `packages/shared-schema` owns schema contracts and validators shared between
|
|
app and server. It has no dependency on `@sp/sync-core`.
|
|
- `packages/super-sync-server` depends on both `@sp/shared-schema` (HTTP contract
|
|
types and validation schemas) and `@sp/sync-core` (vector-clock algorithms).
|
|
|
|
## Ownership
|
|
|
|
`@sp/sync-core` owns reusable sync-engine primitives:
|
|
|
|
- generic operation and apply types;
|
|
- vector-clock compare, merge, and prune algorithms;
|
|
- pure conflict, import-filter, upload/download, replay, compression, and
|
|
prefix helpers;
|
|
- structural entity-registry contracts;
|
|
- app-facing port contracts and the privacy-aware `SyncLogger` interface.
|
|
|
|
`@sp/sync-providers` owns bundled provider implementations and provider-neutral
|
|
contracts:
|
|
|
|
- Dropbox, WebDAV, Nextcloud, SuperSync, and LocalFile provider classes;
|
|
- file-based sync envelope types and provider response contracts;
|
|
- provider-owned file envelope constants such as `sync-data.json` and
|
|
file-sync version keys;
|
|
- credential, file-adapter, platform-info, web-fetch, native-HTTP, storage, and
|
|
response-validator ports;
|
|
- provider-shared error classes, PKCE helpers, retry helpers, and safe logging
|
|
metadata helpers.
|
|
|
|
Cross-provider utilities belong in `@sp/sync-providers` when they are reusable
|
|
by provider implementations but not by the generic engine. Existing examples are
|
|
provider-shared error classes, PKCE, retry predicates, native-HTTP retry, and
|
|
safe log-metadata helpers.
|
|
|
|
New bundled providers should follow the Dropbox/WebDAV/SuperSync/LocalFile
|
|
pattern: put provider-owned protocol logic and provider-neutral contracts in
|
|
`@sp/sync-providers`, then compose app-only credentials, platform bridges,
|
|
validators, OAuth routing, and UI config in thin app-side factories. If a
|
|
provider is app-specific or plugin-provided rather than bundled, implement it
|
|
app-side against the provider contracts instead of widening the package surface.
|
|
|
|
`src/app` owns host-specific configuration and choreography:
|
|
|
|
- `ActionType`, `ENTITY_TYPES`, `SyncProviderId`, provider lists, and storage
|
|
prefixes such as `REMOTE_FILE_CONTENT_PREFIX` and `PRIVATE_CFG_PREFIX`;
|
|
- entity registry construction from feature reducers/selectors;
|
|
- wrapped full-state payload shape, import reasons, repair payloads, and
|
|
validation against `@sp/shared-schema`;
|
|
- Angular services, NgRx dispatch/replay conversion, local-action filtering,
|
|
hydration windows, archive side effects, provider factories, OAuth callbacks,
|
|
config dialogs, and platform bridge implementations.
|
|
|
|
`packages/shared-schema` owns Super Productivity schema contracts and validators
|
|
that are shared between app and server. In this boundary it should stay
|
|
SP-coupled and should not become a dependency of `@sp/sync-core` or
|
|
`@sp/sync-providers`.
|
|
|
|
## Public Exports
|
|
|
|
Package consumers should import from package barrels only:
|
|
|
|
```ts
|
|
import { compareVectorClocks } from '@sp/sync-core';
|
|
import { Dropbox, PROVIDER_ID_DROPBOX } from '@sp/sync-providers/dropbox';
|
|
```
|
|
|
|
Do not import from package internals such as `@sp/sync-core/src/*`,
|
|
`@sp/sync-providers/src/*`, or `dist/*`. If a host needs a symbol, promote it to
|
|
the package barrel deliberately and check that it is not app-owned.
|
|
|
|
The root `@sp/sync-providers` barrel has been removed; consumers MUST import
|
|
from focused subpath barrels: `@sp/sync-providers/dropbox`, `/webdav`,
|
|
`/super-sync`, `/local-file`, `/http`, `/errors`, `/file-based`, `/pkce`,
|
|
`/platform`, `/provider-types`, `/credential-store`, and `/log`. Provider
|
|
classes, provider-owned string constants, and shared privacy-boundary logging
|
|
helpers are exported there, but app enums such as `SyncProviderId` are not.
|
|
Internal helpers such as WebDAV API/adapter classes stay unexported unless a
|
|
second host needs them.
|
|
|
|
`@sp/sync-core` still exports deprecated full-state op compatibility defaults
|
|
and host-defined `OpType.SyncImport` / `BackupImport` / `Repair` strings for
|
|
existing consumers. New reusable hosts should provide their own full-state
|
|
operation strings through `createFullStateOpTypeHelpers()`.
|
|
|
|
## Privacy Boundary
|
|
|
|
Package logging must use `SyncLogger` and safe structured metadata only.
|
|
`SyncLogger` is a privacy-aware port shape; it does not sanitize arbitrary
|
|
metadata. Call sites are responsible for passing already-scrubbed values, and
|
|
enforcement is currently code review plus focused tests.
|
|
|
|
IDs, counts, action strings, entity types, provider IDs, and error names/codes
|
|
are acceptable. URL metadata is acceptable only after the caller strips query
|
|
strings, fragments, credentials, tokens, raw response bodies, and user-provided
|
|
path segments such as file names, emails, share IDs, or folder names. Prefer
|
|
coarse path templates, provider operation names, host-only values, or a
|
|
provider-owned relative path category over raw URL paths.
|
|
|
|
Full entities, operation payloads, task titles, note text, raw provider
|
|
responses, credentials, headers, and encryption material must stay out of
|
|
exportable logs. A lint rule for unsafe direct logging remains a possible
|
|
follow-up; until then, new movable/provider code should use `SyncLogger` and
|
|
tests should assert privacy-sensitive catch paths.
|
|
|
|
## Tests
|
|
|
|
The ESLint package-boundary overrides apply to all TypeScript files under
|
|
`packages/sync-core/**` and `packages/sync-providers/**`, including tests. Tests
|
|
may import their own package internals through relative paths for white-box
|
|
coverage. `@sp/sync-providers` tests may import public `@sp/sync-core` exports,
|
|
but should not import `@sp/sync-core` internals or sync-core test helpers.
|
|
|
|
## Verification
|
|
|
|
Before moving code across these boundaries, run:
|
|
|
|
```bash
|
|
npm run lint
|
|
npm run sync-core:build
|
|
npm run sync-providers:build
|
|
npm run packages:test
|
|
```
|
|
|
|
For a quick boundary spot-check, use:
|
|
|
|
```bash
|
|
rg -n "from ['\"](@angular|@ngrx|@sp/shared-schema|src/app|@sp/sync-core/src|@sp/sync-core/)|import\(['\"](@angular|@ngrx|@sp/shared-schema|src/app|@sp/sync-core/src|@sp/sync-core/)" packages/sync-core/src packages/sync-providers/src
|
|
```
|