Skip to content

nexical/sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Nexical SDK Reference

The Nexical SDK (@nexical/sdk) is the official TypeScript library for interacting with the Nexical Orchestrator. It provides a typed, robust interface for managing users, teams, projects, and executing jobs.

This SDK is designed for four primary developer personas:

  1. Browser Extension Developers: Building tools to monitor and trigger jobs.
  2. Web Application Developers: Building management interfaces or dashboards.
  3. Factory Worker Developers: Building custom job execution runtimes (workers).
  4. Remote Agent Developers: Building AI agents running inside job containers.

Installation

npm install @nexical/sdk
# or
yarn add @nexical/sdk


1. Getting Started

Initialize the client with your access token.

import { NexicalClient } from '@nexical/sdk';

// Initialize with a static token (e.g., from environment or local storage)
const client = new NexicalClient({
    token: 'nx_abc123...', // API Token or JWT
});

1.1 Authentication Deep Dive

The SDK supports multiple authentication strategies depending on your runtime environment.

A. API Tokens (Long-Lived)

Best for: CI/CD pipelines, Backend Scripts, Web Servers.

  1. Log in to the Nexical Dashboard.
  2. Navigate to Settings > API Tokens.
  3. Click "Generate New Token" and select scope (e.g., read, write).
  4. Copy the token (starts with nx_...) and store it securely (e.g., .env).
const client = new NexicalClient({
    token: process.env.NEXICAL_API_TOKEN
});

B. Worker Enrollment (Automated)

Best for: Headless factory workers, GPU nodes.

Worker auth uses a "Golden Enrollment Token" to bootstrap trust. The SDK handles the exchange automatically.

  1. Generate an Enrollment Token in the dashboard (System Admin only).
  2. Set NEXICAL_ENROLLMENT_TOKEN in your worker's environment.
  3. The NexicalWorker class will:
    • Detect the env var.
    • Call /auth/worker/enroll to exchange it for a session JWT.
    • Cache the JWT in memory for subsequent requests.
// No manual token handling needed if using NexicalWorker + Env Var
const worker = new NexicalWorker(client, {
    workerId: 'my-node',
    enrollmentToken: process.env.NEXICAL_ENROLLMENT_TOKEN
});

C. Device Flow (Interactive)

Best for: CLI Tools, Desktop Apps, Developer-facing extensions.

Allows a user to authorize a headless device by visiting a URL on their phone/laptop.

// 1. Start Flow
// This tells the API "I want to authenticate user on this device"
const token = await client.auth.authenticateDevice('my-cli-app', (userCode, verificationUri) => {
    // 2. Prompt User
    console.log(`Please visit ${verificationUri} and enter code: ${userCode}`);
    // Ideally, open the browser automatically for them here.
});

// 3. Authenticated!
// The SDK polls until the user approves, then returns the token.
client.setToken(token);
console.log('Successfully logged in as', (await client.users.me()).fullName);

2. Developer Guides

🧩 Browser Extension Developer

Goal: Monitor build status, trigger deployments, and view logs from a browser popup.

Recommended Auth: API Token (generated by user) or Device Flow (if interactive).

// 1. List my teams
const teams = await client.teams.list();
const teamId = teams[0].id;

// 2. List projects in the team
const projects = await client.projects.list(teamId);
const project = projects.find(p => p.name === 'Frontend App');

if (project) {
    // 3. Find target branch (e.g., main)
    const branches = await client.branches.list(teamId, project.id);
    let branch = branches.find(b => b.name === 'main');
    
    // Create branch if missing (optional logic)
    if (!branch) {
         branch = await client.branches.create(teamId, project.id, { name: 'main' });
    }

    // 4. Trigger a new deployment on the branch
    const newJob = await client.jobs.create(teamId, project.id, branch.id, {
        type: 'deploy',
        inputs: { commit: 'latest' }
    });
    console.log(`Triggered Job ${newJob.id}`);

    // 5. Poll for status
    const interval = setInterval(async () => {
        const job = await client.jobs.get(teamId, project.id, branch.id, newJob.id);
        if (job.status !== 'pending' && job.status !== 'running') {
            clearInterval(interval);
            console.log(`Job finished: ${job.status}`);
        }
    }, 2000);
}

πŸ’» Web Application Developer

Goal: Build a full management dashboard for creating teams, inviting users, and configuring projects.

// 1. Create a new Team
const team = await client.teams.create({
    name: 'Research Division',
    slug: 'research-div'
});

// 2. Invite a colleague
await client.teams.inviteMember(team.id, {
    email: '[email protected]',
    role: 'admin'
});

// 3. Configure a Project
const project = await client.projects.create(team.id, {
    name: 'AI Model Training',
    repoUrl: 'github.com/org/ai-model',
    productionUrl: 'https://model.ai'
});

// 4. Create a Default Branch
const mainBranch = await client.branches.create(team.id, project.id, {
    name: 'main',
    previewUrl: 'https://main.model.ai'
});

// 4. Update User Profile
await client.users.update({
    fullName: 'Bob Manager',
    avatarUrl: 'https://...'
});

🏭 Factory Worker Developer

Goal: Build a custom runtime (e.g., a GPU cluster node) that polls the Orchestrator for heavy compute jobs.

Recommended Auth: Enrollment Token (headless) or Device Flow (interactive CLI).

The SDK provides a NexicalWorker class that handles polling logic, backoff (jitter), and concurrency for you.

import { NexicalClient, NexicalWorker } from '@nexical/sdk';

const client = new NexicalClient();

// 1. Initialize Worker
// The worker will automatically exchange the ENROLLMENT_TOKEN for a session token.
const worker = new NexicalWorker(client, {
    workerId: 'gpu-node-01',
    concurrency: 2, // Process 2 jobs in parallel
    enrollmentToken: process.env.NEXICAL_ENROLLMENT_TOKEN
});

// 2. Define Job Processor
// This function is compatible with the "JobProcessor" type.
const processor = async (job) => {
    console.log(`[Job ${job.id}] Starting execution...`);
    
    // ... Perform heavy compute ...
    
    // Add logs back to the platform
    // Note: We need teamId/projectId/branchId from job metadata
    await client.jobs.addLog(job.teamId, job.projectId, job.branchId, job.id, {
        message: 'Compute complete. Uploading artifacts...',
        level: 'info'
    });
};

// 3. Start Polling
// This promise resolves only when worker.stop() is called.
await worker.start(processor);

πŸ€– Remote Agent Developer

Goal: Write code that runs inside the job container (e.g., an LLM Agent) and needs to interact with the platform securely.

Auth: The Agent uses a temporary token minted by the Worker.

// Inside the job container, these might be passed as ENV vars or args
const TEAM_ID = ...;
const PROJECT_ID = ...;
const BRANCH_ID = ...;
const JOB_ID = ...;

// 1. Get a GitHub Token to clone the repo
// (Only works if the worker specifically requests it or if it's part of the job context)
try {
    const gitToken = await client.jobs.getGitToken(TEAM_ID, PROJECT_ID, BRANCH_ID, JOB_ID);
    console.log(`Cloning with token expiring at ${gitToken.expires_at}`);
} catch (err) {
    console.error('Failed to get Git token:', err);
}

// 2. Mint a sub-token for a sub-agent
// If this process spawns another isolated process, it can vend a restricted token.
const agentToken = await client.jobs.getAgentToken(TEAM_ID, PROJECT_ID, BRANCH_ID, JOB_ID);

3. API Reference & Coverage

This table maps the Orchestrator API endpoints to the corresponding SDK methods.

βœ… = Supported & Verified ⚠️ = Partially Supported / Different Signature ❌ = Not Implemented in SDK

Authentication (client.auth)

API Endpoint SDK Method Status
POST /auth/users createSystemUser(data) βœ…
POST /auth/tokens generateToken(data) βœ…
GET /auth/tokens listTokens() βœ…
DELETE /auth/tokens/:id revokeToken(id) βœ…
POST /auth/worker/enroll enrollWorker(data) βœ…
POST /device/* authenticateDevice(clientId, cb) βœ… (Orchestrated)

Users (client.users)

API Endpoint SDK Method Status
GET /users/me me() βœ…
PUT /users/me update(data) βœ…

Teams (client.teams)

API Endpoint SDK Method Status
GET /teams list() βœ…
POST /teams create(data) βœ…
GET /teams/:id get(id) βœ…
PUT /teams/:id update(id, data) βœ…
POST /teams/:id/invites inviteMember(id, data) βœ…
DELETE /teams/:id/members/:uid removeMember(id, uid) βœ…
DELETE /teams/:id delete(id) βœ…

Projects (client.projects)

API Endpoint SDK Method Status
GET /teams/:tid/projects list(teamId) βœ…
POST /teams/:tid/projects create(teamId, data) βœ…
GET /teams/:tid/projects/:pid get(teamId, projId) βœ…
PUT /teams/:tid/projects/:pid update(teamId, projId, data) βœ…
DELETE /teams/:tid/projects/:pid delete(teamId, projId) βœ…

Branches (client.branches)

API Endpoint SDK Method Status
GET /teams/:tid/projects/:pid/branches list(teamId, projId) βœ…
POST /teams/:tid/projects/:pid/branches create(teamId, projId, data) βœ…
GET /teams/:tid/projects/:pid/branches/:bid get(teamId, projId, branchId) βœ…
DELETE /teams/:tid/projects/:pid/branches/:bid delete(teamId, projId, branchId) βœ…

Jobs (client.jobs)

API Endpoint SDK Method Status
GET /:branchId/jobs list(teamId, projId, branchId) * ⚠️ (Requires teamId scope)
POST /:branchId/jobs create(teamId, projId, branchId, data) * ⚠️ (Requires teamId scope)
GET /:jobId get(teamId, projId, branchId, jobId) * ⚠️ (Requires full scope)
GET /:jobId/logs getLogs(teamId, projId, branchId, jobId) βœ…
POST /:jobId/logs addLog(teamId, projId, branchId, jobId, data) βœ…
GET /jobs/:id/git-token getGitToken(teamId, projId, branchId, jobId) βœ…
POST /jobs/:id/agent-token getAgentToken(teamId, projId, branchId, jobId) βœ…

* Note: The SDK enforces strict hierarchical scoping (/teams/:id/projects/:id/branches/:id/...) to ensure correct resource addressing and team-based authorization checks.

Workers (client.workers)

API Endpoint SDK Method Status
POST /workers/acquire acquireJob() βœ…

Error Handling

The SDK throws typed error classes for easier handling:

  • NexicalNetworkError: Connection failures (DNS, Timeout).
  • NexicalAuthError: 401 Unauthorized / 403 Forbidden.
  • NexicalRateLimitError: 429 Too Many Requests.
  • NexicalContractError: Response did not match expected Zod schema.
  • NexicalAPIError: Generic 4xx/5xx errors (includes code and message).
try {
  await client.teams.create({ ... });
} catch (error) {
  if (error instanceof NexicalContractError) {
    console.error('Server returned invalid data format', error.validationErrors);
  } else if (error instanceof NexicalAPIError) {
    console.error(`API Error ${error.statusCode}: ${error.message}`);
  }
}

4. Data Models

The SDK exports TypeScript interfaces for all API resources. These match the Zod schemas used for runtime validation.

Core Resources

export interface User {
  id: string; // UUID
  email?: string;
  fullName: string | null;
  avatarUrl: string | null;
  role: 'user' | 'system';
  createdAt: string;
  updatedAt: string;
}

export interface Team {
  id: number;
  name: string;
  slug: string;
  billingPlan: string;
  role?: 'owner' | 'admin' | 'member'; // Current user's role
  createdAt: string;
  updatedAt: string;
}

export interface Project {
  id: number;
  teamId: number;
  name: string;
  repoUrl: string | null;
  productionUrl: string | null;
  mode: 'managed' | 'self_hosted';
  contextHash: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface Branch {
  id: number;
  projectId: number;
  name: string;
  previewUrl: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface Job {
  id: number;
  branchId: number;
  type: string; // e.g. "deploy", "build"
  status: 'pending' | 'running' | 'completed' | 'failed';
  queue: string; // e.g. "public", "private-123"
  inputs: Record<string, any> | null;
  outputs: Record<string, any> | null;
  startedAt: string | null;
  completedAt: string | null;
  createdAt: string;
}

export interface JobLog {
  id: number;
  jobId: number;
  level: 'info' | 'warn' | 'error';
  message: string;
  metadata: Record<string, any> | null;
  timestamp: string;
}

Context Interfaces

Workers

export interface Worker {
  id: string; // UUID
  name: string;
  teamId: number | null; // Null for managed/public workers
  lastSeenAt: string | null;
}

Tokens

export interface ApiToken {
  id: number;
  name: string;
  tokenPrefix: string;
  scopes: string[] | null;
  lastUsedAt: string | null;
  expiresAt: string | null;
}

export interface GitTokenResponse {
  token: string;
  expires_at: string; // ISO Date
}

Request Objects

Useful payload types for create and update methods.

export interface CreateBranchRequest {
  name: string;
  previewUrl?: string;
}

export interface CreateJobRequest {
  type: string;
  inputs?: Record<string, any>;
}

export interface EnrollWorkerRequest {
  token: string; // The Golden Enrollment Token
  metadata?: Record<string, any>;
}

About

Typescript SDK for the Nexical API

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published