@terreno/mcp 0.31.0 → 56.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +8 -9
- package/dist/bootstrap.js.map +1 -1
- package/dist/docs/templates/bootstrap/frontend/app/_layout.template.tsx +1 -1
- package/dist/docs/upgrades/56.0.0-beta.2.md +59 -0
- package/dist/docs/versioned/next/README.md +2 -0
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +21 -0
- package/dist/docs/versioned/next/how-to/README.md +2 -0
- package/dist/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +445 -0
- package/dist/docs/versioned/next/implementationPlans/PLAN_INDEX.md +28 -50
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +3 -2
- package/dist/docs/versioned/next/implementationPlans/comms-abstraction.md +98 -15
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +63 -13
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +65 -12
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +9 -3
- package/dist/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
- package/dist/docs/versioned/next/implementationPlans/rtk-to-syncdb-migration-docs.md +52 -47
- package/dist/docs/versioned/next/implementationPlans/syncdb-api-inventory.md +303 -0
- package/dist/docs/versioned/next/implementationPlans/syncdb-codegen.md +252 -0
- package/dist/docs/versioned/next/implementationPlans/syncdb-local-first.md +468 -420
- package/dist/docs/versioned/next/implementationPlans/syncdb-phase-c-design.md +425 -0
- package/dist/docs/versioned/next/implementationPlans/terreno-syncdb-2.md +800 -0
- package/dist/docs/versioned/next/reference/README.md +2 -0
- package/dist/docs/versioned/next/reference/comms.md +132 -0
- package/dist/docs/versioned/next/reference/environment-variables.md +9 -0
- package/dist/docs/versioned/next/reference/syncdb.md +456 -0
- package/dist/docs/versioned/next/superpowers/plans/2026-07-28-admin-mobile-navigation.md +97 -0
- package/dist/docs/versioned/next/superpowers/specs/2026-07-28-admin-mobile-navigation-design.md +36 -0
- package/dist/docs/versioned/next/tasks/comms-abstraction.md +29 -16
- package/dist/docs/versioned/next/tasks/comms-adapter-sendgrid.md +17 -7
- package/dist/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +17 -7
- package/dist/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +3 -3
- package/dist/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
- package/dist/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
- package/dist/docs/versioned/next/tasks/rtk-to-syncdb-migration-docs.md +10 -10
- package/dist/docs/versioned/next/tasks/syncdb-codegen.md +65 -0
- package/dist/docs/versioned/next/tasks/syncdb-local-first.md +434 -117
- package/package.json +3 -3
- package/src/docs/templates/bootstrap/frontend/app/_layout.template.tsx +1 -1
- package/src/docs/upgrades/56.0.0-beta.2.md +59 -0
- package/src/docs/versioned/next/README.md +2 -0
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +21 -0
- package/src/docs/versioned/next/how-to/README.md +2 -0
- package/src/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +445 -0
- package/src/docs/versioned/next/implementationPlans/PLAN_INDEX.md +28 -50
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +3 -2
- package/src/docs/versioned/next/implementationPlans/comms-abstraction.md +98 -15
- package/src/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +63 -13
- package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +65 -12
- package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +9 -3
- package/src/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
- package/src/docs/versioned/next/implementationPlans/rtk-to-syncdb-migration-docs.md +52 -47
- package/src/docs/versioned/next/implementationPlans/syncdb-api-inventory.md +303 -0
- package/src/docs/versioned/next/implementationPlans/syncdb-codegen.md +252 -0
- package/src/docs/versioned/next/implementationPlans/syncdb-local-first.md +468 -420
- package/src/docs/versioned/next/implementationPlans/syncdb-phase-c-design.md +425 -0
- package/src/docs/versioned/next/implementationPlans/terreno-syncdb-2.md +800 -0
- package/src/docs/versioned/next/reference/README.md +2 -0
- package/src/docs/versioned/next/reference/comms.md +132 -0
- package/src/docs/versioned/next/reference/environment-variables.md +9 -0
- package/src/docs/versioned/next/reference/syncdb.md +456 -0
- package/src/docs/versioned/next/superpowers/plans/2026-07-28-admin-mobile-navigation.md +97 -0
- package/src/docs/versioned/next/superpowers/specs/2026-07-28-admin-mobile-navigation-design.md +36 -0
- package/src/docs/versioned/next/tasks/comms-abstraction.md +29 -16
- package/src/docs/versioned/next/tasks/comms-adapter-sendgrid.md +17 -7
- package/src/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +17 -7
- package/src/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +3 -3
- package/src/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
- package/src/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
- package/src/docs/versioned/next/tasks/rtk-to-syncdb-migration-docs.md +10 -10
- package/src/docs/versioned/next/tasks/syncdb-codegen.md +65 -0
- package/src/docs/versioned/next/tasks/syncdb-local-first.md +434 -117
- package/dist/__tests__/bootstrap.test.d.ts +0 -2
- package/dist/__tests__/bootstrap.test.d.ts.map +0 -1
- package/dist/__tests__/bootstrap.test.js +0 -299
- package/dist/__tests__/bootstrap.test.js.map +0 -1
- package/dist/__tests__/databaseQuery.test.d.ts +0 -2
- package/dist/__tests__/databaseQuery.test.d.ts.map +0 -1
- package/dist/__tests__/databaseQuery.test.js +0 -83
- package/dist/__tests__/databaseQuery.test.js.map +0 -1
- package/dist/__tests__/docsRoot.test.d.ts +0 -2
- package/dist/__tests__/docsRoot.test.d.ts.map +0 -1
- package/dist/__tests__/docsRoot.test.js +0 -59
- package/dist/__tests__/docsRoot.test.js.map +0 -1
- package/dist/__tests__/inferPackages.test.d.ts +0 -2
- package/dist/__tests__/inferPackages.test.d.ts.map +0 -1
- package/dist/__tests__/inferPackages.test.js +0 -35
- package/dist/__tests__/inferPackages.test.js.map +0 -1
- package/dist/__tests__/preload.d.ts +0 -2
- package/dist/__tests__/preload.d.ts.map +0 -1
- package/dist/__tests__/preload.js +0 -12
- package/dist/__tests__/preload.js.map +0 -1
- package/dist/__tests__/prompts.test.d.ts +0 -2
- package/dist/__tests__/prompts.test.d.ts.map +0 -1
- package/dist/__tests__/prompts.test.js +0 -295
- package/dist/__tests__/prompts.test.js.map +0 -1
- package/dist/__tests__/resources.test.d.ts +0 -2
- package/dist/__tests__/resources.test.d.ts.map +0 -1
- package/dist/__tests__/resources.test.js +0 -352
- package/dist/__tests__/resources.test.js.map +0 -1
- package/dist/__tests__/search.test.d.ts +0 -2
- package/dist/__tests__/search.test.d.ts.map +0 -1
- package/dist/__tests__/search.test.js +0 -163
- package/dist/__tests__/search.test.js.map +0 -1
- package/dist/__tests__/tools.test.d.ts +0 -2
- package/dist/__tests__/tools.test.d.ts.map +0 -1
- package/dist/__tests__/tools.test.js +0 -540
- package/dist/__tests__/tools.test.js.map +0 -1
- package/dist/__tests__/upgradeGuide.test.d.ts +0 -2
- package/dist/__tests__/upgradeGuide.test.d.ts.map +0 -1
- package/dist/__tests__/upgradeGuide.test.js +0 -22
- package/dist/__tests__/upgradeGuide.test.js.map +0 -1
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# Implementation Plan: RTK Deprecation and SyncDB Migration Docs
|
|
2
2
|
|
|
3
|
-
**Status:**
|
|
4
|
-
**Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1007
|
|
3
|
+
**Status:** In progress — syncdb available on `release-56.0.0`; reference + migration guide drafted
|
|
5
4
|
**Priority:** Critical (gates most of Wave 1)
|
|
6
5
|
**Effort:** Big batch
|
|
7
6
|
**Owner:** unassigned
|
|
8
7
|
**Created:** 2026-07-27
|
|
9
8
|
**Program:** [OSS launch](oss-launch-program.md)
|
|
10
|
-
**Depends on:** a merged `@terreno/syncdb` package.
|
|
11
|
-
**RTK deprecation flag:** **
|
|
9
|
+
**Depends on:** a merged `@terreno/syncdb` package. It was **not** delivered by PR #869 (closed); it lives on the **`release-56.0.0`** launch branch (`syncdb/`), so this IP is authored on and targets `release-56.0.0`, not `master`.
|
|
10
|
+
**RTK deprecation flag:** **Unblocked on `release-56.0.0`** — this IP *is* the RTK deprecation. The `@terreno/syncdb` public surface is now final on `release-56.0.0` (`syncdb/src/index.ts`, `syncdb/src/react/index.ts`, `syncdb/src/testing/index.ts`); docs are written against that source.
|
|
12
11
|
|
|
13
12
|
## Goal
|
|
14
13
|
|
|
@@ -34,8 +33,8 @@ Scope is documentation, deprecation signalling, and migration tooling — not sy
|
|
|
34
33
|
| M3 | Auth vs data migration | **C** — Better Auth first, then syncdb |
|
|
35
34
|
| M4 | `docs/reference/rtk.md` (→ P7 **A**) | **Remove from the public reference index** — no legacy reference page. Existing RTK consumers use **`docs/how-to/migrate-rtk-to-syncdb.md`** only; do not maintain a parallel RTK reference path in launch docs |
|
|
36
35
|
| M5 | SDK codegen command | **A** — `bun run sdk` keeps working |
|
|
37
|
-
| M6 | Codemod | **B (reaffirmed 2026-08-09)** — no migration script
|
|
38
|
-
| M7 | Local-first default | **A
|
|
36
|
+
| M6 | Codemod | **B (reaffirmed 2026-08-09)** — no migration script/codemod. Ship the *context* an AI agent needs (the syncdb reference, verified before/after pairs, and the `upgrading-terreno` skill), not a mechanical transform. See "Migration strategy" below |
|
|
37
|
+
| M7 | Local-first default | **A — confirmed local-first only.** `@terreno/syncdb` has no server-first mode and no opt-in flag: the local store is the UI source of truth (`syncdb/src/index.ts:4-7`, `syncdb/README.md:3`) and `SyncDbConfig` (`syncdb/src/client.ts`) exposes no server-first option |
|
|
39
38
|
|
|
40
39
|
## Architecture
|
|
41
40
|
|
|
@@ -58,49 +57,55 @@ Every document below currently describes an RTK-shaped world and must be reconci
|
|
|
58
57
|
| `README.md` architecture diagram | `@terreno/rtk` box | `@terreno/syncdb` box |
|
|
59
58
|
| `mcp-server` resources + bootstrap templates | RTK store wiring | syncdb client wiring |
|
|
60
59
|
|
|
60
|
+
### Surface map reconciliation (Task 1.2, checked against `release-56.0.0`)
|
|
61
|
+
|
|
62
|
+
The pre-merge surface map above was a hypothesis. Reconciled against the merged
|
|
63
|
+
`syncdb/` on `release-56.0.0`:
|
|
64
|
+
|
|
65
|
+
- **Three entry points, not one:** `@terreno/syncdb` (client, protocol/status/conflict
|
|
66
|
+
types, `betterAuthAdapter`, key providers/codecs, persister factories, transports,
|
|
67
|
+
`wipeLocalData`, `generateMutationId`, `listConflicts`, `OUTBOX_TABLE`),
|
|
68
|
+
`@terreno/syncdb/react` (`SyncDbProvider`, `useSyncDbClient`, `useEntity`, `useQuery`,
|
|
69
|
+
`useEntityIds`, `useMutate`, `useSyncStatus`, `useConflicts`, `useSyncDebugLog`), and
|
|
70
|
+
`@terreno/syncdb/testing` (`createFakeTransport`).
|
|
71
|
+
- **Backend surface #869's hypothesis under-specified:** `SyncApp` (`GET /sync/snapshot`,
|
|
72
|
+
`POST /sync/mutate`, `POST /sync/mutate/batch`, `GET /sync/key`, `POST /sync/entities`),
|
|
73
|
+
`RealtimeApp` (Socket.io `sync:subscribe`/`sync:mutate`/`sync:delta`/`sync:ack`/`sync:nack`/
|
|
74
|
+
`sync:mutateBatch`), the required `syncPlugin` + `isDeletedPlugin`, the `sync` modelRouter
|
|
75
|
+
config (owner/tenant/broadcast/custom scoping + `getUserScopes`/`snapshotFilter`), and
|
|
76
|
+
`ensureSyncIndexes()` plus the `SyncCounter`/`SyncMutation`/`SyncScopeMove`/`SyncKey`
|
|
77
|
+
bookkeeping models. All are documented in `docs/reference/syncdb.md`.
|
|
78
|
+
- **Encryption at rest (web) is a real public surface:** AES-GCM codec, `createServerKeyProvider`
|
|
79
|
+
(default) / `createLocalKeyProvider`, `onDecryptFailure`. Documented.
|
|
80
|
+
- **M5 confirmed:** `bun run sdk` still generates `store/openApiSdk.ts` for non-synced routes
|
|
81
|
+
(auth, profile, admin, AI, feature flags); synced collections use syncdb hooks instead.
|
|
82
|
+
- **M7 confirmed:** local-first only (see the blocking-questions table).
|
|
83
|
+
|
|
61
84
|
### Migration strategy: AI-context-first (not codemods)
|
|
62
85
|
|
|
63
|
-
The migration is delivered as **context for an AI coding agent to perform
|
|
64
|
-
migration in a specific app**, not as a script that mechanically transforms code.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Design rules that follow from this strategy:
|
|
87
|
-
|
|
88
|
-
- **Every code sample must be real and compile against the merged syncdb** — an
|
|
89
|
-
agent will copy them, so an invented sample produces broken migrations at scale.
|
|
90
|
-
- **Name what to delete, not just what to add.** The parts consumers get wrong
|
|
91
|
-
are the RTK patterns that become dead code (manual optimistic updates, write
|
|
92
|
-
spinners, refetch-after-mutate); the guide must call these out explicitly so an
|
|
93
|
-
agent removes them.
|
|
94
|
-
- **Prefer decision tables and per-step checklists** (agent-followable) over long
|
|
95
|
-
narrative. The copy-pasteable checklist in step 11 doubles as an agent to-do
|
|
96
|
-
list.
|
|
97
|
-
- **Keep the rollout unit small** — per screen via `USE_SYNCDB` — so an agent can
|
|
98
|
-
migrate, verify, and stop at any point.
|
|
99
|
-
|
|
100
|
-
If a mechanical helper turns out to be genuinely safe for a narrow sub-step (for
|
|
101
|
-
example a pure import rename during the support window), it may be added later as
|
|
102
|
-
an *optional* convenience, but it is never the primary path and never a
|
|
103
|
-
precondition for migrating.
|
|
86
|
+
The migration is delivered as **context for an AI coding agent (and humans) to perform
|
|
87
|
+
the migration in a specific app**, not as a script that mechanically transforms code.
|
|
88
|
+
The RTK → syncdb move is not find-and-replace: writes change semantics (local-first;
|
|
89
|
+
optimistic code gets *deleted*), conflicts and sync status are net-new concepts with
|
|
90
|
+
app-specific UI, and auth migrates on its own schedule. Those are per-screen judgment
|
|
91
|
+
calls, not blind transforms.
|
|
92
|
+
|
|
93
|
+
This IP therefore ships three context artifacts and no migration script:
|
|
94
|
+
|
|
95
|
+
1. **The syncdb reference** (`docs/reference/syncdb.md`) — the ground-truth API the agent
|
|
96
|
+
maps RTK calls onto.
|
|
97
|
+
2. **The migration guide** (`docs/how-to/migrate-rtk-to-syncdb.md`) — organized by *what the
|
|
98
|
+
developer changes*, with **verified before/after pairs** from the real `example-frontend`
|
|
99
|
+
migration (RTK todos on `master` → `SyncTodosScreen` on `release-56.0.0`). An agent
|
|
100
|
+
generalizes far better from a correct concrete example than from prose.
|
|
101
|
+
3. **The `upgrading-terreno` skill** (owned by [`upgrade-guides-and-skill`](upgrade-guides-and-skill.md))
|
|
102
|
+
— drives an agent to migrate one screen at a time behind a flag, verify, and repeat.
|
|
103
|
+
|
|
104
|
+
Design rules that follow: every code sample is real and compiles against the merged
|
|
105
|
+
syncdb; the guide names what to **delete** (manual optimistic updates, write spinners,
|
|
106
|
+
refetch-after-mutate), not just what to add; prefer decision tables and per-step
|
|
107
|
+
checklists over narrative; keep the rollout unit small (per screen). A mechanical helper
|
|
108
|
+
may be added later for a narrow safe sub-step, but it is never the primary path.
|
|
104
109
|
|
|
105
110
|
### The migration guide's shape
|
|
106
111
|
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# @terreno/syncdb API inventory (temporary)
|
|
2
|
+
|
|
3
|
+
Working document for the RTK → syncdb migration. Lists every public export from the three package entry points, with source locations verified against `syncdb/src/`.
|
|
4
|
+
|
|
5
|
+
## M5 — Does `bun run sdk` still work?
|
|
6
|
+
|
|
7
|
+
**Yes.** The example app still generates RTK Query hooks from the backend OpenAPI spec:
|
|
8
|
+
|
|
9
|
+
- `example-frontend/package.json:73` — `"sdk": "bun scripts/generate-sdk.ts && bun biome check --write scripts/generate-sdk.ts"`
|
|
10
|
+
- `example-frontend/scripts/generate-sdk.ts:22` — runs `@rtk-query/codegen-openapi` against `openapi-config.ts`
|
|
11
|
+
- `example-frontend/openapi-config.ts:11` — output is `./store/openApiSdk.ts`
|
|
12
|
+
|
|
13
|
+
**What it generates now (post-migration):** typed RTK Query hooks for **non-synced** routes — Better Auth, `GET /auth/me`, admin, AI explorer, version config, feature-flag configuration, and any custom REST endpoints. Synced collections (e.g. todos) are **not** read or written through generated hooks; they use `@terreno/syncdb` hooks instead. `example-frontend/store/sdk.ts` still wraps `openApiSdk.ts` with tag enhancements and realtime wiring for endpoints that remain on RTK (todos realtime config is legacy/unused by the syncdb screen).
|
|
14
|
+
|
|
15
|
+
## M7 — Local-first only vs opt-in?
|
|
16
|
+
|
|
17
|
+
**Local-first only — there is no server-first mode and no opt-in flag.**
|
|
18
|
+
|
|
19
|
+
The on-device TinyBase store is always the UI source of truth; reads come from local state, writes apply optimistically, and the server reconciles asynchronously.
|
|
20
|
+
|
|
21
|
+
- `syncdb/src/index.ts:4-7` — package doc: "reads come from the local store, writes apply optimistically… the server is asynchronous reconciliation"
|
|
22
|
+
- `syncdb/README.md:3-4` — "TinyBase MergeableStore … is the UI's source of truth"
|
|
23
|
+
- `syncdb/src/client.ts:60-151` (`SyncDbConfig`) — no `mode`, `serverFirst`, or similar option
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## `@terreno/syncdb` (`syncdb/src/index.ts`)
|
|
28
|
+
|
|
29
|
+
### Client factory and constants
|
|
30
|
+
|
|
31
|
+
| Symbol | Kind | Description | Source |
|
|
32
|
+
|--------|------|-------------|--------|
|
|
33
|
+
| `createSyncDb` | `function (config: SyncDbConfig): SyncDb` | Assemble the local-first client | `client.ts:281` |
|
|
34
|
+
| `DEFAULT_RECONCILE_INTERVAL_MS` | `const` (5 min) | Default periodic reconcile interval | `client.ts:38` |
|
|
35
|
+
| `DEFAULT_SEQ_JUMP_RECONCILE_MIN_INTERVAL_MS` | `const` (30s) | Seq-jump reconcile rate limit | `client.ts:41` |
|
|
36
|
+
| `DEFAULT_TOMBSTONE_RETENTION_MS` | `const` (90 days) | Client tombstone compaction window | `client.ts:44` |
|
|
37
|
+
| `DEFAULT_START_AUTH_RETRY_ATTEMPTS` | `const` (3) | `start()` auth-resolution retries | `client.ts:55` |
|
|
38
|
+
| `DEFAULT_START_AUTH_RETRY_DELAY_MS` | `const` (250) | Delay between `start()` auth retries | `client.ts:56` |
|
|
39
|
+
|
|
40
|
+
### `SyncDbConfig` fields
|
|
41
|
+
|
|
42
|
+
| Field | Type | Default | Description | Source |
|
|
43
|
+
|-------|------|---------|-------------|--------|
|
|
44
|
+
| `name` | `string` | — (required) | Persisted database name | `client.ts:62` |
|
|
45
|
+
| `collections` | `string[]` | — (required) | Collections to sync | `client.ts:64` |
|
|
46
|
+
| `authProvider` | `AuthProvider` | — (required) | Token/user/auth-change surface | `client.ts:65` |
|
|
47
|
+
| `baseUrl` | `string?` | — | Server origin; required unless `transport` + `httpChannel` injected | `client.ts:67` |
|
|
48
|
+
| `transport` | `SyncTransport?` | socket transport from `baseUrl` | Transport override (tests) | `client.ts:69` |
|
|
49
|
+
| `httpChannel` | `HttpChannel?` | from `baseUrl` | HTTP channel override | `client.ts:71` |
|
|
50
|
+
| `persisterFactory` | `PersisterFactory?` | platform default | Persister override | `client.ts:73` |
|
|
51
|
+
| `keyProvider` | `KeyProvider?` | server-derived via `/sync/key` | Web encryption key provider | `client.ts:75` |
|
|
52
|
+
| `idbGetImpl` | test hook | — | IndexedDB read override (tests) | `client.ts:82` |
|
|
53
|
+
| `idbSetImpl` | test hook | — | IndexedDB write override (tests) | `client.ts:83` |
|
|
54
|
+
| `reconcileIntervalMs` | `number?` | `DEFAULT_RECONCILE_INTERVAL_MS` (5 min); `0` disables | Periodic reconcile timer | `client.ts:85` |
|
|
55
|
+
| `seqJumpReconcileMinIntervalMs` | `number?` | `DEFAULT_SEQ_JUMP_RECONCILE_MIN_INTERVAL_MS` | Per-stream seq-jump rate limit | `client.ts:87` |
|
|
56
|
+
| `now` | `() => number?` | `Date.now` | Injectable clock | `client.ts:89` |
|
|
57
|
+
| `random` | `() => number?` | `Math.random` | Injectable RNG for backoff jitter | `client.ts:91` |
|
|
58
|
+
| `debug` | `boolean \| SyncDebugLogOptions?` | `false` (off) | In-memory debug event log | `client.ts:98` |
|
|
59
|
+
| `onAuthRequired` | `() => void?` | — | Fires once per auth-pause episode | `client.ts:104` |
|
|
60
|
+
| `wipeOnSignOut` | `boolean?` | `false` | `signOut()` also wipes local data | `client.ts:111` |
|
|
61
|
+
| `batchSize` | `number?` | `50` (server caps at 100) | Max mutations per batched drain | `client.ts:113` |
|
|
62
|
+
| `haltQueueOnConflict` | `boolean?` | `false` | Conflict halts entire drain vs per-entity | `client.ts:119` |
|
|
63
|
+
| `onDecryptFailure` | `() => void?` | wipe + re-bootstrap (with `console.warn`) | Override decrypt-failure recovery | `client.ts:129` |
|
|
64
|
+
| `tombstoneRetentionMs` | `number?` | `DEFAULT_TOMBSTONE_RETENTION_MS`; `0` disables | Client tombstone compaction after reconcile | `client.ts:138` |
|
|
65
|
+
| `startAuthRetryAttempts` | `number?` | `DEFAULT_START_AUTH_RETRY_ATTEMPTS`; `1` disables | `start()` user-id resolution attempts | `client.ts:148` |
|
|
66
|
+
| `startAuthRetryDelayMs` | `number?` | `DEFAULT_START_AUTH_RETRY_DELAY_MS` | Delay between those attempts | `client.ts:150` |
|
|
67
|
+
|
|
68
|
+
### `SyncDb` methods and properties
|
|
69
|
+
|
|
70
|
+
| Member | Signature / type | Description | Source |
|
|
71
|
+
|--------|------------------|-------------|--------|
|
|
72
|
+
| `store` | `readonly SyncStore` | Local-first entity store | `client.ts:193` |
|
|
73
|
+
| `outbox` | `readonly Outbox` | Durable mutation outbox | `client.ts:195` |
|
|
74
|
+
| `debug` | `readonly SyncDebugLog \| undefined` | Debug log when `debug` enabled | `client.ts:270` |
|
|
75
|
+
| `start` | `() => Promise<void>` | Resolve user, persist, connect, bootstrap | `client.ts:202` |
|
|
76
|
+
| `stop` | `() => Promise<void>` | Disconnect, stop persistence, clear timers | `client.ts:204` |
|
|
77
|
+
| `goOffline` | `() => void` | Simulated outage (local writes continue) | `client.ts:212` |
|
|
78
|
+
| `goOnline` | `() => Promise<void>` | End simulated outage | `client.ts:218` |
|
|
79
|
+
| `mutate` | `(args: MutateArgs) => {mutationId, id}` | Optimistic write + enqueue + replay | `client.ts:224` |
|
|
80
|
+
| `reconcile` | `() => Promise<void>` | HTTP snapshot catch-up all streams | `client.ts:226` |
|
|
81
|
+
| `forceResync` | `() => Promise<ForceResyncResult>` | Purge streams and re-bootstrap from 0 | `client.ts:233` |
|
|
82
|
+
| `replayOutbox` | `() => Promise<void>` | Drain queued mutations now | `client.ts:235` |
|
|
83
|
+
| `resolveConflict` | `({mutationId, strategy}) => void` | Apply `useServer` or `keepMine` | `client.ts:237` |
|
|
84
|
+
| `retryFailed` | `({entityId}) => void` | Re-enable blocked entity queue | `client.ts:244` |
|
|
85
|
+
| `signOut` | `() => Promise<void>` | Explicit teardown; optional wipe | `client.ts:254` |
|
|
86
|
+
| `getSyncStatus` | `() => SyncStatus` | Aggregate sync state snapshot | `client.ts:256` |
|
|
87
|
+
| `onStatusChange` | `(callback) => () => void` | Subscribe to connectivity/syncing changes | `client.ts:264` |
|
|
88
|
+
|
|
89
|
+
### Supporting client types
|
|
90
|
+
|
|
91
|
+
| Symbol | Kind | Source |
|
|
92
|
+
|--------|------|--------|
|
|
93
|
+
| `MutateArgs` | `interface` `{collection, operation, id?, data?}` | `client.ts:182` |
|
|
94
|
+
| `ForceResyncSkipReason` | `type` union | `client.ts:162` |
|
|
95
|
+
| `ForceResyncResult` | `interface` | `client.ts:170` |
|
|
96
|
+
|
|
97
|
+
### Protocol, status, and conflict types (`types.ts`)
|
|
98
|
+
|
|
99
|
+
| Symbol | Kind | Source |
|
|
100
|
+
|--------|------|--------|
|
|
101
|
+
| `SyncMutationOperation` | `type` `"create" \| "update" \| "delete"` | `types.ts:9` |
|
|
102
|
+
| `SyncDelta` | `interface` | `types.ts:12` |
|
|
103
|
+
| `SyncMutateRequest` | `interface` | `types.ts:35` |
|
|
104
|
+
| `SyncAck` | `interface` | `types.ts:49` |
|
|
105
|
+
| `SyncNackCode` | `type` | `types.ts:63` |
|
|
106
|
+
| `SyncNack` | `interface` | `types.ts:66` |
|
|
107
|
+
| `SyncMutateBatchRequest` | `interface` | `types.ts:94` |
|
|
108
|
+
| `SyncMutateBatchResult` | `type` | `types.ts:107` |
|
|
109
|
+
| `SyncMutateBatchResponse` | `interface` | `types.ts:116` |
|
|
110
|
+
| `SyncSnapshotEntity` | `interface` | `types.ts:121` |
|
|
111
|
+
| `SyncEntitiesResponse` | `interface` | `types.ts:129` |
|
|
112
|
+
| `SyncSnapshotResponse` | `interface` | `types.ts:134` |
|
|
113
|
+
| `SyncStreamInfo` | `interface` | `types.ts:156` |
|
|
114
|
+
| `OutboxStatus` | `type` | `types.ts:164` |
|
|
115
|
+
| `OutboxMutation` | `interface` | `types.ts:167` |
|
|
116
|
+
| `SyncConflict` | `interface` | `types.ts:186` |
|
|
117
|
+
| `ConflictResolutionStrategy` | `type` `"useServer" \| "keepMine"` | `types.ts:206` |
|
|
118
|
+
| `SyncCollectionStatus` | `interface` | `types.ts:213` |
|
|
119
|
+
| `SyncStatus` | `interface` | `types.ts:220` |
|
|
120
|
+
| `AuthProvider` | `interface` | `types.ts:269` |
|
|
121
|
+
|
|
122
|
+
### Store / outbox / wipe
|
|
123
|
+
|
|
124
|
+
| Symbol | Kind | Source |
|
|
125
|
+
|--------|------|--------|
|
|
126
|
+
| `listConflicts` | `function` | `mutations/conflicts.ts:71` |
|
|
127
|
+
| `generateMutationId` | `function` | `mutations/outbox.ts` (re-export `index.ts:75`) |
|
|
128
|
+
| `Outbox` | `type` | `mutations/outbox.ts` |
|
|
129
|
+
| `SyncStore` | `type` | `storage/store.ts` |
|
|
130
|
+
| `OUTBOX_TABLE` | `const` | `storage/types.ts` |
|
|
131
|
+
| `SyncEntity` | `type` | `storage/types.ts` |
|
|
132
|
+
| `wipeLocalData` | `async function` | `storage/wipe.ts:19` |
|
|
133
|
+
|
|
134
|
+
### Auth adapter
|
|
135
|
+
|
|
136
|
+
| Symbol | Kind | Source |
|
|
137
|
+
|--------|------|--------|
|
|
138
|
+
| `betterAuthAdapter` | `function` | `auth/betterAuthAdapter.ts:39` |
|
|
139
|
+
| `DEFAULT_AUTH_POLL_INTERVAL_MS` | `const` (5000) | `auth/betterAuthAdapter.ts:5` |
|
|
140
|
+
| `BetterAuthAdapterOptions` | `interface` | `auth/betterAuthAdapter.ts:7` |
|
|
141
|
+
| `BetterAuthClientLike` | `type` | `auth/types.ts` |
|
|
142
|
+
| `BetterAuthGetSessionResult` | `type` | `auth/types.ts` |
|
|
143
|
+
| `BetterAuthSessionAtomLike` | `type` | `auth/types.ts` |
|
|
144
|
+
| `BetterAuthSessionDataLike` | `type` | `auth/types.ts` |
|
|
145
|
+
| `BetterAuthSessionLike` | `type` | `auth/types.ts` |
|
|
146
|
+
| `BetterAuthUserLike` | `type` | `auth/types.ts` |
|
|
147
|
+
|
|
148
|
+
### Encryption and key providers
|
|
149
|
+
|
|
150
|
+
| Symbol | Kind | Source |
|
|
151
|
+
|--------|------|--------|
|
|
152
|
+
| `AES_GCM_ENVELOPE_VERSION` | `const` | `crypto/aesGcmCodec.ts` |
|
|
153
|
+
| `createAesGcmCodec` | `function` | `crypto/aesGcmCodec.ts` |
|
|
154
|
+
| `PayloadIntegrityError` | `class` | `crypto/aesGcmCodec.ts` |
|
|
155
|
+
| `UnknownEnvelopeVersionError` | `class` | `crypto/aesGcmCodec.ts` |
|
|
156
|
+
| `identityCodec` | `const` | `crypto/identityCodec.ts` |
|
|
157
|
+
| `createKeyProviderCodec` | `function` | `crypto/keyProviders.ts` |
|
|
158
|
+
| `createLocalKeyProvider` | `function` | `crypto/keyProviders.ts` |
|
|
159
|
+
| `createServerKeyProvider` | `function` | `crypto/keyProviders.ts` |
|
|
160
|
+
| `DEFAULT_KEY_CACHE_DB_NAME` | `const` | `crypto/keyProviders.ts` |
|
|
161
|
+
| `KeyProvider` | `interface` | `crypto/types.ts` |
|
|
162
|
+
| `PayloadCodec` | `interface` | `crypto/types.ts` |
|
|
163
|
+
|
|
164
|
+
### Persisters
|
|
165
|
+
|
|
166
|
+
| Symbol | Kind | Source |
|
|
167
|
+
|--------|------|--------|
|
|
168
|
+
| `createDefaultPersisterFactory` | `function` | `persisters/defaultPersisterFactory.ts` |
|
|
169
|
+
| `createEncryptedIndexedDbPersister` | `function` | `persisters/encryptedIndexedDbPersister.ts` |
|
|
170
|
+
| `clearMemoryPersisterData` | `function` | `persisters/memoryPersister.ts` |
|
|
171
|
+
| `createMemoryPersister` | `function` | `persisters/memoryPersister.ts` |
|
|
172
|
+
| `memoryPersisterFactory` | `function` | `persisters/memoryPersister.ts` |
|
|
173
|
+
| `DefaultPersisterFactoryConfig` | `type` | `persisters/types.ts` |
|
|
174
|
+
| `PersisterFactory` | `type` | `persisters/types.ts` |
|
|
175
|
+
|
|
176
|
+
### Transports and HTTP channel
|
|
177
|
+
|
|
178
|
+
| Symbol | Kind | Source |
|
|
179
|
+
|--------|------|--------|
|
|
180
|
+
| `AuthRequiredError` | `class` | `sync/httpChannel.ts` |
|
|
181
|
+
| `createHttpChannel` | `function` | `sync/httpChannel.ts` |
|
|
182
|
+
| `FetchLike` | `type` | `sync/httpChannel.ts` |
|
|
183
|
+
| `FetchSnapshotPageArgs` | `type` | `sync/httpChannel.ts` |
|
|
184
|
+
| `HttpChannel` | `interface` | `sync/httpChannel.ts` |
|
|
185
|
+
| `HttpChannelConfig` | `interface` | `sync/httpChannel.ts` |
|
|
186
|
+
| `createSocketTransport` | `function` | `sync/socketTransport.ts` |
|
|
187
|
+
| `SocketTransportConfig` | `interface` | `sync/socketTransport.ts` |
|
|
188
|
+
| `DEFAULT_BATCH_SIZE` | `const` | `sync/transport.ts` |
|
|
189
|
+
| `DEFAULT_MUTATION_TIMEOUT_MS` | `const` | `sync/transport.ts` |
|
|
190
|
+
| `SendMutationBatchResult` | `type` | `sync/transport.ts` |
|
|
191
|
+
| `SendMutationResult` | `type` | `sync/transport.ts` |
|
|
192
|
+
| `SyncTransport` | `interface` | `sync/transport.ts` |
|
|
193
|
+
| `TransportStatus` | `interface` | `sync/transport.ts` |
|
|
194
|
+
|
|
195
|
+
### Debug log types
|
|
196
|
+
|
|
197
|
+
| Symbol | Kind | Source |
|
|
198
|
+
|--------|------|--------|
|
|
199
|
+
| `SyncDebugDirection` | `type` | `debug/debugLog.ts:43` |
|
|
200
|
+
| `SyncDebugEvent` | `interface` | `debug/debugLog.ts:46` |
|
|
201
|
+
| `SyncDebugEventType` | `type` | `debug/debugLog.ts:27` |
|
|
202
|
+
| `SyncDebugLog` | `interface` | `debug/debugLog.ts` |
|
|
203
|
+
| `SyncDebugLogOptions` | `interface` | `debug/debugLog.ts` |
|
|
204
|
+
| `SyncDebugRecordInput` | `interface` | `debug/debugLog.ts` |
|
|
205
|
+
| `SyncDebugSnapshot` | `interface` | `debug/debugLog.ts` |
|
|
206
|
+
| `SyncDebugStats` | `interface` | `debug/debugLog.ts` |
|
|
207
|
+
|
|
208
|
+
**Not exported (internal):** `resolveConflict` (mutation writer), `writeConflict`, cursor mutators, IndexedDB helpers, debug broadcast bridge — use `client.resolveConflict` / `useConflicts().resolve` instead.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## `@terreno/syncdb/react` (`syncdb/src/react/index.ts` → hooks + provider)
|
|
213
|
+
|
|
214
|
+
| Symbol | Kind | Description | Source |
|
|
215
|
+
|--------|------|-------------|--------|
|
|
216
|
+
| `SyncDbProvider` | `React.FC<SyncDbProviderProps>` | Provides client to descendants | `provider.tsx:13` |
|
|
217
|
+
| `SyncDbProviderProps` | `interface` `{client, children}` | Provider props | `provider.tsx:7` |
|
|
218
|
+
| `useSyncDbClient` | `() => SyncDb` | Access client from context | `provider.tsx:18` |
|
|
219
|
+
| `useEntity` | `<T>(collection, id) => UseEntityResult<T>` | Subscribe to one entity | `hooks.ts:117` |
|
|
220
|
+
| `UseEntityResult` | `interface` `{data, deleted, seq, isPending}` | `useEntity` return shape | `hooks.ts:105` |
|
|
221
|
+
| `useQuery` | `<T>(collection, options?) => T[]` | Subscribe to collection (decoded data) | `hooks.ts:170` |
|
|
222
|
+
| `UseQueryOptions` | `interface` `{filter?, sort?, includeDeleted?}` | Query options | `hooks.ts:149` |
|
|
223
|
+
| `useEntityIds` | `<T>(collection, options?) => string[]` | Stable id list for virtualization | `hooks.ts:221` |
|
|
224
|
+
| `useMutate` | `(collection) => UseMutateResult` | `{create, update, remove}` | `hooks.ts:266` |
|
|
225
|
+
| `UseMutateResult` | `interface` | Mutation helpers | `hooks.ts:253` |
|
|
226
|
+
| `useSyncStatus` | `() => SyncStatus` | Reactive aggregate status | `hooks.ts:296` |
|
|
227
|
+
| `useConflicts` | `() => UseConflictsResult` | `{conflicts, resolve}` | `hooks.ts:328` |
|
|
228
|
+
| `UseConflictsResult` | `interface` | Conflict hook return | `hooks.ts:320` |
|
|
229
|
+
| `useSyncDebugLog` | `() => UseSyncDebugLogResult` | Debug log subscription | `hooks.ts:379` |
|
|
230
|
+
| `UseSyncDebugLogResult` | `interface` `{enabled, events, stats, log, clear}` | Debug hook return | `hooks.ts:355` |
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## `@terreno/syncdb/testing` (`syncdb/src/testing/index.ts`)
|
|
235
|
+
|
|
236
|
+
| Symbol | Kind | Description | Source |
|
|
237
|
+
|--------|------|-------------|--------|
|
|
238
|
+
| `createFakeTransport` | `() => FakeTransport` | In-memory transport double | `testing/fakeTransport.ts:74` |
|
|
239
|
+
| `FakeTransport` | `interface` extends `SyncTransport` | Test controls + recording | `testing/fakeTransport.ts:32` |
|
|
240
|
+
| `FakeMutationResponder` | `type` | Single-mutation responder | `testing/fakeTransport.ts:22` |
|
|
241
|
+
| `FakeBatchResponder` | `type` | Batch responder | `testing/fakeTransport.ts:27` |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Reference migration (`example-frontend`)
|
|
246
|
+
|
|
247
|
+
Before paths are from `origin/master`; after paths are on the current branch.
|
|
248
|
+
|
|
249
|
+
### (a) Store setup
|
|
250
|
+
|
|
251
|
+
| | Path | What changed |
|
|
252
|
+
|---|------|--------------|
|
|
253
|
+
| **Before** | `example-frontend/store/index.ts` (master) | `generateAuthSlice(terrenoApi)`, `createOfflineMiddleware`, Redux persist, RTK Query reducer |
|
|
254
|
+
| **After** | `example-frontend/store/index.ts` | `generateBetterAuthSlice`, RTK only for non-synced API + app state |
|
|
255
|
+
| **After** | `example-frontend/store/syncdb.ts` | `createSyncDb({authProvider: betterAuthAdapter(...), collections: ["todos"], ...})` |
|
|
256
|
+
|
|
257
|
+
### (b) Provider wiring
|
|
258
|
+
|
|
259
|
+
| | Path | What changed |
|
|
260
|
+
|---|------|--------------|
|
|
261
|
+
| **Before** | `example-frontend/app/_layout.tsx` (master) | Redux `Provider` only; todos screen uses RTK hooks directly |
|
|
262
|
+
| **After** | `example-frontend/app/(tabs)/index.tsx` | `SyncDbProvider client={syncDb}` wraps `SyncTodosScreen` |
|
|
263
|
+
| **After** | `example-frontend/app/_layout.tsx` | `syncDb.start()` / `stop()` on login; `SyncDbProvider` + `SyncHealthToast` at root when `userId` set |
|
|
264
|
+
|
|
265
|
+
### (c) Reads
|
|
266
|
+
|
|
267
|
+
| | Path | What changed |
|
|
268
|
+
|---|------|--------------|
|
|
269
|
+
| **Before** | `example-frontend/app/(tabs)/index.tsx` (master) | `useGetTodosQuery({}, {skip: !userId})`, `isLoading`, `refetch` |
|
|
270
|
+
| **After** | `example-frontend/components/SyncTodosScreen.tsx` | `useEntityIds<SyncTodo>("todos", {filter, sort})` + per-row `useEntity("todos", id)` |
|
|
271
|
+
|
|
272
|
+
### (d) Writes
|
|
273
|
+
|
|
274
|
+
| | Path | What changed |
|
|
275
|
+
|---|------|--------------|
|
|
276
|
+
| **Before** | `example-frontend/app/(tabs)/index.tsx` (master) | `usePostTodosMutation`, `usePatchTodosByIdMutation`, `useDeleteTodosByIdMutation`, `.unwrap()`, per-item `isUpdating` spinners |
|
|
277
|
+
| **After** | `example-frontend/components/SyncTodosScreen.tsx` | `useMutate("todos")` → `create({data})`, `update({id, data})`, `remove({id})`; gated on `useSyncDbReady()` |
|
|
278
|
+
|
|
279
|
+
### (e) Conflict UI
|
|
280
|
+
|
|
281
|
+
| | Path | What changed |
|
|
282
|
+
|---|------|--------------|
|
|
283
|
+
| **Before** | master todos screen | `useServerStatus` undismissed conflicts (RTK offline slice) |
|
|
284
|
+
| **After** | `example-frontend/components/SyncConflictsController.tsx` | App-wide conflict sheet controller |
|
|
285
|
+
| **After** | `example-frontend/app/_layout.tsx` | `ConflictSheet` via `SyncHealthToast` `renderConflictsModal` |
|
|
286
|
+
| **After** | `example-frontend/components/SyncTodosScreen.tsx` | `SyncStatusBanner` `onOpenConflicts` → `openConflicts("todos")` |
|
|
287
|
+
|
|
288
|
+
### (f) Sync-status UI
|
|
289
|
+
|
|
290
|
+
| | Path | What changed |
|
|
291
|
+
|---|------|--------------|
|
|
292
|
+
| **Before** | master todos screen | `useServerStatus`, `OfflineBanner`, request `isLoading` / `isFetching` / `RefreshControl` |
|
|
293
|
+
| **After** | `example-frontend/components/SyncTodosScreen.tsx` | `useSyncStatus()` + `SyncStatusBanner` |
|
|
294
|
+
| **After** | `example-frontend/components/SyncHealthToast.tsx` | Persistent toasts for conflicts, failures, backlog |
|
|
295
|
+
| **After** | `example-frontend/components/syncHealthSignals.ts` | Toast signal computation |
|
|
296
|
+
|
|
297
|
+
### Not covered by the reference migration
|
|
298
|
+
|
|
299
|
+
- **Auth migration details** — Better Auth session atom bridge in `store/syncdb.ts`; login still uses `@terreno/rtk` Better Auth slice (documented in migration guide §7).
|
|
300
|
+
- **Feature flags** — OpenFeature bridge in `_layout.tsx` (`OpenFeatureBridge` + `useTerrenoFeatureFlags`); no per-screen flag gating todos (syncdb-only).
|
|
301
|
+
- **Other screens** — Profile, admin, AI explorer, consent flow still use generated RTK hooks (`store/sdk.ts`).
|
|
302
|
+
- **SDK realtime config for todos** — `TODO_REALTIME_ENDPOINTS` in `sdk.ts` remains but is unused by `SyncTodosScreen`.
|
|
303
|
+
- **Debug tooling** — `example-frontend/app/syncdb-debug.tsx` (`useSyncDebugLog`).
|