📦 @orkait/sdk#
Typed, zero-dependency TypeScript client for the Gatekeeper API.
Runs anywhere fetch exists - Node 18+, browsers, Cloudflare Workers.
🚀 Usage#
Construct a GatekeeperCore once, then plug in only the services you need - each is a standalone class over the same core, so unused services tree-shake away.
import {
GatekeeperCore,
AuthService,
KeysService,
BillingService,
isMfaChallenge,
} from '@orkait/sdk';
const core = new GatekeeperCore({ baseUrl: 'https://gatekeeper-api.example.workers.dev' });
// Auth
const auth = new AuthService(core);
const { accessToken } = await auth.signup({ email: 'a@b.com', password: 'hunter2pass' });
core.setToken(accessToken);
const me = await auth.me();
// MFA - if login returns a challenge instead of tokens, complete it
const login = await auth.login({ email: 'a@b.com', password: 'hunter2pass' });
if (isMfaChallenge(login)) {
// const mfa = new MfaService(core);
// await mfa.verifyChallenge(login.challengeToken, '123456');
}
// API keys
const keys = new KeysService(core);
const { plainTextKey } = await keys.create({ tenantId: 't1', scopes: ['read'] });
// Billing
const billing = new BillingService(core);
const plans = await billing.plans();🧩 Design#
| Property | Detail |
|---|---|
| Composition | new XService(core) - each service depends only on core.request() / core.requestText() |
| Core | holds baseUrl, bearer token (mutable via core.setToken()), and the fetch impl |
| Custom transport | pass options.fetch (a Workers service binding, a test SELF.fetch, a mock) |
| Dependencies | none (uses global fetch) |
| Tree-shaking | root named exports + sideEffects: false - unused services drop from the bundle |
| Errors | non-ok responses throw GatekeeperError with .status; .retryAfter holds the Retry-After seconds on 429 |
| Envelope | unwraps the API's { ok, data, error } automatically - methods return data |
⚙️ Configuration#
Global config on the core, per-service defaults on the service (overridable per call):
const core = new GatekeeperCore({
baseUrl,
token,
timeoutMs: 10_000,
defaultHeaders: { 'x-trace': 'abc' },
userAgent: 'myapp/1.0',
});
// or from env: GATEKEEPER_BASE_URL + GATEKEEPER_TOKEN
const core2 = GatekeeperCore.fromEnv();
// per-service defaults
const keys = new KeysService(core, { defaultScopes: ['read'], defaultQuotaPeriod: 'month' });
const audit = new AuditService(core, { defaultFormat: 'csv' });
const tenants = new TenantsService(core, { defaultRole: 'admin' });Constants ship with their service: QUOTA_PERIODS, AUDIT_EXPORT_FORMATS, TENANT_ROLES.
🔌 Services#
| Service | What it does |
|---|---|
AuthService | signup, login, refresh, password reset, MFA login |
TenantsService | create tenants, manage members |
MfaService | TOTP enroll / verify / disable |
KeysService | API keys: create, validate, JWT exchange |
UsageService | quota checks + metered usage |
PermissionsService | tenant RBAC roles + checks |
WebhooksService | endpoints, dispatch, deliveries |
AuditService | record / query / export audit log |
BillingService | plans, entitlements, invoice, payment providers + checkout |
OAuthService | provider authorize + callback |
RateLimitService | standalone rate-limit check |
PlatformBillingService | platform: override a tenant's subscription |
PlatformJobsService | platform: list / inspect / retry background jobs |
PlatformServiceAccountsService | platform: create / list / revoke service accounts |
Each maps one-to-one to an API route group, fully typed. Construct any subset over a shared GatekeeperCore. Per-service usage + methods: click a service above.