Local development
Installing the SDK, running a sync on your machine with the beetl-connect CLI, and packing.
You can build and run a Connect package entirely on your machine. The beetl-connect CLI that
ships with the SDK compiles your integration, asks for its settings and credentials, runs a sync
against the real API, and writes the records to a local file. Nothing touches your Beetl tenant
until you upload the package.
You need Node.js 24.2 or newer and npm.
Set up a project
A package is an npm project with an integration.ts at its root. There is no scaffolding command,
so create the files yourself. In a new directory, add package.json:
{
"name": "my-integration",
"version": "0.1.0",
"private": true,
"type": "module",
"files": ["integration.ts"]
}"type": "module" and the files allowlist are required. Every file the package needs at run
time, including an icon or extra .ts modules, must be listed in files.
Install the SDK. It is open source under Apache-2.0, and the source lives at github.com/beetlio/connect.
npm install --save-dev @beetlio/connectThis also writes package-lock.json. Keep it: packing requires it, and Beetl installs exactly the
versions it locks.
Then create integration.ts. The smallest working integration reads one record from a public API:
import { defineIntegration, z } from "@beetlio/connect";
const User = z.object({ id: z.number(), login: z.string() });
export default defineIntegration({
key: "github",
displayName: "GitHub",
connection: { origin: "https://api.github.com" },
syncs: (sync) => ({
users: sync({
mode: "replace",
records: User,
async *run(ctx) {
const user = await ctx.json("/users/octocat", User);
yield { records: [user] };
},
}),
}),
});Authoring a sync builds a fuller example with credentials, settings and incremental reads.
The CLI writes state and output files into the project directory. Keep them out of version control:
node_modules/
.beetl/
*.ndjsonConfigure a sync
configure collects the connection's settings, the sync's settings and the credentials, then saves
them as a local profile:
npx beetl-connect configure . usersThe first argument is the package directory and the second is the sync key. You can leave out the sync key when the package has only one sync.
The CLI prompts for each field the manifest declares. Secret fields are masked as you type, and
credential prompts need an interactive terminal. If the connection defines verify, configure
runs it before saving, so a wrong key or URL fails here rather than halfway through a sync. For
OAuth, the CLI prints an authorization URL to open in your browser.
To skip the settings prompts, pass the values as one JSON object with a connection and a sync
part. This example uses the tickets sync from Authoring a sync:
npx beetl-connect configure . tickets --profile demo \
--inputs '{"connection":{"baseUrl":"https://acme.example"},"sync":{"pageSize":50}}'| Option | What it does |
|---|---|
--profile NAME | Saves the sync's settings under a named profile. The default is default. |
--connection NAME | Saves the connection under a name, so several profiles can share it. The default is default. |
--origin URL | Sends requests to a different base URL, such as a local mock server. |
--inputs JSON | Supplies connection and sync settings without prompting. |
--reauthorize | Asks for credentials again, or repeats the OAuth authorization. |
Profiles and connections are stored in your operating system's user configuration directory. Credentials in those files are readable only by your user account, but they are not encrypted.
Run a sync
npx beetl-connect sync . users --output users.ndjsonsync uses the saved profile, or runs configure first if there is none. It compiles the
package, runs the sync, and prints a summary such as Emitted 5 records in 4 batches. Messages
your code writes with ctx.log go to stderr as JSON lines. Press Ctrl+C to stop a run.
| Option | What it does |
|---|---|
--profile NAME | Runs with a named profile. |
--output PATH | Where to write records. By default the CLI writes a timestamped .ndjson file in the current directory. |
--state PATH | Where to keep the checkpoint. |
What the output file contains depends on the sync's write mode. Append
and Replace syncs write one record per line, and a Replace sync only writes the file once the run
succeeds. A Merge sync writes one line per batch, with that batch's records and any
deletedKeys.
Checkpoints between runs
If the sync declares a checkpoint, the CLI saves the latest one under .beetl/state/ and passes
it to the next run, so a second sync reads incrementally. The default location is tied to the
compiled package and the profile, so after you edit the code or change settings the next run
starts without a checkpoint. To keep one checkpoint across code changes, pass the same --state
path each time. To start over, delete the state file.
Test against a mock API
To exercise pagination, errors or empty pages without a real account, run a small HTTP server on your machine and point a separate connection at it:
npx beetl-connect configure . tickets --profile mock --connection mock \
--origin http://127.0.0.1:4010
npx beetl-connect sync . tickets --profile mock --output mock.ndjsonUsing its own --connection keeps the mock's base URL and credentials apart from the connection
you use against the real API.
Authenticated connections require HTTPS, with one exception for loopback addresses such as
127.0.0.1 and localhost, so a plain HTTP mock server works.
The CLI runs your code directly on your machine with your network access. Run only integration code you trust. In Beetl, the same code runs with narrower access; see The sandbox.
Check the package before you pack
configure and sync build the package the way Beetl does: they compile integration.ts with
strict TypeScript settings, load it, and validate the definition and the manifest derived from it.
Type errors, an invalid key, a settings object that is not a z.strictObject(), or a Merge sync
without a primary key all fail at this step, with an error that names the problem.
There is no separate validate command, and pack neither compiles nor runs your code. Run a sync
after your last change and before you pack, so a mistake shows up on your machine instead of as a
failed build in Beetl.
Pack
npx beetl-connect pack . --output my-integration.tgzpack prints every file it included. Read that list before you hand the file to a TenantAdmin.
The rules a package must meet, and the upload steps, are on Pack and upload.
Every command has --help, for example npx beetl-connect sync --help.
Last updated on