JSPM

@tenlyr/sdk

1.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 3
  • Score
    100M100P100Q71298F
  • License MIT

Official Tenlyr SDK — provision, monitor, meter, isolate, and bill tenants in one call

Package Exports

  • @tenlyr/sdk

Readme

@tenlyr/sdk

Official TypeScript/JavaScript SDK for Tenlyr — the Tenant Infrastructure Layer for Modern SaaS.

One SDK call. Full tenant onboarded in < 200 ms.


What Tenlyr solves

Building multi-tenant SaaS means re-implementing the same infrastructure every time: provisioning, usage metering, isolation tiers, health monitoring, billing sync. Tenlyr handles all of it so you can focus on your product.


Installation

npm install @tenlyr/sdk

30-second quickstart

import { Tenlyr } from '@tenlyr/sdk';

const tenlyr = new Tenlyr({ apiKey: 'tenlyr_live_…' });

// Provision a new tenant
const { tenant, apiKey } = await tenlyr.tenants.create({
  name: 'Acme Corp',
  ownerEmail: 'ceo@acme.com',
  plan: 'growth',
  region: 'us-east-1',
});

// Track usage
await tenlyr.usage.track({
  tenantKey: apiKey,
  metric: 'api_call',
  value: 1,
});

Example SaaS flow

import { Tenlyr, TenantPlan, UsageMetric } from '@tenlyr/sdk';

const tenlyr = new Tenlyr({ apiKey: 'tenlyr_live_…' });

// 1. User signs up — provision their tenant
const { tenant, apiKey } = await tenlyr.tenants.create({
  name: 'Acme Corp',
  ownerEmail: 'ceo@acme.com',
  plan: 'growth' satisfies TenantPlan,
  region: 'us-east-1',
});

// 2. Store the tenant key in your database
await db.saveTenant({ id: tenant.id, apiKey });

// 3. Track usage on every API call
const metric: UsageMetric = 'api_call';
await tenlyr.usage.track({ tenantKey: apiKey, metric, value: 1 });

// 4. Check fleet health
const health = await tenlyr.tenants.health();
const atRisk = health.filter(t => t.slaRisk);

// 5. Upgrade a tenant's isolation tier
const migration = await tenlyr.isolation.migrate(tenant.id, {
  targetLevel: 'dedicated_schema',
});
await tenlyr.isolation.waitForMigration(migration.id);

TypeScript types

The SDK is fully typed. Key types you'll use:

import type {
  Tenant,           // Core tenant record
  TenantPlan,       // 'starter' | 'growth' | 'scale' | 'enterprise'
  TenantStatus,     // 'active' | 'suspended' | 'pending' | 'terminated'
  IsolationLevel,   // 'shared_schema' | 'dedicated_schema' | 'dedicated_database'
  UsageMetric,      // 'api_call' | 'storage_gb' | 'seats'
  HealthStatus,     // 'healthy' | 'warning' | 'critical' | 'unknown'
  AlertSeverity,    // 'low' | 'medium' | 'high' | 'critical'
  ProvisionOptions, // Input to tenants.create()
  ProvisionResult,  // { tenant: Tenant; apiKey: string }
  TenlyrConfig,     // Constructor options
} from '@tenlyr/sdk';

Configuration

const tenlyr = new Tenlyr({
  apiKey: 'tenlyr_live_…',     // required — admin key
  baseUrl: 'https://…',         // default: https://www.tenlyr.com
  timeout: 10_000,              // ms, default 10 000
  retries: 3,                   // 5xx retry count, default 3
  retryDelay: 200,              // initial back-off ms (exponential), default 200
});

API reference

tenlyr.tenants

Method Description
create(options) Provision a new tenant — returns { tenant, apiKey }
list() List all tenants (admin)
get(id) Get tenant by ID
health() All tenants with merged health, usage, and billing
update(id, fields) Update name / region
suspend(id, reason?) Suspend (preserves data)
reactivate(id) Reactivate suspended tenant
terminate(id) Permanently terminate
rotateApiKey(id) Rotate API key
changePlan(id, plan) Change billing plan
delete(id) Hard-delete tenant
const { tenant, apiKey } = await tenlyr.tenants.create({
  name: 'Acme Corp',
  ownerEmail: 'ceo@acme.com',
  plan: 'growth',    // starter | growth | scale | enterprise
  region: 'us-east-1',
});

tenlyr.usage

Method Description
track(opts) Track a usage event
metrics(tenantKey) Aggregated counters
summary(tenantKey) Current-month summary + recent events
events(tenantKey, limit?) Raw event log
await tenlyr.usage.track({
  tenantKey: apiKey,
  metric: 'api_call',    // api_call | storage_gb | seats
  value: 1,
  endpoint: '/api/data', // optional
});

tenlyr.health

Method Description
overview() Counts by status + avg error rate
list() All tenant health records
get(tenantId) Single tenant health
update(tenantId, metrics) Push error/request rate
throttle(tenantId, limitRpm) Cap noisy tenant
removeThrottle(tenantId) Remove rate cap

tenlyr.isolation

Method Description
migrate(tenantId, opts) Start isolation migration
getMigration(id) Get migration by ID
migrations(tenantKey) Migration history
waitForMigration(id, opts?) Poll until complete/failed

Isolation levels: shared_schemadedicated_schemadedicated_database

tenlyr.billing

Method Description
get(tenantKey) Billing record
portalUrl(tenantKey) Stripe customer portal URL

tenlyr.alerts

Method Description
list(key?) All alerts (admin = all tenants)
unresolved(key?) Unresolved only
create(opts, tenantKey) Create alert
resolve(alertId) Mark resolved
resolveAll(key?) Bulk resolve

Error handling

The SDK throws specific error classes so you can handle each failure mode precisely:

import {
  Tenlyr,
  TenlyrError,
  AuthenticationError,  // 401 — bad or missing API key
  PermissionError,       // 403 — key lacks permission
  NotFoundError,         // 404 — tenant or resource not found
  InvalidRequestError,   // 422 — invalid request body
  RateLimitError,        // 429 — rate limit exceeded
  TenlyrNetworkError,    // network / connectivity failure
  TenlyrTimeoutError,    // per-request timeout exceeded
} from '@tenlyr/sdk';

try {
  await tenlyr.tenants.create({ name: 'Acme', ownerEmail: 'ceo@acme.com', plan: 'growth', region: 'us-east-1' });
} catch (err) {
  if (err instanceof AuthenticationError) {
    // Invalid or revoked API key — check your tenlyr_live_… key
    console.error('Auth failed:', err.message);

  } else if (err instanceof RateLimitError) {
    // Optionally respect the server-suggested back-off
    const wait = err.retryAfter ?? 60;
    console.warn(`Rate limited — retry in ${wait}s`);

  } else if (err instanceof NotFoundError) {
    console.error('Resource not found:', err.message);

  } else if (err instanceof InvalidRequestError) {
    console.error('Bad request:', err.body);

  } else if (err instanceof TenlyrTimeoutError) {
    console.error('Request timed out');

  } else if (err instanceof TenlyrNetworkError) {
    console.error('Network failure:', err.message);

  } else if (err instanceof TenlyrError) {
    // Catch-all for any other HTTP error
    console.error(err.statusCode, err.message);
  }
}

All error classes extend TenlyrError, so instanceof TenlyrError works as a safe catch-all when you don't need granular handling.


Benchmark results (mock HTTP, pure SDK overhead)

Operation ops/sec avg (µs) p95 (µs)
billing.get() 318,227 3 5
alerts.unresolved() 316,546 3 5
usage.track() 311,163 3 4
health.throttle() 152,947 6 4
tenants.get() 142,201 7 6
health.overview() 137,854 7 6
usage.metrics() 135,495 7 6
isolation.migrate() 115,515 9 5
tenants.create() 85,104 11 9
tenants.list() 55,264 18 6
tenants.suspend() 38,800 26 6

All operations exceed 10,000 ops/sec. SDK overhead is negligible — network RTT dominates in production.


License

MIT