The contract rule
What is fixed once a connection type is installed, and how to ship a change as a new connection type.
When a TenantAdmin installs a package, its manifest becomes the connection type's contract. Connections, saved credentials and syncs are created against that contract, and each sync's dataset takes its schema from it. An installed connection type stays as it is: to ship any change to a package, install the new version as a new connection type and move your connections and syncs to it.
What the contract covers
The manifest is generated from your defineIntegration call when the package is built.
The local configure and sync commands build it too; pack only creates the source archive. These are
the parts that connections, syncs and datasets depend on:
| Part | Where it comes from |
|---|---|
| Integration key | key |
| Provider origin | connection.origin |
| Authentication | connection.auth: the auth type, its options (such as OAuth endpoints and scopes, or a token exchange request) and its credential fields |
| Connection settings | connection.inputs |
| Verification | Whether connection.verify is defined |
| The list of syncs | The keys under syncs |
| Sync settings | Each sync's inputs |
| Record schema | Each sync's records |
| Checkpoint schema | Each sync's checkpoint |
Schemas are recorded as the JSON Schema the SDK generates from your Zod schemas, so field labels,
descriptions and defaults set with .meta() or .default() are part of the contract too.
A sync's write mode is not part of the contract. The person who adds a sync chooses Append or Replace, and can change it later. See Write modes.
Decide the contract early
Every change, including loosening a schema, means a new connection type and new datasets. Mark
fields the provider may omit as .optional() or .nullable() from the start, and use
storageRecord for objects whose keys vary. See SDK reference.
Test against real accounts with the local CLI before you install.
Ship a change
A new version is installed next to the old one, and connections and syncs move across.
- Give the package a
displayNamethat tells the two types apart, such asExample CRM (v2), then pack it withbeetl-connect pack. - Install it under Settings → Tenant → Custom connection types with Add custom connection type. See Pack and upload.
- Create connections of the new type. Saved credentials belong to one connection type, so enter them again.
- Add the syncs. Each writes to a new dataset, because an output link only attaches to a dataset that has never been written.
- Run the new syncs, compare their datasets with the old ones, then point your pipelines at the new datasets.
- Delete the old syncs and connections, and the saved credentials of the old type. Then delete the old connection type, which Beetl refuses while connections or saved credentials still use it. Deleting never deletes the old datasets.
A new sync starts without a checkpoint, so its first run reads from the beginning. Make sure that first run fits the per-run limits.
Packages built with an SDK older than 0.5 are not accepted at all and must be rebuilt, which also means installing them as a new connection type. See Rebuilding older packages.
Schema checks on every run
The record schema is also enforced at run time. The SDK parses each record your sync yields with
its records schema, and Beetl checks it again against the installed contract before staging it.
A record that does not match stops the run: nothing is written and the checkpoint does not advance.
To find the record and field that failed, run the sync locally with
npx beetl-connect sync . <sync>. The error names the record's position in its batch and the Zod
validation message. See Local development.
Related
Last updated on