# Лицензия

> Collaboration SDK по лицензии определяет подключения совместного редактирования, разрешённые домены, узлы совместного редактирования и типы документов.

- Human documentation: [https://docs.univer.ai/ru-RU/server/collaboration/license](https://docs.univer.ai/ru-RU/server/collaboration/license)

- Agent Markdown: [https://docs.univer.ai/ru-RU/server/collaboration/license.md](https://docs.univer.ai/ru-RU/server/collaboration/license.md)

- Requested language: `ru-RU`

- Content language: `ru-RU`

- Documentation version: `1.4.0`

- Source: [collaboration/license.ru-RU.mdx](https://github.com/dream-num/documentation/blob/dev/content/server/collaboration/license.ru-RU.mdx)

---

`UniverCollabService` загружает лицензию при создании, и Endpoint и Worktree используют её совместно. Настройка описана в разделе [Лицензия](https://docs.univer.ai/ru-RU/server/license.md#collaboration-sdk); без лицензии работает бесплатная версия. Если лицензия не проходит проверку, конструктор выбрасывает `CollabError` (`LICENSE_INVALID` или `LICENSE_POLICY_INVALID`), и сервис останавливается при запуске.

## Что определяет лицензия

| Параметр | Где проверяется | При превышении |
| --- | --- | --- |
| Подключения совместного редактирования | Endpoint, при получении отправок | Изменения новых подключений остаются в браузере и отправляются повторно |
| Разрешённые домены | Endpoint, при подключении и получении отправок | Сеанс совместного редактирования в браузере переходит в офлайн |
| Узлы совместного редактирования | Endpoint | Узлы сверх лимита после льготного периода отключаются |
| Типы документов | Service, при создании Unit и получении изменений | Создание и отправки отклоняются; существующие документы остаются доступны для просмотра |

### Подключения совместного редактирования

Лимит считает редактирующие подключения: подключение совместного редактирования занимает место при первой успешной отправке и освобождает его при закрытии или через 120 секунд после последней успешной отправки. Подключения, открывающие документ для просмотра, могут присоединиться в любой момент. Правки внутри Worktree используют те же места, что и основная ветка.

Когда все места заняты, изменения нового подключения остаются в браузере, и Web SDK отправляет их повторно с нарастающей задержкой, пока не освободится место; подключения, у которых уже есть место, продолжают редактировать. В браузере `CollaborationChangesetResend` сообщает о таких повторах с `reason: 'license_editing_connections_exceeded'`.

### Разрешённые домены

Когда Web SDK открывает подключение совместного редактирования или отправляет изменения, Endpoint сверяет домен страницы с разрешёнными доменами лицензии. Домен вне списка получает `403`; сеанс совместного редактирования в браузере переходит в офлайн и показывает причину, а повторная попытка выполняется, когда пользователь переподключается или открывает другой документ.

### Узлы совместного редактирования

**Лицензия на один узел** (включая бесплатную версию): работает один узел совместного редактирования. Если передать `pubSub` в Endpoint, конструктор выбросит `LICENSE_POLICY_INVALID`.

**Лицензия на несколько узлов**: задаёт лимит узлов. Если узлов запущено больше лимита, самые новые входят в льготный период с нарастающими предупреждениями, а затем отключаются: новые подключения получают `503`, существующие закрываются. Узлы в пределах лимита продолжают работать. Если за льготный период число узлов вернётся в пределы лимита, лишние узлы вернутся в нормальное состояние; уже отключённый узел после перезапуска процесса учитывается заново как новый узел. Настройка нескольких узлов описана в разделе [Развёртывание](https://docs.univer.ai/ru-RU/server/deployment.md#несколько-узлов-совместного-редактирования).

### Типы документов

В лицензии перечислены типы документов, доступные для совместного редактирования. Создание Unit другого типа выбрасывает `LICENSE_UNIT_TYPE_REJECTED`, а отправленные изменения отклоняются; в браузере `CollaborationConflict` сообщает `reason` `license_unit_type_rejected`. Существующие документы по-прежнему можно открывать и просматривать.

## Наблюдение за состоянием

```ts
// Service
collabService.license.status // состояние лицензии: 'not_configured' | 'expired' | 'valid'
collabService.license.editingConnectionsLimit // лимит подключений редактирования: number | null; null — без ограничений
collabService.license.nodesLimit // лимит узлов: number | null; null — без ограничений
collabService.license.domains // разрешённые домены: string[]
collabService.license.expiresAt // срок действия: строка ISO | null; null, если лицензия не настроена
collabService.license.update({ license, licenseKey }) // заменяет лицензию; при неудачной проверке выбрасывает ошибку и сохраняет текущую

// Endpoint
endpoint.license.editingConnections.limit // лимит мест: number | null; null — без ограничений
endpoint.license.editingConnections.used // занятые места: number | null; null, если limit без ограничений
endpoint.license.editingConnections.remaining // свободные места: number | null; null — без ограничений
endpoint.license.editingConnections.has(memberID) // занимает ли участник место: boolean; false, если limit без ограничений
endpoint.license.nodes.limit // лимит узлов: number | null; null — без ограничений
endpoint.license.nodes.status // состояние этого узла: 'normal' | 'exceeded' | 'exceeded-warning' | 'exceeded-offlineSoon' | 'exceeded-offline'

// События
endpoint.license.on('editingConnectionsChanged', ({ change, memberIDs, used, limit }) => {}) // места заняты или освобождены: change — 'acquired' | 'released', used — значение после изменения; не вызывается, если limit без ограничений
endpoint.license.on('editingConnectionsExceeded', ({ memberID, userID, unitID, used, limit }) => {}) // все места заняты, отправка нового подключения не сохранена
endpoint.license.on('nodesStatusChanged', ({ status, previousStatus, limit, reason }) => {}) // изменилось состояние этого узла; reason заполняется только при отключении
```

`nodesStatusChanged` вызывается один раз при каждом изменении состояния этого узла. Когда `status` равен `exceeded-offline`, узел перестал принимать подключения; выведите его из балансировщика нагрузки или отправьте оповещение.
