@locci-scheduler/client
v1.0.0-beta
Published
JavaScript client library for Locci Scheduler platform
Maintainers
Readme
Locci Scheduler - JavaScript Client
A powerful and easy-to-use JavaScript/TypeScript client library for the Locci Scheduler platform. Schedule webhook executions with flexible timing options including one-time, recurring (cron), and interval-based schedules.
Installation
npm install @locci-scheduler/clientQuick Start
import { LocciScheduler } from '@locci-scheduler/client';
// Initialize the client
const scheduler = new LocciScheduler({
baseUrl: 'https://api.scheduler.locci.cloud',
apiToken: 'your-jwt-token-here'
});
// Schedule a one-time webhook
const task = await scheduler.scheduleOnce({
name: 'Daily Report Generation',
webhook: {
url: 'https://your-app.com/api/generate-report',
method: 'POST',
payload: { reportType: 'daily' }
},
executeAt: new Date('2024-12-25T10:00:00Z')
});
console.log('Task scheduled:', task.id);Configuration
const scheduler = new LocciScheduler({
baseUrl: 'https://api.scheduler.locci.cloud', // Required: Your server URL
apiToken: 'your-jwt-token', // Required: Your JWT token
timeout: 30000, // Optional: Request timeout (ms)
retries: 3 // Optional: Number of retries
});Usage Examples
One-time Scheduling
// Schedule a task to run once at a specific time
const task = await scheduler.scheduleOnce({
name: 'Welcome Email',
description: 'Send welcome email to new user',
webhook: {
url: 'https://your-app.com/api/send-welcome-email',
method: 'POST',
headers: {
'X-API-Key': 'your-publishable-api-key' // We recommend setting .env on the server side
},
payload: {
userId: '12345',
template: 'welcome'
}
},
executeAt: new Date(Date.now() + 3600000), // 1 hour from now
metadata: {
userId: '12345',
campaign: 'onboarding'
}
});Recurring Schedules (Cron)
// Daily at 9:00 AM UTC
const dailyTask = await scheduler.scheduleDaily({
name: 'Daily Backup',
webhook: {
url: 'https://your-app.com/api/backup',
method: 'POST'
},
time: '09:00'
});
// Weekly on Monday at 2:30 PM
const weeklyTask = await scheduler.scheduleWeekly({
name: 'Weekly Report',
webhook: {
url: 'https://your-app.com/api/weekly-report',
method: 'POST'
},
dayOfWeek: 1, // Monday
time: '14:30'
});
// Custom cron expression
const customTask = await scheduler.scheduleRecurring({
name: 'Custom Schedule',
webhook: {
url: 'https://your-app.com/api/custom-task',
method: 'POST'
},
cronExpression: '0 */4 * * *', // Every 4 hours
timezone: 'America/New_York'
});Interval-based Scheduling
// Every 30 minutes
const intervalTask = await scheduler.scheduleInterval({
name: 'Health Check',
webhook: {
url: 'https://your-app.com/api/health-check',
method: 'GET'
},
intervalSeconds: 1800, // 30 minutes
startAt: new Date(),
endDate: new Date(Date.now() + 86400000) // End after 24 hours
});
// Convenience methods
const minuteTask = await scheduler.scheduleEveryMinute({
name: 'Minute Task',
webhook: { url: 'https://your-app.com/api/minute-task', method: 'POST' }
});
const hourlyTask = await scheduler.scheduleEveryHour({
name: 'Hourly Task',
webhook: { url: 'https://your-app.com/api/hourly-task', method: 'POST' }
});Webhook Authentication
// API Key authentication
const taskWithApiKey = await scheduler.createTask({
name: 'API Key Task',
webhook: {
url: 'https://your-app.com/api/secure-endpoint',
method: 'POST',
authentication: {
type: 'apiKey',
apiKey: {
headerName: 'X-API-Key',
key: 'your-secret-api-key'
}
}
},
schedule: { type: 'once', executeAt: new Date(Date.now() + 3600000) }
});
// Bearer token authentication
const taskWithBearer = await scheduler.createTask({
name: 'Bearer Token Task',
webhook: {
url: 'https://your-app.com/api/secure-endpoint',
method: 'POST',
authentication: {
type: 'bearerToken',
bearerToken: {
token: 'your-bearer-token'
}
}
},
schedule: { type: 'once', executeAt: new Date(Date.now() + 3600000) }
});
// Basic authentication
const taskWithBasicAuth = await scheduler.createTask({
name: 'Basic Auth Task',
webhook: {
url: 'https://your-app.com/api/secure-endpoint',
method: 'POST',
authentication: {
type: 'basicAuth',
basicAuth: {
username: 'your-username',
password: 'your-password'
}
}
},
schedule: { type: 'once', executeAt: new Date(Date.now() + 3600000) }
});Task Management
// List all tasks
const taskList = await scheduler.listTasks({ page: 1, perPage: 20 });
console.log(`Found ${taskList.total} tasks`);
// Get specific task
const task = await scheduler.getTask('task-id-here');
console.log('Task:', task.name);
// Update a task
const updatedTask = await scheduler.updateTask('task-id-here', {
name: 'Updated Task Name',
description: 'New description'
});
// Pause/Resume/Cancel tasks
await scheduler.pauseTask('task-id-here');
await scheduler.resumeTask('task-id-here');
await scheduler.cancelTask('task-id-here');
// Manual trigger
await scheduler.triggerTask('task-id-here');
// Delete task
await scheduler.deleteTask('task-id-here');Execution History
// Get execution history for a task
const history = await scheduler.getTaskHistory('task-id-here');
console.log(`Task has ${history.total} executions`);
history.executions.forEach(execution => {
console.log(`${execution.executedAt}: ${execution.status} (${execution.durationMs}ms)`);
if (execution.errorMessage) {
console.error('Error:', execution.errorMessage);
}
});Error Handling
import {
SchedulerError,
AuthenticationError,
ValidationError,
NotFoundError,
RateLimitError
} from '@locci-scheduler/client';
try {
const task = await scheduler.createTask(taskOptions);
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.message);
// Handle authentication error (e.g., refresh token)
} else if (error instanceof ValidationError) {
console.error('Validation error:', error.message, error.details);
// Handle validation errors
} else if (error instanceof NotFoundError) {
console.error('Resource not found:', error.message);
} else if (error instanceof RateLimitError) {
console.error('Rate limit exceeded:', error.message);
// Implement backoff strategy
} else if (error instanceof SchedulerError) {
console.error('Scheduler error:', error.message, error.statusCode);
} else {
console.error('Unexpected error:', error);
}
}Advanced Configuration
Retry Configuration
const taskWithRetries = await scheduler.createTask({
name: 'Resilient Task',
webhook: {
url: 'https://unreliable-service.com/api/endpoint',
method: 'POST',
retryConfig: {
maxAttempts: 5, // Maximum retry attempts
backoffSeconds: 2, // Initial backoff delay
backoffMultiplier: 2.0, // Exponential backoff multiplier
maxBackoffSeconds: 300 // Maximum backoff delay (5 minutes)
},
timeoutSeconds: 45 // Custom timeout for this webhook
},
schedule: { type: 'once', executeAt: new Date(Date.now() + 3600000) }
});Complex Payloads and Headers
const complexTask = await scheduler.createTask({
name: 'Complex API Call',
webhook: {
url: 'https://api.example.com/v1/process',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Version': '2.1',
'X-Client-ID': 'webhook-scheduler',
'User-Agent': 'WebhookScheduler/1.0'
},
payload: {
event: 'scheduled_task',
data: {
timestamp: new Date().toISOString(),
source: 'webhook-scheduler',
payload: {
type: 'batch_process',
items: ['item1', 'item2', 'item3'],
options: {
priority: 'high',
async: true
}
}
},
metadata: {
version: '1.0',
environment: 'production'
}
}
},
schedule: {
type: 'recurring',
cronExpression: '0 2 * * 1-5', // Weekdays at 2 AM
timezone: 'UTC'
}
});TypeScript Support
The library is built with TypeScript and provides full type safety:
import {
LocciScheduler,
Task,
TaskExecution,
CreateTaskOptions,
ScheduleConfig
} from '@locci-scheduler/client';
// Fully typed configurations
const config: SchedulerConfig = {
baseUrl: 'https://api.scheduler.locci.cloud',
apiToken: process.env.LOCCI_SCHEDULER_TOKEN!,
timeout: 30000
};
const scheduler = new LocciScheduler(config);
// Type-safe task creation
const taskOptions: CreateTaskOptions = {
name: 'Typed Task',
webhook: {
url: 'https://api.example.com/webhook',
method: 'POST', // Typed as HttpMethod
payload: {
// Any JSON-serializable data
message: 'Hello from TypeScript!'
}
},
schedule: {
type: 'once', // Typed schedule configuration
executeAt: new Date(Date.now() + 3600000)
}
};
const task: Task = await scheduler.createTask(taskOptions);Best Practices
1. Environment Configuration
// Use environment variables for configuration
const scheduler = new LocciScheduler({
baseUrl: process.env.LOCCI_SCHEDULER_URL || 'https://api.scheduler.locci.cloud',
apiToken: process.env.LOCCI_SCHEDULER_TOKEN,
timeout: parseInt(process.env.DEFAULT_WEBHOOK_TIMEOUT || '30000'),
retries: parseInt(process.env.MAX_CONCURRENT_EXECUTIONS || '3')
});2. Idempotent Operations
// Use metadata to track operations and avoid duplicates
const task = await scheduler.createTask({
name: 'User Onboarding Email',
webhook: {
url: 'https://your-app.com/api/send-email',
method: 'POST',
payload: { userId: '12345', template: 'onboarding' }
},
schedule: { type: 'once', executeAt: new Date(Date.now() + 3600000) },
metadata: {
userId: '12345',
operation: 'user_onboarding',
idempotencyKey: 'user-12345-onboarding-2024-01-01'
}
});3. Graceful Error Handling
async function scheduleWithRetry(taskOptions, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await scheduler.createTask(taskOptions);
} catch (error) {
if (error instanceof RateLimitError && attempt < maxRetries) {
// Exponential backoff for rate limits
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}4. Batch Operations
// Schedule multiple related tasks
async function scheduleUserOnboarding(userId) {
const baseTime = new Date(Date.now() + 3600000); // 1 hour from now
const tasks = await Promise.all([
// Welcome email immediately
scheduler.scheduleOnce({
name: `Welcome Email - User ${userId}`,
webhook: {
url: 'https://your-app.com/api/send-email',
method: 'POST',
payload: { userId, template: 'welcome' }
},
executeAt: baseTime,
metadata: { userId, step: 'welcome' }
}),
// Follow-up email after 3 days
scheduler.scheduleOnce({
name: `Follow-up Email - User ${userId}`,
webhook: {
url: 'https://your-app.com/api/send-email',
method: 'POST',
payload: { userId, template: 'followup' }
},
executeAt: new Date(baseTime.getTime() + 3 * 24 * 60 * 60 * 1000),
metadata: { userId, step: 'followup' }
}),
// Survey after 7 days
scheduler.scheduleOnce({
name: `Survey Email - User ${userId}`,
webhook: {
url: 'https://your-app.com/api/send-email',
method: 'POST',
payload: { userId, template: 'survey' }
},
executeAt: new Date(baseTime.getTime() + 7 * 24 * 60 * 60 * 1000),
metadata: { userId, step: 'survey' }
})
]);
return tasks;
}API Reference
WebhookScheduler Class
Constructor
new LocciScheduler(config: SchedulerConfig)
Methods
Task Management:
createTask(options: CreateTaskOptions): Promise<Task>getTask(taskId: string): Promise<Task>listTasks(options?: PaginationOptions): Promise<TaskListResponse>updateTask(taskId: string, options: UpdateTaskOptions): Promise<Task>deleteTask(taskId: string): Promise<void>
Task Control:
triggerTask(taskId: string): Promise<void>pauseTask(taskId: string): Promise<Task>resumeTask(taskId: string): Promise<Task>cancelTask(taskId: string): Promise<Task>
Scheduling Helpers:
scheduleOnce(options): Promise<Task>scheduleRecurring(options): Promise<Task>scheduleInterval(options): Promise<Task>scheduleDaily(options): Promise<Task>scheduleWeekly(options): Promise<Task>scheduleEveryMinute(options): Promise<Task>scheduleEveryHour(options): Promise<Task>
History:
getTaskHistory(taskId: string): Promise<TaskHistoryResponse>
Testing
// examples/test.js
const { LocciScheduler } = require('@locci-scheduler/client');
async function runTests() {
const scheduler = new LocciScheduler({
baseUrl: 'http://localhost:9696',
apiToken: 'your-test-token'
});
try {
// Test creating a simple task
console.log('Creating test task...');
const task = await scheduler.scheduleOnce({
name: 'Test Task',
webhook: {
url: 'https://httpbin.org/post',
method: 'POST',
payload: { test: true, timestamp: new Date().toISOString() }
},
executeAt: new Date(Date.now() + 60000) // 1 minute from now
});
console.log('Task created:', task.id);
// Test getting the task
const retrievedTask = await scheduler.getTask(task.id);
console.log('Task retrieved:', retrievedTask.name);
// Test listing tasks
const taskList = await scheduler.listTasks();
console.log(`Total tasks: ${taskList.total}`);
// Test manual trigger
console.log('Triggering task manually...');
await scheduler.triggerTask(task.id);
// Wait a moment then check history
setTimeout(async () => {
const history = await scheduler.getTaskHistory(task.id);
console.log(`Executions: ${history.total}`);
// Clean up
await scheduler.deleteTask(task.id);
console.log('Test completed successfully!');
}, 2000);
} catch (error) {
console.error('Test failed:', error.message);
}
}
runTests();Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see the LICENSE file for details.
Support
- Documentation: https://docs.scheduler.locci.cloud
- Issues: GitHub Issues
- Email: [email protected]
