Thank you for being patient! We're working hard on resolving the issue
Each reserved row pattern (e.g. :~strava:{authId}:activities)
gets one Row impl. Rows group under one Integration that owns
the per-account "grab bag" client.
IntegrationOne impl per provider account-type. Declares:
type Deps — host-supplied trait the connector threads into
every Row::sync / Row::list_cells / write-verb call. Always
a dyn <Provider>BackendDeps that you declare in the same
module.type Client — the per-account "grab bag". Typically holds an
Arc<crate::Client> (your SDK client) plus any cross-cutting
seams from Deps that you want available without indirection.type Params — path-level params extracted from the rowkey
(e.g. {authId} for garmin, {authId, calId} for google).
Plain serde::Deserialize.fn client(user, deps, params) — assembles the grab-bag.
Resolves the typed credential via
user.auth::<MyProviderAuth>(...), builds the HTTP client.Optional:
fn client_for_write(deps) — assembles a write-side grab-bag
without an authenticated user. Default: errors. Override for
integrations that accept writes from system contexts.RowOne impl per reserved pattern. Required:
type Integration — the parent Integration impl.type Params — additional params beyond the integration's
(often ()).const ROW_LABEL: &'static str — human-friendly name.fn lookup_key(int, own) — formats the canonical rowkey from
the params.Defaulted (override what you need):
| Method | Default | Override when |
|---|---|---|
const ROW_TYPE | "data" | Integration-scope rows that should not be listed as cell-bearing rows. |
const CELL_ENCODING | None | Wire-cell encoding has a tagged decoder (e.g. "event.v1"). |
fn attributes | None | Computed/formula rows that stamp initial JSON onto the row record. |
fn sync_shape | None | Sync-backed rows. None = no orchestrator registration. |
fn sync | errors | Required when sync_shape is Some. |
fn alias_key | None | Shared-data providers (e.g. weather rows aliased to a system owner). |
fn lock_resource_id | None | Providers needing serialised full-resyncs (e.g. Google Calendar's per-calendar sync token). |
fn list_cells | None | Computed-cell rows (logs, aggregators). Returning Some(cells) makes this row the canonical source of truth — the host won't fall through to its persistent cell store. |
fn post / patch / delete | errors | Writeable rows. |
Each callable receives an arg bundle:
SyncCtx<R> — passed to Row::sync. Carries the grab-bag
client, integration params, row params, current stage, owner,
pre-upserted row id, opaque dispatch payload, and the host deps
reference.WriteCtx<R> — passed to Row::post/patch/delete. Same
shape as SyncCtx minus the stage/dispatch fields.ReadCtx<R> — passed to Row::list_cells. Carries integration
params, row params, owner, the requested date range, and deps.The connector is platform-agnostic — it never invokes methods on
deps. Your row body destructures the fields it needs, including
ctx.deps.persist_cells(...) etc.
Client vs BackendDepsClient is for read-side resources — typically the
HTTP client plus any read-mostly host seams that get used in
many rows. Built once per request via Integration::client.BackendDeps is for host-side write/state seams —
things that translate to host-data types (cell store, row store,
log query). Threaded as a reference; never owned by the
connector.A single seam can live in either place. If it's only ever called
from one row's sync body, putting it in BackendDeps keeps the
grab-bag light. If multiple rows share it, putting it in Client
saves a method call per row.