bijection/schema.ts
customers is filled by the crm integration’s
customers collection, and
notes is an ordinary table your app writes, pointing at synced customers by
their document ID.
Binding a table
Call.source(...) on a table definition with a collection handle, the
property of the same name on your integration:
schema. Passing
crm.customers.schema to defineTable is the simplest way to keep the two
identical; a table whose fields differ is refused with
Source schema must match the table validator.
You can add indexes, search indexes
and vector indexes to a synced table as usual. A synced table can’t also be a
link table, have a governing rule or use a staged validator, and a table binds
exactly one collection.
The binding holds as soon as you deploy the schema. Until a
connection is installed and its first sync
completes, the table is simply empty.
Documents in a synced table
Each provider record becomes one document. The document has the fields of the collection’s schema, the usual system fields_id and _creationTime, and one more field that Bijection sets:
source_id: an opaque string identifying the installed source that published the record.
_id when the provider updates it, so your own tables
can refer to it with v.id("customers"). When the provider reports that a
record was deleted, its document is removed.
source_id is part of the generated Doc<"customers"> type and can be
indexed. The collection’s schema can’t declare a field of that name.
Reading synced data
Queries read synced tables with the ordinaryctx.db
API, and subscriptions update when a sync publishes new data:
bijection/customers.ts
Synced tables are read-only
The generated types leave synced tables out of the write methods, so this doesn’t type-check:bijection/customers.ts
ReadOnlySource error:
customers accepts changes only through its admitted source.
To keep your own data about a synced record, store it in an ordinary table that
references the record, like notes above. To change the record at the
provider, send an integration command; see
Operations.
Coverage and freshness
An empty result from a synced table can mean two different things: the provider has no matching records, or the source has never finished a sync. To tell them apart, read the source’s coverage withctx.sources.coverage, in a
query or a mutation:
bijection/customers.ts
source_id of the rows you read. The optional table option also
checks that the source publishes into that table. The result has these fields:
acquired: whether an initial sync has completed.observedFromandobservedTo: the window the current data covers, in milliseconds since the epoch, ornullbefore the first completed sync.age: how old the newest observation is, in milliseconds.checkedAt: when the source last answered a check successfully.continuityLost: whether the source lost continuity. The data it has is still valid but can no longer be extended.refreshOutstanding: whether a requested refresh hasn’t completed yet.
Several sources in one table
A synced table can receive records from more than one installed source, for example one per connected account. Each record carries its ownsource_id.
Installing a second source into a table is refused with
SourceReadAccessRequired until the table declares a read access rule, because
readers of one source’s records aren’t automatically allowed to read
another’s. See Access rules.