Skip to content

JavaScript SDK

The official JavaScript/TypeScript SDK for 0.link. Built for modern web applications, Node.js servers, and JavaScript frameworks with full TypeScript support.

Installation

bash
npm install @0link/sdk
# or
yarn add @0link/sdk
# or
pnpm add @0link/sdk

Quick Start

javascript
import { ZeroLink } from '@0link/sdk';

const client = new ZeroLink({
  apiKey: 'your_api_key_here'
});

// Get account information
const account = await client.account.get();
console.log(`Welcome, ${account.name}!`);

// List projects
const projects = await client.projects.list();
console.log(`You have ${projects.length} projects`);

Configuration

Basic Configuration

javascript
import { ZeroLink } from '@0link/sdk';

const client = new ZeroLink({
  apiKey: process.env.ZEROLINK_API_KEY,
  environment: 'production' // 'development' | 'production'
});

Advanced Configuration

javascript
const client = new ZeroLink({
  apiKey: 'your_api_key',
  environment: 'production',

  // Request configuration
  timeout: 10000, // 10 seconds
  retryAttempts: 3,
  retryDelay: 1000, // Base delay in ms

  // Base URL (usually not needed)
  baseURL: 'https://api.0link.com/v2',

  // Debug mode
  debug: process.env.NODE_ENV === 'development',

  // Custom headers
  headers: {
    'User-Agent': 'MyApp/1.0.0'
  },

  // Interceptors
  requestInterceptor: (config) => {
    console.log('Making request:', config.url);
    return config;
  },

  responseInterceptor: (response) => {
    console.log('Response received:', response.status);
    return response;
  }
});

Authentication

The SDK handles authentication automatically using your API key:

javascript
// API key is included in all requests automatically
const projects = await client.projects.list();

// Check authentication status
const isAuthenticated = await client.auth.check();
console.log('Authenticated:', isAuthenticated);

// Get current user info
const user = await client.auth.user();
console.log('Current user:', user);

Core Resources

Account

javascript
// Get account information
const account = await client.account.get();

// Update account settings
await client.account.update({
  name: 'Updated Company Name',
  webhook_url: 'https://your-app.com/webhooks'
});

Projects

javascript
// List all projects
const projects = await client.projects.list();

// List projects with filtering
const activeProjects = await client.projects.list({
  status: 'active',
  limit: 50
});

// Get specific project
const project = await client.projects.get('proj_123');

// Create new project
const newProject = await client.projects.create({
  name: 'My New Project',
  description: 'A sample project',
  settings: {
    public: false,
    webhook_url: 'https://your-app.com/project-webhooks'
  }
});

// Update project
await client.projects.update('proj_123', {
  name: 'Updated Project Name',
  description: 'Updated description'
});

// Delete project
await client.projects.delete('proj_123');

Assets

javascript
// List assets in a project
const assets = await client.assets.list('proj_123');

// Upload file
const asset = await client.assets.upload({
  projectId: 'proj_123',
  file: fileObject, // File object or Buffer
  name: 'my-image.jpg',
  folder: '/images',
  metadata: {
    alt_text: 'A beautiful image',
    tags: ['nature', 'landscape']
  }
});

// Upload with progress tracking
const asset = await client.assets.upload({
  projectId: 'proj_123',
  file: fileObject,
  name: 'large-video.mp4',
  onProgress: (progress) => {
    console.log(`Upload progress: ${progress.percentage}%`);
  }
});

// Get asset details
const asset = await client.assets.get('asset_123');

// Update asset metadata
await client.assets.update('asset_123', {
  name: 'Updated Asset Name',
  metadata: {
    alt_text: 'Updated description'
  }
});

// Delete asset
await client.assets.delete('asset_123');

Analytics

javascript
// Get usage statistics
const usage = await client.analytics.usage({
  period: 'last_30_days',
  group_by: 'project'
});

// Get performance metrics
const performance = await client.analytics.performance({
  start_date: '2024-01-01',
  end_date: '2024-01-31'
});

// Custom analytics query
const results = await client.analytics.query({
  metric: 'api_calls',
  dimensions: ['endpoint', 'status_code'],
  filters: {
    project_id: 'proj_123',
    date_range: 'last_7_days'
  },
  aggregation: 'sum'
});

File Upload

Basic Upload

javascript
// Upload from file input
const fileInput = document.getElementById('file-input');
const file = fileInput.files[0];

const asset = await client.assets.upload({
  projectId: 'proj_123',
  file: file,
  name: file.name
});

Advanced Upload with Progress

javascript
const uploadAsset = async (file) => {
  try {
    const asset = await client.assets.upload({
      projectId: 'proj_123',
      file: file,
      name: file.name,
      folder: '/uploads',
      onProgress: (progress) => {
        console.log(`Progress: ${progress.percentage}%`);
        console.log(`Uploaded: ${progress.loaded}/${progress.total} bytes`);
      },
      onStart: () => {
        console.log('Upload started');
      },
      onComplete: (asset) => {
        console.log('Upload completed:', asset);
      }
    });

    return asset;
  } catch (error) {
    console.error('Upload failed:', error);
    throw error;
  }
};

Multiple File Upload

javascript
const uploadMultipleFiles = async (files) => {
  const uploads = Array.from(files).map(file =>
    client.assets.upload({
      projectId: 'proj_123',
      file: file,
      name: file.name
    })
  );

  try {
    const assets = await Promise.all(uploads);
    console.log('All files uploaded:', assets);
    return assets;
  } catch (error) {
    console.error('Some uploads failed:', error);
    throw error;
  }
};

Real-time Updates

WebSocket Connection

javascript
// Connect to WebSocket
const ws = client.realtime.connect();

// Listen for events
ws.on('asset.uploaded', (event) => {
  console.log('New asset uploaded:', event.data);
});

ws.on('project.updated', (event) => {
  console.log('Project updated:', event.data);
});

// Subscribe to specific project events
ws.subscribe('project:proj_123', (event) => {
  console.log('Project-specific event:', event);
});

// Disconnect when done
ws.disconnect();

Event Handling

javascript
class AssetManager {
  constructor() {
    this.client = new ZeroLink({ apiKey: 'your_api_key' });
    this.ws = null;
  }

  async connect() {
    this.ws = this.client.realtime.connect();

    this.ws.on('connected', () => {
      console.log('Connected to real-time updates');
    });

    this.ws.on('disconnected', () => {
      console.log('Disconnected from real-time updates');
    });

    this.ws.on('error', (error) => {
      console.error('WebSocket error:', error);
    });

    this.ws.on('asset.uploaded', this.handleAssetUploaded.bind(this));
    this.ws.on('asset.deleted', this.handleAssetDeleted.bind(this));
  }

  handleAssetUploaded(event) {
    // Update UI with new asset
    this.addAssetToUI(event.data.asset);
  }

  handleAssetDeleted(event) {
    // Remove asset from UI
    this.removeAssetFromUI(event.data.asset_id);
  }

  disconnect() {
    if (this.ws) {
      this.ws.disconnect();
      this.ws = null;
    }
  }
}

Error Handling

Basic Error Handling

javascript
import {
  ZeroLinkError,
  ValidationError,
  AuthenticationError,
  RateLimitError
} from '@0link/sdk';

try {
  const project = await client.projects.create(invalidData);
} catch (error) {
  if (error instanceof ValidationError) {
    console.log('Validation failed:', error.details);
    console.log('Field:', error.field);
  } else if (error instanceof AuthenticationError) {
    console.log('Authentication failed:', error.message);
  } else if (error instanceof RateLimitError) {
    console.log('Rate limited, retry after:', error.retryAfter);
  } else if (error instanceof ZeroLinkError) {
    console.log('0.link API error:', error.code, error.message);
  } else {
    console.log('Unexpected error:', error);
  }
}

Global Error Handler

javascript
// Set up global error handler
client.on('error', (error) => {
  console.error('Global 0.link error:', error);

  // Send to error tracking service
  if (window.Sentry) {
    window.Sentry.captureException(error);
  }
});

// Set up retry logic
client.on('retry', (attempt, error) => {
  console.log(`Retry attempt ${attempt} after error:`, error.message);
});

Pagination

Cursor-based Pagination

javascript
// Get first page
let response = await client.projects.list({ limit: 25 });
let allProjects = [...response.data];

// Get subsequent pages
while (response.pagination.has_more) {
  response = await client.projects.list({
    limit: 25,
    cursor: response.pagination.next_cursor
  });
  allProjects.push(...response.data);
}

console.log('All projects:', allProjects);

Helper for Pagination

javascript
async function getAllProjects() {
  const allProjects = [];

  for await (const project of client.projects.iterate()) {
    allProjects.push(project);
  }

  return allProjects;
}

// Usage
const projects = await getAllProjects();

Batch Operations

Batch Asset Upload

javascript
const batchUpload = await client.assets.uploadBatch({
  projectId: 'proj_123',
  files: [
    { file: file1, name: 'image1.jpg' },
    { file: file2, name: 'image2.jpg' },
    { file: file3, name: 'image3.jpg' }
  ],
  onProgress: (overall, individual) => {
    console.log(`Overall: ${overall.percentage}%`);
    individual.forEach((progress, index) => {
      console.log(`File ${index + 1}: ${progress.percentage}%`);
    });
  }
});

Batch Operations with Error Handling

javascript
const batchResult = await client.projects.createBatch([
  { name: 'Project 1', description: 'First project' },
  { name: 'Project 2', description: 'Second project' },
  { name: 'Project 3', description: 'Third project' }
]);

// Handle partial success
batchResult.results.forEach((result, index) => {
  if (result.success) {
    console.log(`Project ${index + 1} created:`, result.data);
  } else {
    console.error(`Project ${index + 1} failed:`, result.error);
  }
});

TypeScript Support

Type Definitions

typescript
import { ZeroLink, Project, Asset, User } from '@0link/sdk';

const client = new ZeroLink({
  apiKey: process.env.ZEROLINK_API_KEY!
});

// Fully typed responses
const projects: Project[] = await client.projects.list();
const asset: Asset = await client.assets.get('asset_123');
const user: User = await client.auth.user();

// Type-safe project creation
const newProject: Project = await client.projects.create({
  name: 'Typed Project',
  description: 'A type-safe project',
  settings: {
    public: false
  }
});

Custom Types

typescript
interface CustomProjectData {
  name: string;
  description?: string;
  customField: string;
}

// Extend SDK types
interface ExtendedProject extends Project {
  customField: string;
}

const createCustomProject = async (data: CustomProjectData): Promise<ExtendedProject> => {
  const project = await client.projects.create(data);
  return project as ExtendedProject;
};

Node.js Specific Features

File System Integration

javascript
import fs from 'fs';
import path from 'path';

// Upload file from filesystem
const filePath = path.join(__dirname, 'assets', 'image.jpg');
const fileStream = fs.createReadStream(filePath);

const asset = await client.assets.upload({
  projectId: 'proj_123',
  file: fileStream,
  name: 'image.jpg'
});

// Download asset to filesystem
const assetData = await client.assets.download('asset_123');
fs.writeFileSync('./downloaded-asset.jpg', assetData);

Environment Variables

javascript
// Load configuration from environment
const client = new ZeroLink({
  apiKey: process.env.ZEROLINK_API_KEY,
  environment: process.env.NODE_ENV === 'production' ? 'production' : 'development',
  timeout: parseInt(process.env.ZEROLINK_TIMEOUT || '10000'),
  debug: process.env.ZEROLINK_DEBUG === 'true'
});

Testing

Mock Client

javascript
import { MockZeroLink } from '@0link/sdk/testing';

// Create mock client for testing
const mockClient = new MockZeroLink({
  projects: [
    { id: 'proj_1', name: 'Test Project 1' },
    { id: 'proj_2', name: 'Test Project 2' }
  ],
  assets: [
    { id: 'asset_1', name: 'test.jpg', project_id: 'proj_1' }
  ]
});

// Use in tests
describe('Project Service', () => {
  test('should list projects', async () => {
    const projects = await mockClient.projects.list();
    expect(projects).toHaveLength(2);
    expect(projects[0].name).toBe('Test Project 1');
  });
});

Integration Testing

javascript
import { ZeroLink } from '@0link/sdk';

// Use test API key for integration tests
const testClient = new ZeroLink({
  apiKey: process.env.ZEROLINK_TEST_API_KEY,
  environment: 'development'
});

describe('Integration Tests', () => {
  test('should create and delete project', async () => {
    // Create test project
    const project = await testClient.projects.create({
      name: 'Test Project',
      description: 'Created by integration test'
    });

    expect(project.id).toBeDefined();
    expect(project.name).toBe('Test Project');

    // Clean up
    await testClient.projects.delete(project.id);
  });
});

Performance Optimization

Request Caching

javascript
import { ZeroLink } from '@0link/sdk';

const client = new ZeroLink({
  apiKey: 'your_api_key',
  cache: {
    enabled: true,
    ttl: 300000, // 5 minutes
    storage: 'memory' // or 'localStorage' in browser
  }
});

// Subsequent calls will use cached data
const projects1 = await client.projects.list(); // API call
const projects2 = await client.projects.list(); // From cache

Request Deduplication

javascript
// Multiple simultaneous requests are automatically deduplicated
const [projects1, projects2, projects3] = await Promise.all([
  client.projects.list(), // API call
  client.projects.list(), // Deduplicated
  client.projects.list()  // Deduplicated
]);

Migration Guide

From v1 to v2

javascript
// v1
import ZeroLinkSDK from '@0link/sdk';
const client = new ZeroLinkSDK('your_api_key');

// v2
import { ZeroLink } from '@0link/sdk';
const client = new ZeroLink({ apiKey: 'your_api_key' });

// Method changes
// v1: client.getProjects()
// v2: client.projects.list()

// v1: client.createProject(data)
// v2: client.projects.create(data)

// v1: client.uploadAsset(projectId, file)
// v2: client.assets.upload({ projectId, file })

Best Practices

  1. Reuse Client Instances: Create one client and reuse it
  2. Handle Errors Gracefully: Always wrap API calls in try-catch
  3. Use TypeScript: Leverage full type safety
  4. Implement Retry Logic: Handle rate limits and transient errors
  5. Monitor Performance: Track API usage and response times
  6. Secure API Keys: Never expose keys in client-side code
  7. Use Environment Variables: Store configuration in env vars
  8. Implement Caching: Cache frequently accessed data

Examples

Complete examples are available in our GitHub repository:

Getting Help

Next Steps