Начало работы
Это руководство проведёт вас от нуля до зарегистрированного модуля Tango Vision.
Что вам понадобится
- Учётная запись разработчика — зарегистрируйтесь здесь (самостоятельно)
- Node 22+ и pnpm 10 — pnpm является стандартом платформы; все шаблоны и генераторы рассчитаны на него
- Доступ к приватному реестру
https://npm.k8s.tangovision.dev/ - API-ключ песочницы — см. Учётная запись → Получить API-ключ песочницы
Установка SDK
Пакеты области @tv/* живут в приватном реестре, который не отдаёт анонимные загрузки — запрос без токена возвращает 401. Укажите в .npmrc и реестр, и токен:
# .npmrc
@tv:registry=https://npm.k8s.tangovision.dev/
//npm.k8s.tangovision.dev/:_authToken=${TV_NPM_TOKEN}Экспортируйте токен из письма о регистрации и установите пакет:
export TV_NPM_TOKEN=... # храните в профиле оболочки или менеджере секретов
pnpm add @tv/extension-sdkСборка в Docker
.npmrc с адресом реестра, но без токена — самая частая причина падения CI: реестр отвечает 401 на любой запрос без токена, включая метаданные. В Dockerfile монтируйте токен как build-секрет, а не «запекайте» его в слой:
RUN --mount=type=secret,id=npm_token \
echo "@tv:registry=https://npm.k8s.tangovision.dev/" > .npmrc && \
if [ -f /run/secrets/npm_token ]; then \
echo "//npm.k8s.tangovision.dev/:_authToken=$(cat /run/secrets/npm_token)" >> .npmrc; \
fi && \
pnpm install --frozen-lockfileЧто внутри пакета
SDK поставляет всё одним пакетом, доступным через подпути:
| Подпуть | Что он даёт | Уровень |
|---|---|---|
@tv/extension-sdk | Типы ModuleManifest + Zod-валидатор + типы PlatformContext | @stable |
@tv/extension-sdk/manifest | Схема манифеста, валидатор, генераторы, checkExposes | @stable |
@tv/extension-sdk/context | Типы PlatformContext времени выполнения | @stable |
@tv/extension-sdk/events | Каталог событий, конверт, субъекты | @stable |
@tv/extension-sdk/api | Типы PlatformApiClient | @stable |
@tv/extension-sdk/react | <PlatformProvider>, usePlatformContext(), useBuilding(), useOptionalBuilding(), useCurrentUser() | @stable |
@tv/extension-sdk/nestjs | Декораторы @ModuleCapability(), @RequiresLicense() | @stable |
@tv/extension-sdk/testing | createMockPlatformContext() | @stable |
@tv/extension-sdk/permissions | extractCatalog(), PermissionCatalog, SubjectEntry | @stable |
@tv/extension-sdk/heartbeat | Отчёт о живости в оболочку | @experimental |
@tv/extension-sdk/version-check | useVersionCheck(), <UpdatePrompt> — предложение обновиться развёрнутым клиентам | @experimental |
tv-sdk (bin) | CLI — см. ниже | смешанный |
Также публикуются готовые JSON-артефакты: manifest.schema.json, permissions.snapshot.json, tv-events.snapshot.json, openapi.snapshot.json.
Уровень символа определяет, может ли он измениться под вами — см. Уровни стабильности.
CLI
npx @tv/extension-sdk --helpВызывайте CLI по полному имени пакета
Бинарь CLI называется tv-sdk, и внутри проекта с установленным SDK npx tv-sdk тоже сработает. Не привыкайте к этой форме: пакета tv-sdk в публичном npm-реестре не существует, поэтому вне такого проекта npx tv-sdk запросит у публичного npm незанятое имя — и любой, кто опубликует пакет tv-sdk, получит выполнение своего кода на вашей машине. Всегда пишите npx @tv/extension-sdk <команда>: эта форма резолвится через аутентифицированный @tv:registry, настроенный выше, где бы вы её ни запускали.
| Команда | Что делает |
|---|---|
init-module <slug> --category=<c> | Генерирует модуль целиком: манифест, vite.config.ts, src/Shell.tsx, package.json |
init-manifest <slug> --category=<c> | Генерирует только module-manifest.json |
validate <manifest> | Проверяет манифест по схеме |
check-exposes <manifest> | Проверяет канонический экспорт ./Shell в vite.config.ts |
check-pact <manifest> | Проверяет, что контракты events.subscribes совместимы со схемами издателей |
check-events <snapshot.json> | Падает на ломающих изменениях относительно зафиксированного снимка схем событий |
check-api <snapshot.json> | Падает на ломающих изменениях относительно снимка OpenAPI |
write-version | Пишет version.json (версия + коммит + время сборки) как postbuild-шаг |
ingest <manifest> | Загружает манифест в реестр платформы |
sandbox <subcommand> | Управление песочницами — create, list, connect, extend, reset, delete |
copilot | Интерактивный ИИ-помощник, который создаёт и подключает модуль за вас |
init-module, init-manifest, validate, check-exposes, write-version имеют уровень @stable. Остальные — @experimental: полезны, но набор флагов может измениться.
Анатомия модуля
my-module/
├── module-manifest.json ← контракт
├── frontend/ ← React, экспортирует федеративный "Shell"
│ └── src/Shell.tsx
└── backend/ ← опциональный сервис NestJS
└── src/Манифест — это сердце модуля. Он объявляет идентификатор модуля, нужные ему разрешения, события, на которых он «говорит», инструменты Copilot и место монтирования его UI. Платформа читает его три раза:
- В вашем CI —
npx @tv/extension-sdk validate module-manifest.json - При публикации — реестр отклоняет недопустимый манифест
- Во время выполнения — оболочка Building OS собирает ваш модуль на его основе
Золотое правило
Ваш модуль общается с платформой только через
PlatformContext.
Никакого localStorage. Никаких ручных токенов. Никаких собранных вручную URL API. Контекст даёт вам предварительно аутентифицированный HTTP-клиент, ограниченный областью арендатора. Именно это позволяет одному и тому же коду без изменений работать и в вашей песочнице, и в продакшен-арендаторе клиента.
import { usePlatformContext, useBuilding } from '@tv/extension-sdk/react';
import { useQuery } from '@tanstack/react-query';
export function WorkOrderList() {
const { api } = usePlatformContext(); // уже аутентифицирован + ограничен областью
const building = useBuilding(); // активное здание
return useQuery({
queryKey: ['work-orders', building.id],
queryFn: () => api.get(`/api/v1/buildings/${building.id}/work-orders`),
});
}Далее
→ Ваш первый модуль собирает рабочий hello-world от начала до конца.