A modern, type-safe task execution framework with built-in middleware support, comprehensive testing capabilities, and production-ready features.
npm install @xrundev/sdkA modern, type-safe task execution framework with built-in middleware support, comprehensive testing capabilities, and production-ready features.
✅ Type-Safe: Full TypeScript support with strict typing
✅ Testable: Comprehensive unit testing support with dependency injection
✅ Middleware System: Plugin-based architecture for cross-cutting concerns
✅ Production Ready: Built-in error handling, timeouts, and retries
✅ Docker Support: Containerized execution with environment-based configuration
✅ Monitoring: Optional metrics collection and structured logging
``bash`
npm install @xrundev/sdk
`typescript
// tasks/hello-world.ts
import { task } from '@xrundev/sdk';
export const helloWorld = task(
{
name: 'hello-world',
description: 'A simple hello world task',
},
async (payload: { name: string }) => {
return { message: Hello, ${payload.name}! };`
}
);
`bashBuild the task runner
npx xrun build
$3
`bash
docker run --rm \
-e TASK_ID=hello-world \
-e TASK_PAYLOAD='{"name": "World"}' \
-e JOB_ID=job-123 \
xrun-task-runner:latest
`Testing
The SDK includes comprehensive testing support with automatic console mocking to keep test output clean.
$3
All tests automatically include console mocking to prevent log output from cluttering test results. The test setup file (
src/test-setup.ts) mocks all console methods globally.$3
`typescript
import { describe, it, expect, vi } from 'vitest';
import { createConsoleSpy } from '../test-setup.js';describe('My Task', () => {
it('should execute successfully', async () => {
// Console output is automatically mocked
console.log('This will not appear in test output');
// If you need to verify console calls, use the console spy
const consoleSpy = createConsoleSpy();
// Your test logic here
const result = await myTask({ input: 'test' });
// Verify console calls if needed
expect(consoleSpy.log).toHaveBeenCalledWith('Expected message');
});
});
`$3
The following console methods are automatically mocked in all tests:
-
console.log, console.error, console.warn
- console.info, console.debug, console.trace
- console.dir, console.table, console.group
- console.time, console.count, and moreArchitecture
$3
Tasks are defined using the
task() function with a configuration and handler:`typescript
import { task } from '@xrundev/sdk';interface MyPayload {
input: string;
options?: {
uppercase?: boolean;
};
}
interface MyResult {
output: string;
metadata: {
processedAt: string;
};
}
export const myTask = task(
{
name: 'my-task',
description: 'Processes input with optional transformations',
runtime: {
size: 'm', // xs, s, m, l, xl
},
},
async (payload, context) => {
const { input, options = {} } = payload;
const { jobId, taskId, taskName } = context;
let output = input;
if (options.uppercase) {
output = input.toUpperCase();
}
return {
output,
metadata: {
processedAt: new Date().toISOString(),
},
};
}
);
`$3
The SDK includes a powerful middleware system for handling cross-cutting concerns:
#### Built-in Middleware
`typescript
import {
TaskRunner,
LoggingMiddleware,
TimeoutMiddleware,
RetryMiddleware,
MetricsMiddleware,
} from '@xrundev/sdk';const runner = new TaskRunner({
middleware: [
new LoggingMiddleware(),
new TimeoutMiddleware(30000), // 30 seconds
new RetryMiddleware(3, 1000, 2), // 3 retries, 1s delay, 2x backoff
new MetricsMiddleware((metrics) => console.log(metrics)),
],
});
`#### Custom Middleware
`typescript
import { TaskMiddleware, TaskExecutionContext } from '@xrundev/sdk';export class AuthMiddleware implements TaskMiddleware {
name = 'auth';
async before(context: TaskExecutionContext): Promise {
// Validate authentication
const auth = context.metadata?.auth;
if (!auth) {
throw new Error('Authentication required');
}
}
async after(context: TaskExecutionContext, result: unknown): Promise {
// Log successful execution
console.log(
Task ${context.taskId} completed by user ${context.metadata?.userId}
);
} async onError(context: TaskExecutionContext, error: Error): Promise {
// Log authentication failures
if (error.message.includes('Authentication')) {
console.error(
Auth failure for task ${context.taskId});
}
}
}
`Configuration
$3
| Variable | Required | Default | Description |
| ---------------- | -------- | ------- | ----------------------------- |
|
TASK_ID | ✅ | - | The ID of the task to execute |
| TASK_PAYLOAD | ✅ | - | JSON payload for the task |
| JOB_ID | ✅ | - | Job ID for tracking |
| TASK_TIMEOUT | ❌ | 300000 | Timeout in milliseconds |
| TASK_RETRIES | ❌ | 0 | Number of retries on failure |
| ENABLE_METRICS | ❌ | false | Enable metrics collection |$3
`typescript
import { TaskRunner, createDefaultMiddleware } from '@xrundev/sdk';const runner = new TaskRunner({
timeout: 60000,
logger: new CustomLogger(),
middleware: createDefaultMiddleware({
timeout: 60000,
retries: 3,
enableMetrics: true,
}),
});
`Testing
$3
`typescript
// __tests__/my-task.test.ts
import { describe, it, expect } from 'vitest';
import { myTask } from '../tasks/my-task.js';describe('myTask', () => {
it('should process input correctly', async () => {
const payload = { input: 'hello' };
const result = await myTask.run(payload);
expect(result.output).toBe('hello');
expect(result.metadata.processedAt).toBeDefined();
});
it('should handle uppercase option', async () => {
const payload = { input: 'hello', options: { uppercase: true } };
const result = await myTask.run(payload);
expect(result.output).toBe('HELLO');
});
});
`$3
`typescript
// __tests__/integration.test.ts
import { describe, it, expect } from 'vitest';
import { TaskRunner, TaskExecutionContext } from '@xrundev/sdk';describe('Task Integration', () => {
it('should execute task with full context', async () => {
const context: TaskExecutionContext = {
jobId: 'job-123',
taskId: 'my-task',
payload: { input: 'test' },
config: {},
startTime: Date.now(),
};
const runner = new TaskRunner();
const result = await runner.execute(context);
expect(result).toBeDefined();
});
});
`$3
`typescript
import { vi } from 'vitest';
import { TaskRunner } from '@xrundev/sdk';const mockMiddleware = {
name: 'mock',
before: vi.fn(),
after: vi.fn(),
onError: vi.fn(),
};
const runner = new TaskRunner({
middleware: [mockMiddleware],
});
`CLI Commands
$3
`bash
npx xrun build [options]Options:
-s, --skip-cleanup Skip cleanup of temporary files
`Builds your tasks into a Docker-ready bundle with:
- Compiled and bundled task definitions
- Runtime entry point
- Docker configuration files
$3
`bash
npx xrun package
`Creates a Docker image with your tasks:
- Builds a lightweight Alpine-based image
- Includes all dependencies
- Configures proper entry point and environment
Advanced Usage
$3
For advanced scenarios, you can create a custom runtime:
`typescript
// custom-runtime.ts
import {
main,
TaskRunner,
createContextFromEnv,
DefaultLogger,
} from '@xrundev/sdk';
import { CustomMiddleware } from './middleware.js';// Custom configuration
const customMain = async () => {
const context = createContextFromEnv();
const runner = new TaskRunner({
logger: new DefaultLogger(),
middleware: [
new CustomMiddleware(),
// ... other middleware
],
});
return runner.execute(context);
};
// Use custom main instead of default
customMain().catch((error) => {
console.error('Custom runtime error:', error);
process.exit(1);
});
`$3
`typescript
import { TaskRunnerError } from '@xrundev/sdk';export const myTask = task(
{ name: 'error-handling-task', description: 'Demonstrates error handling' },
async (payload: { shouldFail?: boolean }) => {
if (payload.shouldFail) {
throw new TaskRunnerError(
'Task intentionally failed',
'INTENTIONAL_FAILURE'
);
}
return { success: true };
}
);
``If you're migrating from the old template-based system, see our Migration Guide for step-by-step instructions.
Check out the examples directory for more comprehensive examples including:
- Data processing tasks
- API integration tasks
- Batch processing workflows
- Custom middleware implementations
We welcome contributions! Please see our Contributing Guide for details.
MIT License - see LICENSE for details.