@latrinebot/sdk
v0.5.0
Published
TypeScript client and OpenAPI 3.1 spec for the Latrine Bot public API.
Maintainers
Readme
@latrinebot/sdk
TypeScript client and OpenAPI 3.1 specification for the Latrine Bot public API at api.latrinebot.com.
Part of the
dfnwtf/latrinebotmonorepo. See the root README for the docs, widgets, calculator, and CLI.
npm install @latrinebot/sdkZero runtime deps. Works in Node 18+, browsers, Workers, Deno, Bun. Ships ESM and CJS, with full TypeScript types.
Getting credentials
The SDK talks to two surfaces of the API. Each has its own auth model.
Project ID
A UUID like 789caa12-7411-4754-b1dd-5a637cbe8a9f. You get one when you create a project in the dashboard. The dashboard URL while a project is open is https://latrinebot.com/app/?project=<id> - that's the value to pass into the SDK.
Metrics key (lb_live_...) - read-only
Use this for client.metrics.* (status, stats, events, stream) and client.public.*. It is per-project, read-only, and safe to ship in server-side scripts and dashboards. Do not put it in a public client bundle.
- Open your project in the dashboard
- Go to the API tab (or Metrics keys section)
- Click Generate metrics key, give it a label (e.g.
ci-monitor,grafana) - Copy the
lb_live_...value - it is shown once
const client = new LatrineClient({ metricsKey: process.env.LATRINE_METRICS_KEY });You can also rotate or revoke keys from the same screen, or programmatically via client.keys.* after you authenticate.
Bearer JWT - full session
Use this for client.projects.*, client.lifecycle.* (start, stop, run-once, preflight), and any other authenticated route. Two ways to get one:
Programmatic (Sign-in with Solana):
import { LatrineClient } from "@latrinebot/sdk";
const client = new LatrineClient();
const { message } = await client.auth.challenge(walletPubkey);
const signature = await wallet.signMessage(new TextEncoder().encode(message));
const { token } = await client.auth.verify({ wallet: walletPubkey, signature });
client.useBearer(token);From the dashboard (for one-off scripts):
After you sign in to latrinebot.com/app, open DevTools → Application → Cookies (or Local Storage). The session token is also returned by POST /api/auth/verify if you intercept it. Save it as LATRINE_TOKEN and use:
const client = new LatrineClient({ token: process.env.LATRINE_TOKEN });JWTs expire (rolling 7 days by default). For long-running scripts, repeat the SiwS flow when you get a LatrineError with code === "auth_invalid".
Fully public (no auth)
client.public.checkEligibility(...), share-card bundles, and widget config / live endpoints don't need any credential. Useful for build steps and embeddable third-party pages.
Quick start
Read-only (with a metrics key)
import { LatrineClient } from "@latrinebot/sdk";
const client = new LatrineClient({
metricsKey: process.env.LATRINE_METRICS_KEY,
});
const stats = await client.metrics.get("YOUR_PROJECT_ID");
console.log(stats.stats.totalClaimedSol, "SOL claimed total");
const events = await client.metrics.events("YOUR_PROJECT_ID", { limit: 25 });
for (const ev of events.events) {
console.log(ev.ts, ev.kind, ev.detail);
}Authenticated session (Sign-in with Solana)
import { LatrineClient } from "@latrinebot/sdk";
const client = new LatrineClient();
const { message } = await client.auth.challenge(walletPubkey);
const signature = await wallet.signMessage(new TextEncoder().encode(message));
const { token } = await client.auth.verify({
wallet: walletPubkey,
signature,
});
client.useBearer(token);
const projects = await client.projects.list();Public eligibility check (no auth)
import { LatrineClient } from "@latrinebot/sdk";
const client = new LatrineClient();
const res = await client.public.checkEligibility("PROJECT_ID", {
wallet: "SomeWalletPubkey",
});
if (!res.eligible) console.log("rejected because:", res.reason);What this SDK covers
| API surface | Methods on the client |
|---|---|
| Discovery | client.health(), client.version() |
| Auth | client.auth.* (challenge, verify, OAuth, me, logout) |
| Projects | client.projects.* (list, get, create, patch, delete, tiers reset) |
| Credentials | client.credentials.* (save, get metadata, test RPC) |
| Lifecycle | client.lifecycle.* (preflight, status, stats, events, start, stop, runOnce, stream) |
| Widgets (CRUD) | client.widgets.* (list, get, create, patch, put, delete) |
| Share card | client.share.* (bundle, caption, png, postX) |
| Metrics (read-only) | client.metrics.* (get, events, stream) |
| Public | client.public.* (widget config + live, realm live, share-card, check-eligibility) |
Admin endpoints, internal cycle endpoints, runner endpoints, and anything that handles raw secrets are not in this SDK and never will be. See the security docs.
OpenAPI
The same surface is available as a static openapi.yaml (OpenAPI 3.1). Use it to:
- Generate clients for other languages (
openapi-generator-cli) - Drive Postman or Insomnia collections
- Validate requests in a gateway
npm pack @latrinebot/sdk
tar -xOzf latrinebot-sdk-*.tgz package/openapi.yaml > openapi.yamlOr fetch it directly from this repo.
Errors
All HTTP errors are thrown as LatrineError with a stable code:
import { LatrineClient, LatrineError } from "@latrinebot/sdk";
try {
await client.lifecycle.start("PROJECT_ID");
} catch (err) {
if (err instanceof LatrineError && err.code === "preflight_blocked") {
console.log("Fix these checks first:", err.fields);
} else {
throw err;
}
}error.code values are documented in docs/api-reference.md#errors.
Versioning
This package tracks the service version (currently 0.4.3). Pre-1.0 the minor bump may add fields and endpoints. Breaking changes are listed in CHANGELOG.md under Breaking.
License
MIT - see the root LICENSE.
