@crosspost/scheduler-sdk
Version:
TypeScript SDK client for the Scheduler service
180 lines (179 loc) • 5.19 kB
JavaScript
import axios from 'axios';
import { JobStatus, } from './types.js';
import { ApiError, NetworkError, JobNotFoundError, DuplicateJobError, } from './errors.js';
/**
* Client for interacting with the Scheduler API
*/
export class SchedulerClient {
client;
baseUrl;
/**
* Create a new Scheduler client
* @param options Client configuration options
*/
constructor(options = {}) {
this.baseUrl = options.baseUrl || 'http://localhost:3000';
this.client = axios.create({
baseURL: this.baseUrl,
timeout: options.timeout || 10000,
headers: {
'Content-Type': 'application/json',
...options.headers,
},
});
}
/**
* Create a new job
* @param job Job configuration
* @returns Created job
*/
async createJob(job) {
try {
const response = await this.client.post('/jobs', job);
return response.data.job;
}
catch (error) {
this.handleError(error, {
409: (err) => new DuplicateJobError(job.name),
});
}
}
/**
* Get a job by ID
* @param id Job ID
* @returns Job
*/
async getJob(id) {
try {
const response = await this.client.get(`/jobs/${id}`);
return response.data;
}
catch (error) {
this.handleError(error, {
404: (err) => new JobNotFoundError(id),
});
}
}
/**
* Update a job
* @param id Job ID
* @param job Job configuration
* @returns Updated job
*/
async updateJob(id, job) {
try {
const response = await this.client.put(`/jobs/${id}`, job);
return response.data.job;
}
catch (error) {
this.handleError(error, {
404: (err) => new JobNotFoundError(id),
});
}
}
/**
* Delete a job
* @param id Job ID
* @returns Deleted job ID
*/
async deleteJob(id) {
try {
const response = await this.client.delete(`/jobs/${id}`);
return response.data.id;
}
catch (error) {
this.handleError(error, {
404: (err) => new JobNotFoundError(id),
});
}
}
/**
* List jobs with optional filtering
* @param params Query parameters
* @returns List of jobs
*/
async listJobs(params) {
try {
const response = await this.client.get('/jobs', {
params,
});
return response.data.jobs;
}
catch (error) {
this.handleError(error);
}
}
/**
* Find jobs by name
* @param name Job name to search for
* @returns List of matching jobs
*/
async findJobsByName(name) {
const allJobs = await this.listJobs();
return allJobs.filter(job => job.name === name);
}
/**
* Check if a job with the given name exists
* @param name Job name to check
* @returns True if a job with the name exists, false otherwise
*/
async jobExistsByName(name) {
const jobs = await this.findJobsByName(name);
return jobs.length > 0;
}
/**
* Create a job if it doesn't already exist
* @param job Job configuration
* @returns Created job or existing job
*/
async createJobIfNotExists(job) {
const existingJobs = await this.findJobsByName(job.name);
if (existingJobs.length > 0) {
return existingJobs[0];
}
return this.createJob(job);
}
/**
* List active jobs
* @returns List of active jobs
*/
async listActiveJobs() {
return this.listJobs({ status: JobStatus.ACTIVE });
}
/**
* List failed jobs
* @returns List of failed jobs
*/
async listFailedJobs() {
return this.listJobs({ status: JobStatus.FAILED });
}
/**
* List inactive jobs
* @returns List of inactive jobs
*/
async listInactiveJobs() {
return this.listJobs({ status: JobStatus.INACTIVE });
}
/**
* Handle API errors
* @param error Error from axios
* @param statusHandlers Custom handlers for specific status codes
*/
handleError(error, statusHandlers = {}) {
if (axios.isAxiosError(error)) {
const statusCode = error.response?.status || 500;
const data = error.response?.data;
// Use custom handler if available for this status code
if (statusHandlers[statusCode]) {
throw statusHandlers[statusCode](error);
}
// Default error handling
if (statusCode === 404) {
throw new JobNotFoundError(error.config?.url?.split('/').pop() || 'unknown');
}
throw new ApiError(error.message || `API request failed with status ${statusCode}`, statusCode, data);
}
// Network or other errors
throw new NetworkError(error?.message || 'Network error occurred', error);
}
}