Cluster · разработчикам

SDK в своём проекте

Установка · Первый модуль · Справочник методов

Устанавливаемый пакет cluster-sdk содержит публичные классы и конструкторы, объявления типов и команды работы с проектом. Ядро, серверный транспорт и служебные данные в пакет не входят. Рабочие app и loader передаёт Cluster при запуске модуля.

Подготовка проекта

python -m cluster_sdk init ./my-module --name "My module"

Можно вызвать установленную команду cluster-sdk с теми же аргументами. Далее используется форма python -m cluster_sdk, чтобы команда точно выполнялась в выбранном окружении.

init создаёт main.py и manifest.json, только если обоих файлов ещё нет. Если один из них уже существует, шаблон не добавляется. Исходники пользователя и существующее описание версии не заменяются. Для готового проекта или папки с несколькими модулями используй python -m cluster_sdk init . --existing: шаблон не создаётся даже в пустой папке.

Команда создаёт или дополняет pyrightconfig.json и .vscode/settings.json. Сохраняются пользовательские параметры проверки и редактора; путь интерпретатора обновляется на Python, из которого вызвана команда. Для виртуального окружения также обновляются venvPath и venv. Перед изменением существующего JSON сохраняется файл *.before-cluster-sdk.json. Файл с комментариями или некорректным JSON не перезаписывается; команда сообщает, что его нужно проверить вручную.

В requirements-dev.txt сохраняется ссылка на установленную версию SDK с инструментом проверки типов. Существующий файл не заменяется. Это зависимости разработки, не requirements серверного модуля.

Если в stubPath лежат неизменённые объявления прежнего пакета cluster-sdk-types, команда переносит их в скрытую резервную папку. Редактор после этого использует объявления установленного SDK. Собственные или изменённые объявления сохраняются; команда сообщает о возможном перекрытии типов.

Проверка проекта

python -m cluster_sdk check ./my-module --types

Проверяются синтаксис включаемых в пакет Python-файлов, импорт main.py, наличие Module, описание команд и остальных обработчиков, поля настроек, страницы, повторы алиасов. Перед сравнением учитываются значения по умолчанию полей и обработчиков, которые дописывает сервер. Отсутствующий required и required: false не считаются разными настройками. В отчёте есть state, число Python-файлов и признак проверки типов.

Для проверки импорта передаются локальные app и loader. Создаётся экземпляр Module; методы init и обработчики не вызываются. Сетевые службы такого app не подключены к ядру. Попытка обратиться к ним завершается InvalidState, а не подставным успешным результатом.

Если Pyright установлен, команда также запускает его в окружении проекта. Аргумент --types требует его наличия; без этого аргумента отсутствие Pyright отмечается как types=false, а не как успешная проверка типов. При ошибке команда завершается с ненулевым кодом и выводит причину.

Проверка импорта выполняет обычный Python-код на компьютере разработчика. Она не является изолированной средой. Результат не заменяет серверную проверку прав, зависимостей, сборки, лимитов и поведения модуля в Cluster.

Сборка архива

python -m cluster_sdk pack ./my-module

Команда сначала выполняет проверку, затем создаёт dist/my-module-1.0.0.zip. Имя берётся из каталога проекта, версия из manifest.json. main.py и manifest.json находятся в корне архива. Дополнительные Python-файлы и обычные файлы данных сохраняют относительные пути.

Исключаются виртуальные окружения .venv и venv, Git, скрытые файлы, кеши Python и анализаторов, настройки редакторов, node_modules, dist, tests, pyproject.toml, pyrightconfig.json и requirements-dev.txt. Символические ссылки не упаковываются: команда возвращает ошибку с их именем.

Для другого пути используй --output ./module.zip. Выходной файл должен иметь расширение .zip. Готовый архив загружается через форму публикации; перед выпуском его можно проверить на сайте.

Публичные конструкторы

Конструкторы работают после обычного импорта установленного SDK:

from cluster_sdk import Canvas, Document, Field, Fields, Pages, Text

text = Text().bold("Cluster").line("Hello.")
value = Document({"count": 0}).increment("count")
fields = Fields().add("title", Field("string").default("Hello"))
pages = Pages[int]([101, 102, 103], size=2)

scene = Canvas(800, 400)
scene.rect("background", 0, 0, 800, 400, fill="#18151f")
scene.text("title", "Cluster", 24, 24, 600, 80)

В примере создаются текст, документ, поля, страницы и описание картинки. Отправка сообщения или отрисовка картинки через Image Generator по-прежнему выполняется в Cluster через выданные модулю права.

Свой транспорт

Обычному модулю транспорт настраивать не нужно. Для собственной клиентской привязки или теста отдельного обращения есть Client:

from __future__ import annotations

from cluster_sdk import Client, JSON


async def request(path: str, data: dict[str, JSON]) -> JSON:
    if path == "db/get" and data["key"] == "count": return 3
    raise RuntimeError("No response is configured for " + path)


async def read() -> JSON:
    client = Client(request)
    return await client.db.get("count")

Client(transport) принимает объект с асинхронным методом request(path: str, data: dict[str, JSON]) -> JSON либо асинхронную функцию с такой сигнатурой. Все привычные службы доступны через этот клиент. Client.request(path, **data) проверяет JSON-совместимость переданных данных и копирует результат транспорта. Ошибки транспорта передаются вызывающему коду. Некорректный транспорт вызывает TypeError, неподходящее JSON-значение вызывает TypeError или ValueError.

Transport является протоколом такого объекта. FunctionTransport(request) оборачивает асинхронную функцию и предоставляет метод request. Функция возвращает результат операции; специфические ответы службы, например telegram/request, сохраняют свою структуру ok/result/error.

Это интерфейс клиентской привязки, а не готовое подключение к произвольному юзерботу. Серверные проверки доступа остаются в Cluster; установкой SDK их обойти нельзя.