@withone/sdk
v0.0.4
Published
The One SDK for Node — typed client over the One API.
Readme
@withone/sdk
The One SDK for Node — a typed client over the One API.
It is a thin, typed binding over the Rust one client: every typed action and
its route/credential handling is generated from and executed by Rust. The
JavaScript layer adds no behavior — HTTP, retries, route templating, and
the merge/remove overrides all run in the native client.
Install
pnpm add @withone/sdkNo build step, no toolchain. The package ships prebuilt native binaries per
platform (linux-x64-gnu, linux-arm64-gnu, linux-x64-musl, darwin-x64,
darwin-arm64, win32-x64-msvc) as optionalDependencies; your package
manager installs only the one matching your machine. Node only (≥ 18).
Usage
import { One, gmail } from '@withone/sdk'
const one = new One(process.env.ONE_SECRET!)
const res = await one
.connection('my-gmail-connection')
.run(
gmail.createUsersDraft({
path: { userId: 'me' },
body: { message: { raw: base64Email } },
}),
)
console.log(res.status, res.data)- Typed inputs. Each action exposes exactly the fields it needs. Required
route variables (e.g.
userId) are required fields — omit one and it does not compile. Const headers the action requires are injected for you, never asked. - Connections.
one.connection(key)scopes a call to a connection; the key is sent asX-One-Connection-Key. - From the environment.
One.fromEnv()readsONE_SECRETand the optionalONE_BASE_URL.
Overrides
When an action's typed surface isn't enough, chain escape hatches. These only
collect directives — they are applied by the Rust Operation:
one.connection(key).run(
gmail
.createUsersDraft({ path: { userId: 'me' }, body })
.mergeBody({ fieldTheSchemaOmits: 1 }) // add body fields
.mergeQuery({ debug: true })
.mergeHeaders({ 'X-Trace': 'abc' })
.removeHeader('X-One-Secret')
.removeQuery('page')
.rawBody(new Uint8Array(bytes)), // non-JSON payload
)Raw calls
Every action is also reachable generically (useful for actions the typed surface skips). Construct the request yourself and pass it through:
import { One } from '@withone/sdk'
// one.connection(key).run(...) accepts any built ActionHow it's built
There is a single source of truth: the committed action snapshots
(one/actions/*.json). The Rust one-codegen crate normalizes them once
(const-hiding, envelope naming, Handlebars route-variable extraction) and emits
both the Rust typed client and a manifest. This package translates that manifest
into the typed TypeScript surface, so the two clients cannot drift.
Development
pnpm install
pnpm run build # native addon + typed actions + bundleIndividual steps:
| script | does |
| --- | --- |
| build:native | compiles the napi addon (native.js / native.d.ts / *.node) |
| manifest | runs the Rust one-codegen-manifest binary → actions.manifest.json |
| gen | manifest + generates src/generated/<platform>.ts |
| build:ts | tsup → dist/ (ESM + CJS + types) |
A quick end-to-end check: node scripts/smoke.mjs.
