Skip to main content

JavaScript Client

The Lumenize JavaScript client provides a clean, type-safe way to interact with your Lumenize backend from any JavaScript or TypeScript environment.

Installation

Terminal window
npm install @lumenize/client

Quick Start

import { LumenizeClient } from '@lumenize/client';
const client = new LumenizeClient({
projectId: 'proj_abc123',
apiKey: 'lum_live_xyz789',
environment: 'production' // 'development', 'staging', or 'production'
});
// Create a new user
const user = await client.users.create({
name: 'John Doe',
email: 'john@example.com'
});
// Fetch all users
const users = await client.users.findMany();
// Update a user
const updatedUser = await client.users.update(user.id, {
name: 'John Smith'
});

Configuration

Basic Configuration

const client = new LumenizeClient({
projectId: 'proj_abc123', // Your project ID
apiKey: 'lum_live_xyz789', // Your API key
environment: 'production', // Target environment
baseUrl: 'https://api.lumenize.dev', // Optional: custom base URL
timeout: 5000, // Request timeout in ms
retries: 3, // Number of retry attempts
retryDelay: 1000 // Delay between retries in ms
});

TypeScript Configuration

import { LumenizeClient, User, Task } from '@lumenize/client';
// Fully typed client
const client = new LumenizeClient({
projectId: 'proj_abc123',
apiKey: 'lum_live_xyz789'
});
// Type-safe operations
const user: User = await client.users.create({
name: 'John Doe',
email: 'john@example.com'
});
const tasks: Task[] = await client.tasks.findMany({
where: { assignedTo: user.id }
});

CRUD Operations

Create

// Create a single entity
const user = await client.users.create({
name: 'Alice Johnson',
email: 'alice@example.com',
role: 'admin'
});
// Create multiple entities
const users = await client.users.createMany([
{ name: 'Bob Wilson', email: 'bob@example.com' },
{ name: 'Carol Brown', email: 'carol@example.com' }
]);

Read

// Find by ID
const user = await client.users.findById('user_123');
// Find with filters
const adminUsers = await client.users.findMany({
where: { role: 'admin' }
});
// Find with complex queries
const recentTasks = await client.tasks.findMany({
where: {
createdAt: { gte: new Date('2024-01-01') },
status: { in: ['pending', 'in_progress'] }
},
orderBy: { createdAt: 'desc' },
limit: 10,
offset: 0
});
// Find with relationships
const userWithTasks = await client.users.findById('user_123', {
include: { tasks: true }
});

Update

// Update by ID
const updatedUser = await client.users.update('user_123', {
name: 'New Name',
email: 'newemail@example.com'
});
// Update multiple entities
const result = await client.users.updateMany(
{ where: { role: 'guest' } },
{ role: 'user' }
);
// Partial updates
const task = await client.tasks.update('task_123', {
status: 'completed',
completedAt: new Date()
});

Delete

// Delete by ID
await client.users.delete('user_123');
// Soft delete (if enabled in schema)
await client.users.delete('user_123', { soft: true });
// Delete multiple entities
const result = await client.users.deleteMany({
where: { lastLoginAt: { lt: new Date('2023-01-01') } }
});
// Restore soft-deleted entity
await client.users.restore('user_123');

Query Builder

Advanced Filtering

// Complex where conditions
const tasks = await client.tasks.findMany({
where: {
AND: [
{ status: 'pending' },
{ priority: { in: ['high', 'urgent'] } },
{
OR: [
{ dueDate: { lt: new Date() } },
{ assignedTo: 'user_123' }
]
}
]
}
});
// Text search
const users = await client.users.findMany({
where: {
name: { contains: 'john' }
}
});
// Numeric comparisons
const expensiveTasks = await client.tasks.findMany({
where: {
budget: { gte: 1000, lte: 5000 }
}
});

Sorting and Pagination

// Multiple sort fields
const tasks = await client.tasks.findMany({
orderBy: [
{ priority: 'desc' },
{ createdAt: 'asc' }
],
limit: 20,
offset: 40
});
// Cursor-based pagination
const tasks = await client.tasks.findMany({
orderBy: { createdAt: 'desc' },
limit: 10,
cursor: 'task_456'
});

Field Selection

// Select specific fields
const users = await client.users.findMany({
select: ['id', 'name', 'email']
});
// Include relationships
const userWithDetails = await client.users.findById('user_123', {
include: {
tasks: {
where: { status: 'pending' },
orderBy: { dueDate: 'asc' }
},
profile: true
}
});

Real-time Subscriptions

WebSocket Connection

// Establish WebSocket connection
await client.connect();
// Subscribe to entity changes
const unsubscribe = client.tasks.subscribe('*', (event) => {
console.log(`Task ${event.id} was ${event.type}d:`, event.data);
});
// Subscribe to specific entity
client.users.subscribe('user_123', (event) => {
console.log('User updated:', event.data);
});
// Subscribe with filters
client.tasks.subscribe({
where: { assignedTo: 'user_123' }
}, (tasks) => {
console.log('My tasks updated:', tasks);
});
// Cleanup
unsubscribe();
await client.disconnect();

Event Types

client.tasks.subscribe('*', (event) => {
switch (event.type) {
case 'created':
console.log('New task:', event.data);
break;
case 'updated':
console.log('Task updated:', event.data);
break;
case 'deleted':
console.log('Task deleted:', event.id);
break;
}
});

Authentication

User Authentication

// Login with email/password
const session = await client.auth.login({
email: 'user@example.com',
password: 'password123'
});
// Login with OAuth provider
const session = await client.auth.loginWithProvider('google');
// Get current user
const currentUser = await client.auth.getCurrentUser();
// Logout
await client.auth.logout();

Session Management

// Check authentication status
const isAuthenticated = client.auth.isAuthenticated();
// Refresh token
await client.auth.refreshToken();
// Handle session events
client.auth.onSessionChange((session) => {
if (session) {
console.log('User logged in:', session.user);
} else {
console.log('User logged out');
}
});

Error Handling

Try-Catch Pattern

try {
const user = await client.users.create({
name: 'John Doe',
email: 'invalid-email'
});
} catch (error) {
if (error.code === 'VALIDATION_ERROR') {
console.log('Validation failed:', error.details);
} else if (error.code === 'NETWORK_ERROR') {
console.log('Network error:', error.message);
} else {
console.log('Unknown error:', error);
}
}

Global Error Handler

client.onError((error) => {
console.error('Lumenize error:', error);
// Send to error tracking service
errorTracker.captureException(error);
});

Caching

Automatic Caching

const client = new LumenizeClient({
projectId: 'proj_abc123',
apiKey: 'lum_live_xyz789',
cache: {
enabled: true,
ttl: 300000, // 5 minutes
maxSize: 1000 // Maximum cached items
}
});
// Subsequent calls use cache
const user1 = await client.users.findById('user_123'); // Fetches from API
const user2 = await client.users.findById('user_123'); // Returns from cache

Cache Control

// Bypass cache for fresh data
const freshUser = await client.users.findById('user_123', {
cache: false
});
// Invalidate cache
client.cache.invalidate('users', 'user_123');
// Clear all cache
client.cache.clear();

Middleware

Request Middleware

// Add request interceptor
client.interceptors.request.use((request) => {
// Add custom headers
request.headers['X-Custom-Header'] = 'value';
// Log requests
console.log('Request:', request.method, request.url);
return request;
});
// Add response interceptor
client.interceptors.response.use(
(response) => {
console.log('Response:', response.status, response.data);
return response;
},
(error) => {
console.error('Response error:', error);
throw error;
}
);

Custom Middleware

// Create custom middleware
const loggingMiddleware = (next) => async (request) => {
const start = Date.now();
const response = await next(request);
const duration = Date.now() - start;
console.log(`${request.method} ${request.url} - ${duration}ms`);
return response;
};
// Apply middleware
client.use(loggingMiddleware);

Advanced Features

Batch Operations

// Batch multiple operations
const batch = client.batch();
batch.users.create({ name: 'User 1', email: 'user1@example.com' });
batch.users.create({ name: 'User 2', email: 'user2@example.com' });
batch.tasks.update('task_123', { status: 'completed' });
// Execute batch
const results = await batch.execute();

Transactions

// Perform operations in a transaction
const result = await client.transaction(async (tx) => {
const user = await tx.users.create({
name: 'John Doe',
email: 'john@example.com'
});
const task = await tx.tasks.create({
title: 'Welcome task',
assignedTo: user.id
});
return { user, task };
});

File Uploads

// Upload file
const file = document.getElementById('fileInput').files[0];
const uploadResult = await client.files.upload(file, {
folder: 'avatars',
public: true
});
// Update user with avatar URL
await client.users.update('user_123', {
avatar: uploadResult.url
});

Node.js Specific Features

Server-Side Usage

// Node.js server usage
import { LumenizeClient } from '@lumenize/node';
const client = new LumenizeClient({
projectId: process.env.LUMENIZE_PROJECT_ID,
apiKey: process.env.LUMENIZE_API_KEY
});
// Server-side operations
app.get('/api/users', async (req, res) => {
try {
const users = await client.users.findMany();
res.json(users);
} catch (error) {
res.status(500).json({ error: error.message });
}
});

Environment Variables

Terminal window
# .env file
LUMENIZE_PROJECT_ID=proj_abc123
LUMENIZE_API_KEY=lum_live_xyz789
LUMENIZE_ENVIRONMENT=production

Best Practices

Error Handling

// âś… Good: Specific error handling
try {
await client.users.create(userData);
} catch (error) {
switch (error.code) {
case 'VALIDATION_ERROR':
return handleValidationError(error);
case 'PERMISSION_DENIED':
return handlePermissionError(error);
default:
return handleGenericError(error);
}
}

Performance

// âś… Good: Use field selection for large objects
const users = await client.users.findMany({
select: ['id', 'name', 'email'], // Only fetch needed fields
limit: 100
});
// âś… Good: Use pagination for large datasets
const getAllUsers = async () => {
const users = [];
let cursor = null;
do {
const page = await client.users.findMany({
limit: 100,
cursor
});
users.push(...page.data);
cursor = page.nextCursor;
} while (cursor);
return users;
};

Security

// âś… Good: Never expose API keys in client-side code
const client = new LumenizeClient({
projectId: 'proj_abc123',
// Use public key for client-side
apiKey: 'lum_pub_xyz789'
});
// âś… Good: Validate data before sending
const createUser = async (userData) => {
if (!userData.email || !isValidEmail(userData.email)) {
throw new Error('Valid email is required');
}
return client.users.create(userData);
};

Self-Hosted Usage

For self-hosted Lumenize instances, you can use the client directly with your Durable Objects:

Basic Setup

import { LumenizeClient } from "lumenize";
const client = new LumenizeClient({
agent: "mylumenizeserver", // Your server class name in kebab-case
name: "instance-name", // Specific Durable Object instance
host: window.location.host, // Or your server host
timeout: 5000, // Request timeout in ms (default: 5000)
route: "jsonrpc" // Endpoint route (default: 'jsonrpc')
});

Making Method Calls

The client provides multiple ways to call your server methods:

// Generic call method
const result = await client.call("subtract", [42, 23]);
// Direct method calls (auto-generated based on your server methods)
const result = await client.subtract(42, 23);
// Named parameters
const result = await client.subtract({ minuend: 42, subtrahend: 23 });
// Mixed parameter order (named params)
const result = await client.subtract({ subtrahend: 23, minuend: 42 });
console.log(result); // 19

HTTP Requests (Manual)

For environments where you can’t use the client library:

Single Request

const response = await fetch("https://your-worker.your-subdomain.workers.dev/agents/mylumenizeserver/instance-name/jsonrpc", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
method: "subtract",
params: [42, 23],
id: 1
})
});
const result = await response.json();
console.log(result); // { jsonrpc: '2.0', result: 19, id: 1 }

Batch Requests

JSON-RPC 2.0 supports batch operations:

const response = await fetch("https://your-worker.your-subdomain.workers.dev/agents/mylumenizeserver/instance-name/jsonrpc", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify([
{ jsonrpc: "2.0", method: "subtract", params: [42, 23], id: 1 },
{ jsonrpc: "2.0", method: "subtract", params: [23, 42], id: 2 },
{ jsonrpc: "2.0", method: "getUserProfile", params: ["user123"], id: 3 }
])
});
const results = await response.json();
// Array of responses with matching IDs

WebSocket Connections

Using LumenizeClient

const client = new LumenizeClient({
agent: "mylumenizeserver",
name: "instance-name",
host: "your-worker.your-subdomain.workers.dev",
transport: "websocket" // Use WebSocket instead of HTTP
});
// Same API as HTTP client
const result = await client.subtract(42, 23);
// Subscribe to real-time updates
await client.subscribe("team-updates", (data) => {
console.log("Team updated:", data);
});

Manual WebSocket

const ws = new WebSocket("wss://your-worker.your-subdomain.workers.dev/agents/mylumenizeserver/instance-name");
ws.onopen = () => {
// Send JSON-RPC request wrapped in envelope
ws.send(JSON.stringify({
type: "jsonrpc",
payload: {
jsonrpc: "2.0",
method: "subtract",
params: [42, 23],
id: 1
}
}));
};
ws.onmessage = (event) => {
const envelope = JSON.parse(event.data);
if (envelope.type === "jsonrpc") {
console.log("Response:", envelope.payload);
}
};

Framework Integration

Svelte Integration

<script>
import { useLumenize } from "lumenize/svelte";
const { data, loading, error, call } = useLumenize({
agent: "mylumenizeserver",
name: "instance-name",
host: "your-worker.your-subdomain.workers.dev"
});
async function handleCalculation() {
const result = await call("subtract", [42, 23]);
console.log("Result:", result);
}
</script>
{#if loading}
<p>Connecting...</p>
{:else if error}
<p>Error: {error.message}</p>
{:else}
<button on:click={handleCalculation}>Calculate</button>
<!-- Reactive data updates automatically -->
{#if $data.teamMetrics}
<div>Team Score: {$data.teamMetrics.score}</div>
{/if}
{/if}

React Integration (Coming Soon)

import { useLumenize } from "lumenize/react";
function MyComponent() {
const { data, loading, error, call } = useLumenize({
agent: "mylumenizeserver",
name: "instance-name",
host: "your-worker.your-subdomain.workers.dev"
});
const handleCalculation = async () => {
const result = await call("subtract", [42, 23]);
console.log("Result:", result);
};
if (loading) return <div>Connecting...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button onClick={handleCalculation}>Calculate</button>
{data.teamMetrics && (
<div>Team Score: {data.teamMetrics.score}</div>
)}
</div>
);
}

Advanced Self-Hosted Features

Shared Worker (Browser)

The reactive clients automatically use SharedWorker for WebSocket multiplexing across browser tabs:

// Automatically shared across all tabs on the same origin
const client = new LumenizeClient({
agent: "mylumenizeserver",
name: "instance-name",
useSharedWorker: true // Default in browser environments
});

Custom Storage Reactivity

Build your own reactive layer using the storage-based core:

import { LumenizeStorage } from "lumenize/storage";
const storage = new LumenizeStorage("mylumenizeserver");
// Listen for changes
storage.addEventListener("change", (event) => {
console.log("Data updated:", event.detail);
// Update your UI framework's reactive state
});
// Trigger updates
await storage.set("teamMetrics", { score: 95 });

Next Steps