A high-quality, type-safe TypeScript React client for Daebus services. This library provides seamless integration with Daebus background services through both HTTP and WebSocket protocols, with full TypeScript support and React hooks for easy frontend integration.
- 🎯 Type-Safe: Full TypeScript support with schema-based type generation
- 🔌 Dual Protocol: HTTP REST API and WebSocket real-time communication
- ⚛️ React Ready: Built-in React hooks for easy integration
- 🔄 Auto Reconnection: Automatic WebSocket reconnection with exponential backoff
- 📡 Real-time: Subscribe to broadcast channels for live updates
- 🛡️ Error Handling: Comprehensive error handling with custom error types
- 🎛️ Configurable: Flexible configuration options for different environments
- 📋 Schema Validation: Built-in Zod schema validation for runtime type safety
npm install @daebus/client
# or
yarn add @daebus/client
# or
pnpm add @daebus/clientThis package requires React as a peer dependency:
npm install react react-domimport { z } from 'zod';
import { defineSchema, action, channel, httpRoute, CommonSchemas } from '@daebus/client';
const MyServiceSchema = defineSchema({
actions: {
get_status: action(
z.object({ detail_level: z.enum(['basic', 'full']) }),
CommonSchemas.serviceStatus
),
restart: action(
z.object({ mode: z.enum(['graceful', 'force']) }),
z.object({ success: z.boolean(), message: z.string() })
),
},
channels: {
notifications: channel(CommonSchemas.notification),
system_status: channel(CommonSchemas.serviceStatus),
},
routes: {
'/status': httpRoute({
method: 'GET',
output: CommonSchemas.serviceStatus,
}),
'/devices': httpRoute({
method: 'GET',
output: z.array(CommonSchemas.deviceInfo),
}),
},
});import { DaebusClient } from '@daebus/client';
const client = new DaebusClient({
serviceName: 'my-service',
httpBaseUrl: 'http://localhost:8080',
wsUrl: 'ws://localhost:8081',
schema: MyServiceSchema,
});
// HTTP requests
const statusResponse = await client.get('/status');
console.log('Service status:', statusResponse.data);
// WebSocket actions
const restartResult = await client.sendAction('restart', {
mode: 'graceful'
});
// Subscribe to real-time updates
await client.subscribe('notifications', (notification) => {
console.log('New notification:', notification);
});import React from 'react';
import { useDaebus } from '@daebus/client';
function ServiceDashboard() {
const {
client,
connection,
useAction,
useChannel,
useFetch,
} = useDaebus({
serviceName: 'my-service',
httpBaseUrl: 'http://localhost:8080',
wsUrl: 'ws://localhost:8081',
schema: MyServiceSchema,
});
// Fetch data on mount
const [status, statusState, refetchStatus] = useFetch('/status');
// Action hook for restart
const [restart, restartState] = useAction('restart');
// Subscribe to notifications
const [notification, notificationState] = useChannel('notifications');
const handleRestart = async () => {
try {
await restart({ mode: 'graceful' });
// Refetch status after restart
setTimeout(() => refetchStatus(), 5000);
} catch (error) {
console.error('Restart failed:', error);
}
};
return (
<div>
<h1>Service Dashboard</h1>
{/* Connection Status */}
<div>
Status: {connection.connected ? '✅ Connected' : '❌ Disconnected'}
</div>
{/* Service Status */}
{statusState.loading ? (
<p>Loading...</p>
) : status ? (
<div>
<p>Service Status: {status.status}</p>
<p>Uptime: {status.uptime}s</p>
<button onClick={refetchStatus}>Refresh</button>
</div>
) : null}
{/* Actions */}
<button
onClick={handleRestart}
disabled={restartState.loading}
>
{restartState.loading ? 'Restarting...' : 'Restart Service'}
</button>
{/* Real-time Notifications */}
{notification && (
<div>
<h3>Latest Notification</h3>
<p>{notification.title}: {notification.message}</p>
</div>
)}
</div>
);
}The main client class that provides both HTTP and WebSocket functionality.
interface DaebusClientOptions<T extends ServiceSchema> {
serviceName: string; // Name of the target service
httpBaseUrl?: string; // Base URL for HTTP requests
wsUrl?: string; // WebSocket server URL
timeout?: number; // Default timeout (30000ms)
retryAttempts?: number; // Retry attempts (3)
retryDelay?: number; // Retry delay (1000ms)
headers?: Record<string, string>; // Default HTTP headers
autoConnect?: boolean; // Auto-connect WebSocket (true)
schema?: T; // Service schema for type safety
}// GET request
const response = await client.get('/status');
// POST request
const response = await client.post('/control', {
action: 'reboot',
params: { delay: 5 }
});
// Request with parameters
const response = await client.get('/devices/<device_id>', {
params: { device_id: 'device-123' }
});// Send action
const result = await client.sendAction('restart', { mode: 'graceful' });
// Subscribe to channel
await client.subscribe('notifications', (data) => {
console.log('Notification:', data);
});
// Broadcast message
client.broadcast('device_events', {
device_id: 'sensor-1',
event_type: 'connected',
timestamp: Date.now(),
});
// Check connection
const isConnected = client.isConnected();
// Manual connection management
await client.connect();
client.disconnect();Main hook that provides a configured client and helper hooks.
const {
client,
connection,
broadcast,
useAction,
useChannel,
useHttp,
useFetch,
} = useDaebus({
serviceName: 'my-service',
httpBaseUrl: 'http://localhost:8080',
wsUrl: 'ws://localhost:8081',
schema: MyServiceSchema,
});Hook for sending WebSocket actions with loading state.
const [sendAction, state] = useAction('restart');
await sendAction({ mode: 'graceful' });
console.log(state.loading, state.error, state.data);Hook for subscribing to real-time channels.
const [latestData, state] = useChannel('notifications', {
autoSubscribe: true,
reconnectOnError: true,
});Hook for HTTP requests with automatic fetching.
const [data, state, refetch] = useFetch('/status', {
refetchOnMount: true,
enabled: true,
});Hook for monitoring WebSocket connection state.
const connection = useConnection(client);
console.log(connection.connected, connection.connecting, connection.error);Type-safe schema definition helper.
const schema = defineSchema({
actions: { /* ... */ },
channels: { /* ... */ },
routes: { /* ... */ },
});// Action definition
const myAction = action(inputSchema, outputSchema);
// Channel definition
const myChannel = channel(dataSchema);
// HTTP route definition
const myRoute = httpRoute({
method: 'POST',
input: inputSchema,
output: outputSchema,
params: { id: z.string() },
});Pre-built schemas for common use cases:
import { CommonSchemas } from '@daebus/client';
CommonSchemas.serviceStatus // Service health status
CommonSchemas.deviceInfo // Device information
CommonSchemas.notification // User notifications
CommonSchemas.errorResponse // Error responses
CommonSchemas.paginationQuery // Pagination parameters
// ... and moreThe library provides custom error types for different scenarios:
import { DaebusError, DaebusTimeoutError, DaebusConnectionError } from '@daebus/client';
try {
await client.sendAction('restart', { mode: 'graceful' });
} catch (error) {
if (error instanceof DaebusTimeoutError) {
console.log('Request timed out');
} else if (error instanceof DaebusConnectionError) {
console.log('Connection failed');
} else if (error instanceof DaebusError) {
console.log('Daebus error:', error.message, error.code, error.details);
}
}const client = new DaebusClient({
serviceName: 'my-service',
httpBaseUrl: 'http://localhost:8080',
wsUrl: 'ws://localhost:8081',
timeout: 10000,
retryAttempts: 3,
retryDelay: 1000,
});const client = new DaebusClient({
serviceName: 'my-service',
httpBaseUrl: 'https://api.myapp.com',
wsUrl: 'wss://ws.myapp.com',
timeout: 30000,
retryAttempts: 5,
retryDelay: 2000,
headers: {
'Authorization': `Bearer ${authToken}`,
'X-API-Version': 'v1',
},
});const mainClient = new DaebusClient({
serviceName: 'main-service',
httpBaseUrl: 'http://localhost:8080',
wsUrl: 'ws://localhost:8081',
});
// Create client for different service with same config
const deviceClient = mainClient.forService('device-service');const client = new DaebusClient({
serviceName: 'my-service',
wsUrl: 'ws://localhost:8081',
// Custom WebSocket sub-protocols
protocols: ['daebus-v1', 'custom-protocol'],
});// Wait for connection with timeout
await client.waitForConnection(5000);
// Ensure connection before operations
await client.ensureConnection();
// Manual reconnection
if (!client.isConnected()) {
await client.connect();
}import { validateSchema, safeValidateSchema } from '@daebus/client';
// Validate data (throws on error)
const validated = validateSchema(mySchema, data);
// Safe validation (returns result object)
const result = safeValidateSchema(mySchema, data);
if (result.success) {
console.log(result.data);
} else {
console.error(result.error);
}- Define schemas early: Create comprehensive schemas for type safety
- Use hooks in components: Leverage React hooks for state management
- Handle errors gracefully: Always wrap async operations in try-catch
- Monitor connection state: Display connection status to users
- Implement retry logic: Use built-in retry mechanisms for reliability
- Validate data: Use schema validation for runtime type safety
- Clean up subscriptions: React hooks handle cleanup automatically
This library is built with TypeScript and provides full type safety:
- ✅ Automatic type inference from schemas
- ✅ Compile-time type checking for requests/responses
- ✅ IntelliSense support in editors
- ✅ Generic types for custom schemas
- ✅ Strict null checks supported
We welcome contributions! Please see our Contributing Guide for details.
MIT License - see LICENSE file for details.