npm package: @slingts/core
Description: Core runtime and function system for Sling framework
Latest version: 0.1.8

# @slingts/core

Core runtime and function system for the Sling framework.

## Installation

```bash
pnpm add @slingts/core
```

## Quick Start

### Define a Function

```typescript
import { defineFunction } from '@slingts/core';

export const getUser = defineFunction({
  handler: async (params: { userId: string }) => {
    return {
      id: params.userId,
      name: 'John Doe',
      email: 'john@example.com',
    };
  },
});
```

### Register and Start Server

```typescript
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

```bash
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:

```typescript
const myFunction = defineFunction({
  handler: async (params: { name: string }) => {
    return { message: `Hello, ${params.name}!` };
  },
});
```

### Validation with Zod

Sling integrates with [Zod](https://zod.dev) for runtime validation and automatic type inference:

```typescript
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:

```json
{
  "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:

```bash
# 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.ts
```

This creates a `sling-client.d.ts` file with full type definitions:

```typescript
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

```typescript
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

```typescript
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

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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.

```typescript
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.

```typescript
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 class
- `ValidationError` - Input validation failed
- `AuthenticationError` - User not authenticated
- `AuthorizationError` - User lacks permission
- `NotFoundError` - Resource not found
- `RateLimitError` - Too many requests
- `TimeoutError` - Operation timed out
- `ServiceError` - External service failed

## License

MIT