# Sockular

A modular, decorator-based framework for building scalable Socket.IO applications with TypeScript.

## Overview

Sockular transforms the way you build real-time applications by providing a clean, modular architecture that eliminates boilerplate code and promotes best practices. Built on top of Socket.IO, it brings structure and maintainability to WebSocket applications through TypeScript decorators and a powerful middleware system.

## Key Features

- **Decorator-Based API**: Define message handlers and room logic using intuitive TypeScript decorators
- **Modular Architecture**: Organize your real-time logic into reusable services
- **Three-Level Middleware System**: Apply middleware at global, service, or method level
- **Auto-Discovery**: Automatically discover and register services from your codebase
- **Unified Client API**: Fluent and Decorative APIs for seamless frontend integration
- **Declarative Room Management**: Manage rooms easily with @JoinRoom, @LeaveRoom, and @EmitToRoom
- **Socket.IO Dependency Injection**: Inject the Socket.IO server instance directly into your services
- **Type-Safe**: Full TypeScript support with comprehensive type definitions
- **Secure by Default**: Global middleware enforcement with explicit opt-out for public endpoints
- **Built-in Rate Limiting**: Protect your server from spam with configurable built-in rate limiting
- **CLI Tools**: Scaffolding commands for project initialization and component generation (`scr` / `sockular`)

## Installation

Sockular is designed to be used with **xfpm**, an ultra-fast and high-performance package manager compared to npm.

To get started:

1. Follow the installation guide for **[xypriss-cli](https://www.npmjs.com/package/xypriss-cli)**.
2. Once `xypriss-cli` is installed, you will have access to `xfpm`.
3. Install Sockular:

```bash
xfpm install sockular # xfpm i sockular
```

## CLI Usage

Sockular comes with a powerful CLI to speed up your development. You can use either `sockular` or the shortcut `scr`.

### Initialize a new project

```bash
npx sockular init my-app
```

### Generate components

```bash
# Generate a service
npx sockular g service chat

# Generate a middleware
npx sockular g middleware auth
```

## Quick Start

### 1. Create a Service

```typescript
import { Service, OnMessage, OnConnect, OnDisconnect } from 'sockular';
import { Socket } from 'sockular';

@Service('chat')
export class ChatService {
  @OnConnect()
  async handleConnect(socket: Socket, clientId: string) {
    console.log(`Client ${clientId} connected to chat`);
  }

  @OnMessage('send_message')
  async handleSendMessage(socket: Socket, data: any, clientId: string) {
    // Handle incoming message
    socket.emit('message_received', {
      message: data.message,
      timestamp: Date.now(),
    });
  }

  @OnDisconnect()
  async handleDisconnect(socket: Socket, clientId: string) {
    console.log(`Client ${clientId} disconnected`);
  }
}
```

### 2. Initialize the Server

```typescript
import { SockularServer } from 'sockular';
import { ChatService } from './services/chat.service';

const server = new SockularServer({
  port: 3000,
  enableLogging: true,
});

// Register services
server.register(ChatService);

// Start the server
await server.start();
```

### 3. Connect from Client

```typescript
import io from 'socket.io-client';

const socket = io('http://localhost:3000', {
  auth: { token: 'your-auth-token' },
});

socket.emit('message', {
  service: 'chat',
  type: 'send_message',
  data: { message: 'Hello, world!' },
});
```

### 4. Using the Sockular Client (Recommended)

Sockular provides a dedicated client for a better developer experience:

```typescript
import { Client } from 'sockular';

@Client.SetUrl('http://localhost:3000')
class ChatClient {
  @Client.OnConnect()
  onConnect() {
    console.log('Connected!');
  }

  @Client.OnMessage('chat', 'message_received')
  onMessage(data: any) {
    console.log('Received:', data.message);
  }
}

const chat = Client.create(ChatClient);
```

See the [Client API Documentation](./docs/CLIENT_API.md) for more details.

## Middleware System

Sockular provides a powerful three-level middleware system for authentication, validation, rate limiting, and more.

### Defining Middleware

```typescript
import { Middleware } from 'sockular';

export const authMiddleware: Middleware = async (socket, data, clientId, next) => {
  const token = socket.handshake.auth?.token;

  if (!token) {
    throw new Error('Authentication required');
  }

  const user = await validateToken(token);
  socket.data.user = user;

  await next();
};
```

### Applying Middleware

```typescript
// Global middleware (applied to all messages)
server.registerMiddleware('auth', authMiddleware);
server.use('auth');

// Service-level middleware
@Service('chat', {
  middleware: ['validation']
})
export class ChatService { }

// Method-level middleware
@OnMessage('admin_action')
@UseMiddleware('adminOnly')
async handleAdminAction(socket: Socket, data: any, clientId: string) { }

// Skip global middleware for public endpoints
@OnMessage('login')
@SkipMiddleware('auth')
async handleLogin(socket: Socket, data: any, clientId: string) { }
```

## Decorators

### @Service(name, options?)

Marks a class as a Sockular service.

```typescript
@Service('chat', {
  middleware: ['validation'],
  rateLimit: { maxRequests: 100, windowMs: 60000 },
})
export class ChatService {}
```

### @OnMessage(messageType)

Defines a handler for a specific message type.

```typescript
@OnMessage('send_message')
async handleSendMessage(socket: Socket, data: any, clientId: string) { }
```

### @OnConnect()

Called when a client connects to the service.

```typescript
@OnConnect()
async handleConnect(socket: Socket, clientId: string) { }
```

### @OnDisconnect()

Called when a client disconnects.

```typescript
@OnDisconnect()
async handleDisconnect(socket: Socket, clientId: string) { }
```

### @UseMiddleware(...names)

Applies additional middleware to a specific method.

```typescript
@UseMiddleware('adminOnly', 'validation')
async handleAdminAction(socket: Socket, data: any, clientId: string) { }
```

### @SkipMiddleware(...names)

Excludes global middleware from a specific method.

````typescript
@SkipMiddleware('auth')
async handlePublicEndpoint(socket: Socket, data: any, clientId: string) { }

### @JoinRoom(room)

Automatically adds the client's socket to a specific room. The `room` parameter can be a string or a function taking `data` as an argument.

```typescript
@OnMessage('join_chat')
@JoinRoom((data) => `room_${data.id}`)
async handleJoin() {}
````

### @LeaveRoom(room)

Automatically removes the client's socket from a specific room.

```typescript
@OnMessage('leave_chat')
@LeaveRoom('global_chat')
async handleLeave() {}
```

### @EmitToRoom(room, event)

Broadcasts the **returned value** of the handler to everyone in the specified room.

```typescript
@OnMessage('send_message')
@EmitToRoom((data) => `room_${data.id}`, 'new_message')
async handleSend(socket, data) {
  return { text: data.message };
}
```

### @SocketIO()

Injects the native Socket.IO `Server` instance into a class property.

```typescript
@SocketIO()
private io: Server;
```

````

## Auto-Discovery

Automatically discover and register services from a directory:

```typescript
await server.discoverServices('./services');
````

## Configuration

```typescript
const server = new SockularServer({
  port: 3000,
  host: 'localhost',
  enableLogging: true,
  enableHeartbeat: true,
  sessionTimeout: 600000,
  maxConnections: 1000,
  rateLimit: {
    enabled: true,
    windowMs: 60000,
    maxRequests: 100,
    global: true, // Apply to all messages automatically
    message: 'Too many requests, please try again later.',
  },
});
```

### Built-in Rate Limiting

Sockular includes a built-in rate limiting middleware that can be enabled globally or registered for specific use.

```typescript
const server = new SockularServer({
  port: 3000,
  rateLimit: {
    enabled: true,
    windowMs: 5000, // 5 seconds
    maxRequests: 5,
    global: true,
  },
});
```

If `global` is set to `false`, you can still apply it to specific services or methods using the name `'rateLimit'`:

```typescript
@Service('chat')
@UseMiddleware('rateLimit')
export class ChatService {}
```

## Architecture Benefits

### Before Sockular

```typescript
io.on('connection', (socket) => {
  socket.on('send_message', async (data) => {
    /* ... */
  });
  socket.on('typing', async (data) => {
    /* ... */
  });
  socket.on('join_room', async (data) => {
    /* ... */
  });
  socket.on('leave_room', async (data) => {
    /* ... */
  });
  socket.on('delete_message', async (data) => {
    /* ... */
  });
  // Hundreds of handlers in one file...
});
```

### With Sockular

```typescript
@Service('chat')
export class ChatService {
  @OnMessage('send_message')
  async handleSendMessage(socket, data, clientId) {}

  @OnMessage('typing')
  async handleTyping(socket, data, clientId) {}

  @OnMessage('join_room')
  async handleJoinRoom(socket, data, clientId) {}
}
```

Clean, modular, and maintainable.

## Examples

See the `examples/` directory for complete working examples:

- `basic/` - Simple chat application
- `with-auth/` - Authentication and authorization
- `with-redis/` - Horizontal scaling with Redis adapter

## Requirements

- Node.js >= 16
- TypeScript >= 4.5
- Socket.IO >= 4.0

## Contributing

Contributions are welcome. Please open an issue or submit a pull request.

## Support

For questions and support, please open an issue on GitHub.

## Roadmap

- [x] CLI tools for scaffolding
- [x] Built-in rate limiting
- [x] Auto-discovery of services
- [x] Unified Client API (Decorative & Fluent)
- [ ] Plugin system
- [ ] Redis adapter for horizontal scaling
- [ ] Prometheus metrics integration
- [ ] WebSocket native support
- [ ] Advanced validation with Zod

---

By the Nehonix Team
