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/sdkQuick 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 cacheRequest 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
- Reuse Client Instances: Create one client and reuse it
- Handle Errors Gracefully: Always wrap API calls in try-catch
- Use TypeScript: Leverage full type safety
- Implement Retry Logic: Handle rate limits and transient errors
- Monitor Performance: Track API usage and response times
- Secure API Keys: Never expose keys in client-side code
- Use Environment Variables: Store configuration in env vars
- Implement Caching: Cache frequently accessed data
Examples
Complete examples are available in our GitHub repository:
Getting Help
- Documentation: Complete API reference
- GitHub: Report issues
- Support: Email support@0link.com
- Community: Join our developer Discord