Skip to content

Latest commit

 

History

History
455 lines (334 loc) · 9.29 KB

File metadata and controls

455 lines (334 loc) · 9.29 KB

Rekurn TypeScript SDK

This guide shows how to add @reeveskeefe/rekurn-sdk to a website, API route, server job, or integration. It is separate from the CLI command guide because the SDK is for application code, not terminal workflows.

Current package version for the next npm publish:

npm install @reeveskeefe/rekurn-sdk@0.2.8

Package facts:

  • ESM-only.
  • Dependency-free at runtime.
  • Includes TypeScript declarations.
  • Uses fetch.
  • Requires HTTPS by default.
  • Supports request timeouts, retries, 429 backoff, and sanitized API errors.

What You Need

You need:

  • A Rekurn API site, such as https://your-site.com.
  • A bearer token for that site.
  • A repository owner ID or username.
  • A repository name.

Do not expose write-capable Rekurn tokens in browser code. Use the SDK in server-side code for authenticated operations.

Install

npm install @reeveskeefe/rekurn-sdk@0.2.8

Other package managers:

pnpm add @reeveskeefe/rekurn-sdk@0.2.8
yarn add @reeveskeefe/rekurn-sdk@0.2.8

Configure Environment Variables

For a server-rendered site or API route:

REKURN_BASE_URL=https://your-site.com
REKURN_TOKEN=your-token
REKURN_OWNER=your-username-or-owner-id
REKURN_REPO=my-repo

Keep .env and .env.* ignored. Rekurn’s default .rekurnignore already ignores them for new files.

Create A Client

import { RekurnClient } from '@reeveskeefe/rekurn-sdk'

export const rekurn = new RekurnClient({
  baseUrl: process.env.REKURN_BASE_URL!,
  token: process.env.REKURN_TOKEN,
  timeoutMs: 30_000,
  retries: 2,
})

baseUrl is the origin of the site running Rekurn. Do not include /api/v1; the SDK adds that path.

Correct:

new RekurnClient({ baseUrl: 'https://your-site.com' })

Incorrect:

new RekurnClient({ baseUrl: 'https://your-site.com/api/v1' })

Next.js Example

Use the SDK in a Server Component or Route Handler.

// app/api/rekurn/commits/route.ts
import { NextResponse } from 'next/server'
import { RekurnClient } from '@reeveskeefe/rekurn-sdk'

const rekurn = new RekurnClient({
  baseUrl: process.env.REKURN_BASE_URL!,
  token: process.env.REKURN_TOKEN,
})

export async function GET() {
  const owner = process.env.REKURN_OWNER!
  const repo = process.env.REKURN_REPO!
  const { commits } = await rekurn.commits.list(owner, repo, { n: 10 })

  return NextResponse.json({ commits })
}

Call it from the browser through your own route:

const res = await fetch('/api/rekurn/commits')
const data = await res.json()

This keeps the token on the server.

Express Example

import express from 'express'
import { RekurnClient } from '@reeveskeefe/rekurn-sdk'

const app = express()
const rekurn = new RekurnClient({
  baseUrl: process.env.REKURN_BASE_URL!,
  token: process.env.REKURN_TOKEN,
})

app.get('/rekurn/refs', async (_req, res, next) => {
  try {
    const refs = await rekurn.refs.list(
      process.env.REKURN_OWNER!,
      process.env.REKURN_REPO!,
    )
    res.json(refs)
  } catch (err) {
    next(err)
  }
})

Browser Usage

The SDK can run anywhere fetch exists, but browser usage should be read-only unless your app issues short-lived scoped tokens.

Safer browser pattern:

// Browser calls your API route.
const refs = await fetch('/api/rekurn/refs').then((res) => res.json())

Avoid:

new RekurnClient({
  baseUrl: 'https://your-site.com',
  token: 'long-lived-write-token',
})

Local Development

The SDK rejects plain HTTP by default. For a local Rekurn API:

const rekurn = new RekurnClient({
  baseUrl: 'http://localhost:3000',
  token: process.env.REKURN_TOKEN,
  allowInsecureHttp: true,
})

Only localhost and 127.0.0.1 are allowed with allowInsecureHttp.

Authentication

Pass a bearer token when constructing the client:

const rekurn = new RekurnClient({
  baseUrl: process.env.REKURN_BASE_URL!,
  token: process.env.REKURN_TOKEN,
})

Or set it later:

rekurn.setToken(newToken)

Use setToken when your app refreshes sessions or receives a token from a secure server-side auth flow.

Error Handling

The SDK throws RekurnApiError for API responses that are not successful.

import { RekurnApiError } from '@reeveskeefe/rekurn-sdk'

try {
  const repo = await rekurn.repos.get(owner, repoName)
  console.log(repo)
} catch (err) {
  if (err instanceof RekurnApiError) {
    console.error(err.status, err.code, err.message)
  } else {
    console.error(err)
  }
}

The SDK retries transient responses:

  • 408
  • 429
  • 5xx

For 429, it honors Retry-After when present.

Common Workflows

List Repositories

const repos = await rekurn.repos.list()

Create A Repository

const repo = await rekurn.repos.create({
  name: 'my-site',
  description: 'Website releases',
  visibility: 'private',
  defaultBranch: 'main',
})

Read Refs

const { refs } = await rekurn.refs.list(owner, repo)
const main = refs.find((ref) => ref.name === 'heads/main')

Update A Ref

Use expectedHash when you want compare-and-swap behavior.

await rekurn.refs.update(owner, repo, 'heads/main', {
  commitHash: newCommitHash,
  expectedHash: previousCommitHash,
})

Delete A Ref

await rekurn.refs.delete(owner, repo, 'heads/old-branch')

List Commits

const { commits } = await rekurn.commits.list(owner, repo, { n: 20 })

Get One Commit

const commit = await rekurn.commits.get(owner, repo, commitHash)

Commit objects may include deletedPaths when deletion tombstones are available:

for (const path of commit.deletedPaths ?? []) {
  console.log('deleted', path)
}

Object Want/Have Negotiation

Use this before upload to avoid sending objects the remote already has.

const { missing } = await rekurn.objects.want(owner, repo, [
  commitHash,
  treeHash,
  blobHash,
])

Upload One Object

Object data must be base64-encoded serialized Rekurn object bytes.

await rekurn.objects.upload(owner, repo, hash, base64Data)

Upload Objects In A Batch

await rekurn.objects.uploadBatch(owner, repo, [
  { hash: commitHash, data: commitBase64 },
  { hash: treeHash, data: treeBase64 },
])

Download One Object

const object = await rekurn.objects.download(owner, repo, hash)
const bytes = Buffer.from(object.data, 'base64')

Download Objects In A Batch

const batch = await rekurn.objects.downloadBatch(owner, repo, hashes)

for (const object of batch.objects) {
  const bytes = Buffer.from(object.data, 'base64')
}

for (const missingHash of batch.missing) {
  console.warn('missing', missingHash)
}

Stream An Object

const stream = await rekurn.objects.downloadStream(owner, repo, hash)

if (stream) {
  const reader = stream.getReader()
  // Read chunks from reader.
}

Manage Deploy Hooks

await rekurn.deploy.setHooks(owner, repo, {
  production: 'https://example.com/deploy/prod',
  preview: 'https://example.com/deploy/preview',
})

const hooks = await rekurn.deploy.getHooks(owner, repo)

Record A Deployment

await rekurn.deploy.record(owner, repo, {
  commitHash,
  env: 'production',
  status: 'ready',
  externalDeploymentId: 'vercel-deployment-id',
  externalUrl: 'https://my-site.vercel.app',
  notes: 'Deployed from CI',
})

List Deployments

const deployments = await rekurn.deploy.list(owner, repo)

Read Audit Events

const events = await rekurn.audit.list(owner, repo)

Complete API Surface

rekurn.repos.list()
rekurn.repos.create({ name, description?, visibility?, defaultBranch? })
rekurn.repos.get(ownerId, name)
rekurn.repos.delete(ownerId, name)

rekurn.refs.list(ownerId, repo)
rekurn.refs.update(ownerId, repo, refName, { commitHash, expectedHash?, isImmutable? })
rekurn.refs.delete(ownerId, repo, refName)

rekurn.commits.list(ownerId, repo, { n? })
rekurn.commits.get(ownerId, repo, hash)

rekurn.objects.want(ownerId, repo, hashes)
rekurn.objects.upload(ownerId, repo, hash, data)
rekurn.objects.uploadBatch(ownerId, repo, objects)
rekurn.objects.download(ownerId, repo, hash)
rekurn.objects.downloadBatch(ownerId, repo, hashes)
rekurn.objects.downloadStream(ownerId, repo, hash)

rekurn.deploy.getHooks(ownerId, repo)
rekurn.deploy.setHooks(ownerId, repo, deployHooks)
rekurn.deploy.list(ownerId, repo)
rekurn.deploy.record(ownerId, repo, input)

rekurn.audit.list(ownerId, repo)

rekurn.setToken(token)
rekurn.raw(method, path, body?)
rekurn.request<T>(method, path, body?)

Type Reference

Important exported types:

import type {
  RekurnClientOptions,
  CommitObject,
  Ref,
  RepoSummary,
  CreateRepoInput,
  CommitListOptions,
  UpdateRefInput,
  ObjectDownload,
  ObjectBatchItem,
  ObjectBatchDownload,
  DeployHooksResponse,
  CreateDeploymentInput,
  DeploymentRecord,
  AuditEvent,
} from '@reeveskeefe/rekurn-sdk'

Deployment Checklist

Before shipping SDK usage in your site:

  • Keep REKURN_TOKEN server-side.
  • Use HTTPS baseUrl.
  • Set a timeout that fits your route runtime.
  • Catch RekurnApiError.
  • Use expectedHash when updating refs.
  • Batch object downloads and uploads when transferring many objects.
  • Do not commit .env files.

Related Documentation

  • CLI commands: docs/cli-commands.md
  • Deployment hooks: docs/deployment-hooks.md
  • Push security: docs/push-security.md
  • Security practices: docs/security.md