defineIntegration in a file inside your bijection/ directory.
This integration reads customers from a provider that exposes an ordered change
feed at GET changes?after=<checkpoint>:
bijection/crm.ts
httpdeclares every request the integration may make.identifyreads which provider account a connection speaks for.collectionsdeclares each kind of record, its schema, and its sync.commandsdeclares the changes the integration can send back to the provider. This one declares none.
Declaring an integration
defineIntegration must be imported by name from bijection/server, called
directly, and assigned to an exported const:
bijection/crm.ts
crm.js:crm here. Connections and tables refer to the integration by this
address, so export each integration exactly once and keep it in the same
module. Moving a definition to another module requires its installations to be
recreated.
The collections become properties of the returned object. crm.customers is
the handle a synced table binds to. A collection
can’t be named after a built-in property of the integration, such as
commands.
Definitions from another directory
A definition written outside yourbijection/ directory, for example in a
shared package, has no address in your deployment. Admit it from a module of
your deployment with admitIntegration:
bijection/storefront.ts
storefront.js:storefront, and .source(...) binds its collections exactly as
it binds a local definition. admitIntegration accepts only the imported
definition itself, and a definition can be admitted from one module only.
HTTP contracts
Each entry ofhttp is a named contract for one request. Your handlers make a
request by naming its contract:
Handlers
handler.member names the handler that owns the contract:
A handler can only make requests through its own contracts. A request through a
contract owned by another handler is refused.
Routes, queries and bodies
Route segments, query values, header values and body fields are templates. Use{ kind: "literal", value } for a fixed value and { kind: "input", input }
for a value the host supplies:
checkpoint: the change feed position the sync resumes from.resume: the provider cursor a listing resumes from.parameter: a value your code passes, checked againstparameters.operation_id,target_key,target_version,argument: values a command sends.
parameters and address them by path:
bijection/crm.ts
Responses
response.statuses lists each status the provider may answer and the body it
carries:
{ kind: "json", validator }: the body must parse and match the validator.{ kind: "none" }: no body.{ kind: "opaque" }: bytes that are retained but not interpreted, such as an HTML error page.
xml, jsonl and a few provider-specific shapes are also available. A status
that is not listed is still retained, but proves only that the provider
answered.
ctx.http.request resolves to the status, the admitted headers, the typed
body and an evidence reference to the retained response. The body type
follows the validators you declared.
For syncs, response.failures classifies error statuses so a failed read is
retried or reported correctly:
transient, unavailable, insufficient_scope,
authentication, signature and throttled.
Evidence
evidence says what an admitted response proves, in terms of paths into its
body. Bijection checks your handler’s result against it: a record your code
returns must cite the response it came from and its position in that response,
and its key must match the key the evidence reads. A handler can’t publish a
record a response never contained.
Other kinds, such as
incremental, traversal, projections and
query_result, describe more specialized provider APIs. The HttpEvidence
type in bijection/server lists them all.
Verifying the account
identify reads which provider account a connection speaks for. It runs when
you verify a connection, and
the result is the identity every later sync is checked against.
bijection/crm.ts
account_id: the provider’s identifier for the account, read at the path theidentityevidence declares inaccount.incarnation: optional. The provider’s own reset epoch, where it has one.evidence: the response that proved it.
identity evidence without
account and return only { evidence }. Returning an account_id the
evidence doesn’t declare is refused.
Collections
Each collection declares aschema, a protocol and a sync.
Schema
schema is an object of validators, the same
ones you use in defineTable. It is the exact shape of the table that binds to
the collection. The field name source_id is reserved.
Keep exact provider values exact. Store large identifiers, decimal amounts and
positions as strings or v.int64(), and don’t convert them through JavaScript
numbers on the way in.
Protocols
protocol states what the provider’s API actually guarantees. Bijection relies
on it to decide what a sync may publish, so declare what the provider documents,
not what you hope for.
- Change feed
- Record observation
change_feed is an ordered history of changes. Each change is a full
replacement or a deletion of one record, at a position the provider states.position.encodingisuint64_decimalorint64_decimal. Positions travel as decimal strings.checkpoint.initialis where the first sync starts.checkpoint.retentionis how long the provider keeps a position resumable:{ kind: "stated", unit, value }with a unit ofminutes,hoursordays, or{ kind: "unknown" }.
The sync
sync declares how often the collection is read and how a response becomes
records:
everyis the interval:{ seconds },{ minutes }or{ hours }, at most 366 days. Bijection’s scheduler runs it; you don’t need a cron job. A schedule requests work: it doesn’t guarantee a completed sync every interval while the provider is down.read(ctx, input)makes requests through its own contracts and returns what they observed. A singlereadmay make at most 16 requests.
read receives { checkpoint } and returns the changes,
each citing its response and its index within it, plus the provider’s progress:
read receives the provider cursor as resume and
returns the records it observed. This integration lists invoices a page at a
time. The contract, under http:
bijection/billing.ts
collections:
bijection/billing.ts
next_resume, commits each page with the records
it admitted, and fills the resume input of the next request with it until the
listing is complete.
A
read returns candidate records. It never writes to a table itself.
Bijection checks the result against the retained responses and publishes it
into the synced table in one transaction per page. A failed page publishes
nothing: it is retried later, or marked blocked until you resume it (see
Connecting and syncing).Deletions
A record is removed from the synced table only when the provider says it is gone: adelete change in a feed, or a record your read returns with
kind: "deleted". A record that is simply missing from a listing is kept.
Commands
commands declares the changes the integration can send back to the provider.
Each command names the collection it targets, its typed args, the provider’s
delivery and conditional-write contract, and send and reconcile handlers
with their own HTTP contracts.
Your application never calls a command directly. It requests one as a durable
external call from a mutation, and Bijection sends it, reconciles its outcome
and records it. See Operations.
Setup fields
Some providers need more than a base URL and a credential, such as an account subdomain. Declare these values once withsetup:
bijection/helpdesk.ts
bijection integration configure --show-setup are derived from this declaration, and the backend refuses values
that don’t match it. A field with fills: "base_url" renders the connection’s
base URL, so you don’t pass --base-url. Setup values are never secrets: a
field marked secret: true only documents what the provider needs, and the
value itself goes into a credential.
Provider rate limits
Declare the provider’s request allowance withbudget. It belongs to the
connection, so every collection and command of that connection spends from one
bucket, and a request the bucket can’t hold waits until it can:
bijection/crm.ts
capacity
with restorePerSecond or restorePerMinute instead, and optionally
requestCost and the response fields under stated where the provider reports
its own figures.
backoff declares where the provider states when it will accept another
request, such as a Retry-After header on a 429:
bijection/crm.ts
maxWaitSeconds holds the connection until an operator
resumes it. A stated wait never makes Bijection resend a command.