# OT Middleware

## Content

The middleware mechanism in `js-collaboration-ot` allows developers to intercept and customize logic in the server-side OT (Operational Transformation) processing flow, such as permission validation or logging. This document explains how to use middleware, including its lifecycle, registration methods, and practical examples.

## Basic Conception

Middleware is a core extension feature of `DocumentServices`, used to **add custom logic** during the processing stages of operations (`op`) and snapshots (`snapshot`).
**Purpose**:

* Intercept and validate the operation flow
* Modify the context or abort processing

**Applicable Scenarios**: User authentication, data validation, logging, performance monitoring, etc.
**Difference from hooks**: Middleware can interrupt the flow and return errors, whereas hooks only listen to events.

## Lifecycle

Middleware covers multiple stages of the OT processing flow, with each stage corresponding to an action. Developers can selectively intervene in these stages. The following are the supported middleware actions and their trigger timings:

| Action | Description |
| ------ | ----------- |
| `receive` | Triggered when the server receives a client message, used for initial validation or logging. |
| `submit` | Triggered when an operation (`op`) is about to be submitted, allowing validation of operation data. |
| `commit` | Triggered when an operation is about to be committed to the database, after the operation has been transformed, allowing final validation. |
| `afterWrite` | Triggered after an operation is successfully written to the database, used for subsequent processing or notifications. |
| `submitSnapshot` | Triggered when a snapshot submission begins, allowing control over snapshot update logic. |
| `apply` | Triggered when an operation is about to be applied to a snapshot, with the snapshot still in its old state. |
| `commitSnapshot` | Triggered when a snapshot is about to be committed to the database. |
| `readSnapshots` | Triggered when one or more snapshots are loaded from the database (e.g., during `fetch` or `subscribe`), allowing rejection of specific snapshot reads. |
| `readOp` | Triggered when an operation is loaded from the database, allowing rejection of operation reads. |
| `reply` | Triggered when the document is about to send a non-error reply to the client. |

## Middleware Functions

Middleware is an asynchronous function that receives `context` and `next` parameters:

* `context`: Contains contextual information for the current action (e.g., `connection`, `request`).
* `next`: A function to continue execution, which can be called with an error to abort the flow.
    * `await next()`: Continues executing subsequent middleware or processing logic.
    * `await next(error)`: Aborts the flow and returns an error.

### Example: Basic Middleware

```typescript
docService.use('submit', async (context, next) => {
    const user = context.connection.tags.get('user');
    if (user.role === 'editor') {
        console.log('Submitting operation:', context.request.op);
        await next(); // Continue
    } else {
        await next('No permission'); // Abort
    }
});
```

## Registering Middleware

Middleware is registered using the [use](https://developer.mescius.com/spreadjs/api/collaboration/js-collaboration-ot/classes/DocumentServices#use "https://developer.mescius.com/spreadjs/api/collaboration/js-collaboration-ot/classes/DocumentServices#use") method of `DocumentServices`.

```typescript
import { DocumentServices } from '@mescius/js-collaboration-ot';

const docService = new DocumentServices();

docService.use('receive', async (context, next) => {
    console.log('Message received:', context.request);
    await next();
});
```

## Middleware Execution Order

Multiple middleware for the same action are executed in the order of registration. If a middleware calls `next(error)`, subsequent middleware will be skipped.

### Example: Execution Order

```typescript
docService.use('submit', async (context, next) => {
  console.log('Middleware 1');
  await next();
});
docService.use('submit', async (context, next) => {
  console.log('Middleware 2');
  await next();
});
docService.use('submit', async (context, next) => {
  console.log('Middleware 3');
  await next();
});
// Output:
// Middleware 1
// Middleware 2
// Middleware 3
```

### Example: Error Handling

```typescript
docService.use('submit', async (context, next) => {
    console.log('Middleware 1');
    await next();
});
docService.use('submit', async (context, next) => {
    console.log('Middleware 2');
    await next('Test error');
});
docService.use('submit', async (context, next) => {
    console.log('Middleware 3'); // Will not be executed
    await next();
});
// Output:
// Middleware 1
// Middleware 2
// Error returned to the client, triggering the client-side error event
```

## Use Cases

The following are common middleware use cases and their implementations:

### 1. Permission Validation

```typescript
docService.use('submit', async (context, next) => {
    const user = context.connection.tags.get('user');
    if (user.role === 'editor') {
        console.log('Submitting operation:', context.request.op);
        await next(); // Continue
    } else {
        await next('No permission'); // Abort
    }
});
```

### 2. Logging

```typescript
docService.use('afterWrite', async (context, next) => {
    console.log('Operation written to database:', context.request.op);
    await next();
});
```

## Summary

Middleware provides powerful flow control capabilities for the server-side of `js-collaboration-ot`. By registering middleware at different lifecycle stages, you can implement validation, logging and other functionalities.