# Constructing and Using DocumentServices

## Content

The `DocumentServices` class in `js-collaboration-ot` is the core component of server-side OT (Operational Transformation) functionality, used to manage document snapshots and operations, including storage, submission, and retrieval. This document explains how to construct and use [DocumentServices](/spreadjs/api/v18/collaboration/js-collaboration-ot/classes/DocumentServices), including:

* Store and read document snapshots and operations
* Handle operation submission and snapshot updates
* Add middleware and hook extensions

## **Use Cases**

* Customize OT behavior
* Optimize performance
* Implement specific persistence solutions

## Initialization

[Initalizing DocumentServices](/spreadjs/docs/v18/spreadjs-collaboration-server/collaboration-framework/js-collaboration-ot/initalizing-documentservices)

## Construction

`DocumentServices` accepts a configuration object ([IDocConfig](/spreadjs/api/v18/collaboration/js-collaboration-ot/interfaces/IDocConfig)) through its constructor, allowing developers to customize the database and behavior parameters.

### Configuration Parameters

| Parameter Name | Type | Description | Default Value |
| -------------- | ---- | ----------- | ------------- |
| `db` | `IDataBaseAdapter` | Database adapter, used to store snapshots and operations. | `MemoryDb` |
| `milestoneDb` | `IMilestoneDataBaseAdapter` | Milestone database adapter, used for periodic snapshot storage. | In-memory implementation |
| `maxSubmitRetries` | `number` | Maximum number of retries for operation submission. | Unlimited |
| `submitSnapshotBatchSize` | `number` | Number of accumulated operations (ops) before applying them to the current snapshot and submitting the updated snapshot to the database. | 100 |

>type=note
> **Note on** **submitSnapshotBatchSize**:
> This parameter defines the frequency of snapshot updates. When the number of accumulated operations on the server reaches this value, these operations are applied to the current snapshot, generating and submitting an updated snapshot to the database which will overwrite the old snapshot.
> Operations themselves are stored independently, while the snapshot always maintains the latest version. This mechanism balances the frequency of snapshot updates with database write overhead.

### Example: Basic Configuration

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

// Configure DocumentServices
const docService = new DocumentServices({
    db: new MemoryDb(), // Use in-memory database
    maxSubmitRetries: 3, // Maximum 3 retries
    submitSnapshotBatchSize: 50 // Update snapshot after accumulating 50 operations
});
```

>type=note
> The default is to use MemoryDb, suitable for development and testing. For production environments, it is recommended to use a persistent adapter (e.g., Postgres Adapter)

## Server Operation (Op) Processing Flow

![construct_documentServices](https://cdn.mescius.io/document-site-files/images/7719ad0a-f083-46d7-aff6-f63e2e187c15/construct_documentServices.ab15fd.png?width=400&verticalAlign=middle)

## Methods

### use

Register middleware to add custom logic to the operation process.

```typescript
use<K extends keyof IDocMiddlewareContext<S, T>>(action: K, middleware: IMiddleware<IDocMiddlewareContext<S, T>[K]>)
```

**Parameters**

* `action`: Middleware action name (e.g., "submit", "receive")
* `middleware`: Middleware function. Its type is `IMiddleware`. It receives the context and controls the process.

**Example**

```typescript
docService.use('submit', async (context, next) => {
    console.log('submit op', context.request.op);
});
```

### on

Register a hook to listen for operation events.

```typescript
on<K extends keyof IDocHookContext>(hookName: K, hook: IHook<IDocHookContext[K]>)
```

**Parameters**

* `hookName`: Hook name (e.g., "submitRequestEnd")
* `hook`: Hook function, type `IHook`, which receives the context

**Example**

```typescript
docService.on('submitRequestEnd', (context) => {
    console.log('Submission completed:', context);
});
```

### fetch

Retrieve the latest snapshot of a specified document.

```typescript
fetch(id: string, context?: IContext): Promise<ISnapshot<S>>
```

**Parameters**

* `id`: Document ID (string)
* `context` (optional): Operation context

**Return**:
`Promise<ISnapshot<S>>` \- A Promise containing the latest snapshot\.
**Example**

```typescript
const snapshot = await docService.fetch('doc1');
console.log('Latest snapshot:', snapshot.data);
```

### getOps

Retrieve operations within a version range for a specified document (including `from`, excluding `to`).

```typescript
getOps(id: string, from: number, to?: number, context?: IContext): Promise<IOp<T>[]>
```

**Parameters**

* `id`: Document ID (string)
* `from`: Starting version number (inclusive)
* `to` (optional): Ending version number (exclusive)
* `context` (optional): Operation context

**Return**
`Promise<IOp<T>[]>` \- A Promise containing an array of operations\.
**Example**

```typescript
const ops = await docService.getOps('doc1', 0, 5);
console.log(ops);
```

### submit

Submit an operation to a specified document.

```typescript
submit(id: string, op: IOp<T>, context?: IContext): Promise<IOp<T>[]>
```

**Parameters**

* `id`: Document ID (string)
* `op`: Operation, type `IOp<T>`
* `context` (optional): Operation context

**Return**
`Promise<IOp<T>[]>` \- A promise resolving to the resulting operations\.
**Example**

```typescript
docService.submit('doc1', op);
```

### fetchHistorySnapshot

Retrieve a historical snapshot of a specified document.

```typescript
fetchHistorySnapshot(id: string, version?: number, context?: IContext): Promise<ISnapshot<S>>
```

**Parameters**

* `id`: Document ID (string)
* `version` (optional): Target version number; if omitted, returns the latest snapshot
* `context` (optional): Operation context

**Return**
`Promise<ISnapshot<S>>` \- A Promise containing the historical snapshot\.
**Example**

```typescript
const snapshot = await docService.fetchHistorySnapshot('doc1', 2);
console.log('Historical snapshot:', snapshot.data);
```