Scrydon
Client SDK

TypeScript / JavaScript SDK

The official TypeScript / JavaScript client SDK for Scrydon — OAuth/PKCE auth and a typed surface for workflows, knowledge, storage, chat, and webhooks

@scrydon/sdk is the official client SDK for browser, TanStack Start / Next.js, and Node.js apps. It authenticates end-users through OAuth 2.0 with PKCE and exposes typed modules for workflows, chat, knowledge, storage, and webhooks, plus the platform data / ai / action SDK surface.

This SDK is for first-party apps acting on behalf of a user (OAuth flow). For server-to-server execution with a static API key — backends, cron jobs, CI — call the workflow API directly with x-api-key (see Execution).

Installation

bun add @scrydon/sdk
npm install @scrydon/sdk
yarn add @scrydon/sdk

Quick Start

import { ScrydonClient } from '@scrydon/sdk'

const client = new ScrydonClient({
  baseUrl: 'https://scrydon.com',
  clientId: 'your-oauth-client-id',
  redirectUri: 'https://your-app.com/auth/callback',
})

// 1. Start the OAuth/PKCE flow — returns the authorization URL
const authUrl = await client.auth.signIn()
window.location.assign(authUrl)

// 2. On your callback page, exchange the code for a session
const session = await client.auth.handleCallback() // reads window.location by default

// 3. Call typed APIs
const result = await client.workflows.trigger({
  workflowId: 'wf_…',
  inputs: { message: 'Hello, world!' },
})
console.log(result.executionId, result.status, result.outputs)

Authentication — OAuth 2.0 + PKCE

The SDK uses the PKCE flow so it's safe in browsers without a client secret. The verifier is held in sessionStorage (browser) or in-memory (other runtimes).

auth.signIn()

const authUrl = await client.auth.signIn()
// Redirect the user to authUrl. After consent they come back to redirectUri
// with ?code=… and ?state=… in the query string.

auth.handleCallback(callbackUrl?)

// On the callback route — defaults to window.location.href
const session = await client.auth.handleCallback()
// session: { user: { id, email, name? }, accessToken, expiresAt }

auth.getSession()

const session = await client.auth.getSession() // null if signed out / expired

auth.signOut()

await client.auth.signOut()

auth.onAuthStateChange(cb)

const unsubscribe = client.auth.onAuthStateChange((session) => {
  if (session) {
    console.log('signed in as', session.user.email)
  } else {
    console.log('signed out')
  }
})
// Later: unsubscribe()

client.workflows

trigger(options) — synchronous

const result = await client.workflows.trigger({
  workflowId: 'wf_abc',
  inputs: { message: 'Hello' },
})
// result: { executionId, status, outputs? }

POST /api/v1/workflows/{workflowId}/trigger. Best for short-running workflows that respond inline.

triggerAsync(options) — fire and poll

const { executionId } = await client.workflows.triggerAsync({
  workflowId: 'wf_abc',
  inputs: { message: 'Long task' },
})

// Poll for status when you're ready
const result = await client.workflows.getStatus(executionId)
// result: { executionId, status: 'running' | 'completed' | 'failed', outputs? }

POST /api/v1/workflows/{workflowId}/trigger?async=true. Use for long-running workflows.

getStatus(executionId)

const result = await client.workflows.getStatus(executionId)

GET /api/v1/workflows/executions/{executionId}.

client.chat

Streaming chat against a deployed chat surface.

for await (const chunk of client.chat.stream({
  deploymentId: 'chat_abc',
  message: 'Summarize Q3',
})) {
  process.stdout.write(chunk)
}

client.knowledge

const hits = await client.knowledge.query({
  question: 'What is our refund policy?',
  topK: 5,
})
// hits: Array<{ content, source, score }>

await client.knowledge.ingest({
  documents: [file1, file2],
  collection: 'policies',
})

client.ontology

Map-ready geo layers projected from your ontology — one layer per object type whose instances carry coordinates (latitude/lat, longitude/lng/lon). Omit all options to discover every mappable type across your readable ontologies; pass objectTypes to narrow.

const layers = await client.ontology.queryGeo({
  objectTypes: ['Aircraft', 'MilitaryBase'], // optional — omit to discover
  ontologySlug: 'my-domain', // optional — omit to search all
  limit: 300, // max instances per type (1–1000)
})
// layers: Array<{ objectTypeSlug, label, features }>
// features: Array<{ id, lat, lng, label, properties }>

Geo is a dedicated projection rather than a generic instance query: coordinate extraction, range validation, and binding traversal run server-side, so the client receives render-ready features.

client.storage

const { url } = await client.storage.upload(file, { path: 'reports/q3.pdf' })

const directLink = await client.storage.getUrl('reports/q3.pdf')

client.webhooks

A simple in-process event emitter for delivering webhook payloads to subscribers in your app.

const off = client.webhooks.on('workflow.completed', (data) => {
  console.log('workflow completed', data)
})
// Later: off()

Platform SDK — client.data, client.ai, client.action

The client exposes the platform's typed ScrydonSDK:

  • client.data.knowledge.search(...), client.data.memex.query(...), client.data.storage.read(...), client.data.memory.add(...) — read / write the workspace data surface
  • client.ai.llm.complete(...) — capability-resolved LLM calls
  • client.action.workflow.execute(...), client.action.email.send(...), client.action.sms.send(...), client.action.functionExecute(...) — server-side actions

See @scrydon/sdk/types for the full set of platform types.

Errors

import {
  ScrydonAuthError,
  ScrydonForbiddenError,
  ScrydonRateLimitError,
  ScrydonValidationError,
  ScrydonServerError,
  ScrydonError,
} from '@scrydon/sdk'

try {
  await client.workflows.trigger({ workflowId: 'wf_abc' })
} catch (err) {
  if (err instanceof ScrydonAuthError) {
    // 401 — token expired or invalid; redirect to signIn()
  } else if (err instanceof ScrydonForbiddenError) {
    // 403 — user lacks permission for this workflow
  } else if (err instanceof ScrydonRateLimitError) {
    // 429 — err.retryAfter seconds
  } else if (err instanceof ScrydonValidationError) {
    // 400 — err.details has the Zod issues
  } else if (err instanceof ScrydonServerError) {
    // 5xx — retry with backoff
  } else if (err instanceof ScrydonError) {
    // Other 4xx — err.code, err.status
  }
}

React

@scrydon/sdk/react ships hooks for the common flows:

import { ScrydonProvider, useAuth, useWorkflow } from '@scrydon/sdk/react'

function App() {
  return (
    <ScrydonProvider config={{ baseUrl, clientId, redirectUri }}>
      <Page />
    </ScrydonProvider>
  )
}

function Page() {
  const { session, signIn, signOut } = useAuth()
  const { trigger, result, loading, error } = useWorkflow('wf_abc')

  if (!session) return <button onClick={signIn}>Sign in</button>

  return (
    <div>
      <button onClick={() => trigger({ message: 'Hello' })} disabled={loading}>
        Run workflow
      </button>
      {result && <pre>{JSON.stringify(result.outputs, null, 2)}</pre>}
    </div>
  )
}

TanStack Start / Next.js callback route

// /auth/callback page
import { ScrydonClient } from '@scrydon/sdk'

const client = new ScrydonClient({
  baseUrl: import.meta.env.VITE_SCRYDON_BASE_URL,
  clientId: import.meta.env.VITE_SCRYDON_CLIENT_ID,
  redirectUri: `${window.location.origin}/auth/callback`,
})

export function CallbackPage() {
  useEffect(() => {
    client.auth
      .handleCallback()
      .then(() => router.navigate({ to: '/' }))
      .catch((err) => console.error('OAuth callback failed', err))
  }, [])
  return <p>Signing you in…</p>
}

Backend / server-to-server

@scrydon/sdk is built around an end-user OAuth flow. For backend processes that need to execute workflows on behalf of the platform (cron, CI, internal services), call the API directly:

curl -X POST "https://scrydon.com/api/workflows/{workflowId}/execute" \
  -H "x-api-key: $SCRYDON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": "…"}'

API keys are issued during the deploy flow (see Execution). They are the right tool for server contexts where there is no end user.

Requirements

  • Node.js 18+ (for fetch + atob globals)
  • TypeScript 5.0+ for full types
  • A browser-like environment for the React module

License

Apache-2.0

On this page

On this page