@slingts/core
v0.1.8
Published
Core runtime and function system for Sling framework
Maintainers
Readme
@slingts/core
Core runtime and function system for the Sling framework.
Installation
pnpm add @slingts/coreQuick Start
Define a Function
import { defineFunction } from '@slingts/core';
export const getUser = defineFunction({
handler: async (params: { userId: string }) => {
return {
id: params.userId,
name: 'John Doe',
email: '[email protected]',
};
},
});Register and Start Server
import { registerFunction, createSlingServer } from '@slingts/core';
import { getUser } from './functions/getUser';
// Register functions
registerFunction('getUser', getUser);
// Start server
const server = await createSlingServer({ port: 3000 });Call from Frontend
curl -X POST http://localhost:3000/getUser \
-H "Content-Type: application/json" \
-d '{"userId": "123"}'Features
Type-Safe Functions
Functions are fully typed, with automatic type inference:
const myFunction = defineFunction({
handler: async (params: { name: string }) => {
return { message: `Hello, ${params.name}!` };
},
});Validation with Zod
Sling integrates with Zod for runtime validation and automatic type inference:
import { defineFunction, z } from '@slingts/core';
export const createUser = defineFunction({
validate: z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().min(18).optional(),
tags: z.array(z.string()).max(10).optional(),
}),
handler: async (params) => {
// params is fully typed: { name: string; email: string; age?: number; tags?: string[] }
return {
id: '123',
...params,
createdAt: new Date().toISOString(),
};
},
});Validation Features
- Automatic type inference - Parameter types are inferred from Zod schemas
- Runtime validation - Invalid inputs are rejected before the handler executes
- Detailed error messages - Validation errors include field-level details
- All Zod features - Supports nested objects, arrays, unions, refinements, transforms, etc.
Error Handling
When validation fails, a ValidationError is returned with field details:
{
"success": false,
"error": {
"message": "Validation failed: Invalid email",
"code": "VALIDATION_ERROR",
"statusCode": 400,
"details": {
"email": ["Invalid email"],
"age": ["Number must be greater than or equal to 18"]
}
}
}Type Generation
Generate TypeScript types for your frontend automatically:
# Generate types once
npx sling generate
# Watch mode - regenerate on changes
npx sling generate --watch
# Custom paths
npx sling generate --dir ./src/api --output ./src/types/api.d.tsThis creates a sling-client.d.ts file with full type definitions:
export interface SlingClient {
createUser(params: {
name: string;
email: string;
age?: number;
tags?: string[];
}): Promise<{ id: string; name: string; email: string; ... }>;
// ... all other functions
}Service Adapters
Sling provides a pluggable adapter system for services like databases, storage, email, etc.
Using Service Adapters
import { globalAdapterRegistry, createMemoryDBAdapter } from '@slingts/core';
// Register an adapter
const dbAdapter = createMemoryDBAdapter();
globalAdapterRegistry.register('db', dbAdapter, {
adapter: 'memory-db',
config: { debug: true },
});
// Initialize and get services
const services = {
db: await globalAdapterRegistry.getClient('db'),
};
// Pass to server
await createSlingServer({
port: 3000,
services,
});Accessing Services in Functions
export const createUser = defineFunction({
validate: z.object({
name: z.string(),
email: z.string().email(),
}),
handler: async (params, ctx) => {
// Access service via context
const user = await ctx.services.db.create('users', params);
return user;
},
});Built-in Adapters
- MemoryDBAdapter - In-memory database for development and testing
Creating Custom Adapters
import type { ServiceAdapter } from '@slingts/core';
class MyServiceAdapter implements ServiceAdapter<MyClient, MyConfig> {
name = 'my-service';
async initialize(config?: MyConfig): Promise<void> {
// Initialize your service
}
async shutdown(): Promise<void> {
// Cleanup resources
}
async healthCheck(): Promise<boolean> {
// Check if service is healthy
return true;
}
getClient(): MyClient {
// Return service client
return this.client;
}
}AuthorizationControl access with authorization functions:
export const deleteUser = defineFunction({
auth: 'required',
authorize: async (params, ctx) => {
return ctx.user?.role === 'admin';
},
handler: async (params: { userId: string }) => {
// Only admins can reach here
return { success: true };
},
});Error Handling
Use built-in error classes for consistent error responses:
import { NotFoundError, AuthorizationError } from '@slingts/core';
export const getPost = defineFunction({
handler: async (params: { postId: string }, ctx) => {
const post = await db.posts.findOne({ id: params.postId });
if (!post) {
throw new NotFoundError('Post not found');
}
if (post.isPrivate && post.authorId !== ctx.user?.id) {
throw new AuthorizationError('Cannot access private post');
}
return post;
},
});Function Context
Every handler receives a context object:
export const myFunction = defineFunction({
handler: async (params, ctx) => {
// Access request information
ctx.requestId; // Unique request ID
ctx.timestamp; // Request timestamp
ctx.user; // Authenticated user (if any)
// Use logger
ctx.log.info('Processing request');
ctx.log.error('Something went wrong');
// Access environment
ctx.env.NODE_ENV;
// Services (Phase 3)
// ctx.services.db
// ctx.services.storage
return { result: 'success' };
},
});API Reference
defineFunction(definition)
Create a function definition.
interface FunctionDefinition {
auth?: 'required' | 'optional' | 'none';
authorize?: (params, ctx) => boolean | Promise<boolean>;
rateLimit?: RateLimitConfig | false;
timeout?: number;
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
description?: string;
handler: (params, ctx) => Promise<result> | result;
}registerFunction(name, definition)
Register a function with the global registry.
createSlingServer(options)
Create and start an HTTP server.
interface ServerOptions {
port?: number; // Default: 3000
host?: string; // Default: '0.0.0.0'
isDev?: boolean; // Default: NODE_ENV === 'development'
timeout?: number; // Default: 30000 (30 seconds)
}Built-in Endpoints
/_health- Health check endpoint/_functions- List all registered functions with metadata
Error Classes
SlingError- Base error classValidationError- Input validation failedAuthenticationError- User not authenticatedAuthorizationError- User lacks permissionNotFoundError- Resource not foundRateLimitError- Too many requestsTimeoutError- Operation timed outServiceError- External service failed
License
MIT
