Skip to content

Ваш модуль в оболочке песочницы ​

Ваш модуль — это remote федерации. По-настоящему он работает только тогда, когда его загружает оболочка, и для вашего модуля это оболочка песочницы: тот же образ Building OS, развёрнутый отдельно и привязанный к вашей песочнице. В продуктивную оболочку ваш модуль не попадает никогда: код модуля выполняется с полным доверием той оболочки, которая его загрузила, поэтому стороннему коду выделяется собственная.

Начиная с 1.14.0

tv-sdk sandbox install и скрипты dev:remote / serve:remote появились в @tv/extension-sdk 1.14.0. Используйте 1.15.1 или новее: в более ранних версиях есть ошибки в командах с этой страницы, а модуль, созданный версией 1.14.0, не собирается. У модуля, созданного версией 1.13.0 или более ранней, этих скриптов нет — пересоздайте каркас или добавьте их вручную, как показано в шаге 1. Что не так в каждой старой версии: Известные проблемы по версиям SDK.

1. Отдавайте remote со своей машины ​

@originjs/vite-plugin-federation создаёт remoteEntry.js при сборке, а не в dev-сервере. Поэтому pnpm dev отдаёт приложение вообще без remote: на запрос /assets/remoteEntry.js dev-порт отвечает HTML-страницей приложения, и оболочка, нацеленная на него, показывает Module failed to load, а консоль браузера сообщает о скрипте-модуле с MIME-типом "text/html". Два терминала, две команды, запускайте в таком порядке:

bash
# терминал 1 — пересборка при каждом изменении
pnpm dev:remote     # vite build --watch

# терминал 2 — отдача собранного
pnpm serve:remote   # vite preview --port 6001 --strictPort

Пока первая сборка не закончилась, serve:remote останавливается с The directory "dist" does not exist. Did you build your project?; запустите его снова, когда dev:remote соберёт проект. После этого ваш remote будет здесь:

http://localhost:6001/assets/remoteEntry.js

Регистрируйте его с localhost, а не 127.0.0.1: в macOS сервер preview отвечает только на localhost.

6001 — закреплённый в каркасе порт preview (порт dev плюс 1000). strictPort задан намеренно: без него vite перескочит на следующий свободный порт и уведёт remote из-под записи реестра, которая на него ссылается.

Если в вашем каркасе нет dev:remote / serve:remote, их эквиваленты — vite build --watch и vite preview --port 6001 --strictPort плюс preview: { port: 6001, strictPort: true, cors: true } в vite.config.ts.

2. Установите модуль в свою песочницу ​

bash
npx @tv/extension-sdk sandbox install module-manifest.json \
  --sandbox=sbx_... \
  --remote-entry=http://localhost:6001/assets/remoteEntry.js

Два вызова к tv-api вашей собственной песочницы, по порядку:

  1. POST /api/v1/registry/modules/ingest с вашим манифестом и URL remote — это та запись реестра, из которой рисует оболочка.
  2. POST /api/v1/licenses на наполненное здание: оболочка рисует из состояния лицензий, поэтому зарегистрированный, но нелицензированный модуль просто отсутствует. Уже существующая лицензия отвечает 409, и команда считает это успехом — её безопасно запускать повторно.

--sandbox=<id> за один запрос находит URL API, токен, наполненное здание и console URL. Здесь нужен идентификатор песочницы вида sbx_…: его печатает sandbox create, а npx @tv/extension-sdk sandbox list показывает идентификаторы всех ваших песочниц. Это не slug из URL песочницы.

С --sandbox держите в TV_API_TOKEN ключ с портала (или полагайтесь на login) и не передавайте --token. Поиск песочницы идёт в сервис, который управляет песочницами, с этими учётными данными, а два вызова выше используют собственный токен песочницы из её записи. Не выполняйте в том же терминале строки export, которые печатает sandbox connect: тогда TV_API_URL отправит поиск в вашу песочницу, и она ответит 404.

Без --sandbox используется пара TV_API_URL / TV_API_TOKEN, которую печатает tv-sdk sandbox connect.

Обоим эндпоинтам нужны права администратора платформы — и внутри своей песочницы они у вас есть: tv-api песочницы принимает собственный токен как администратора этого одного API и этой одной базы, и ничего больше (tv-platform#795). Поэтому 401 или 403 от этой команды означают неверные учётные данные: проверьте их по таблице Если что-то не так. SDK 1.15.0 и более ранние печатают после любого из них старое пояснение (This is expected today: … ask for the module to be registered for you), написанное до этого изменения; не обращайте на него внимания.

Смена адреса, с которого вы отдаёте remote, — это повторный запуск команды, а не пересборка оболочки.

3. Откройте ​

<хост вашей песочницы>/sandbox/<slug вашего модуля>

Хост песочницы — это consoleUrl в записи песочницы (тот же хост, что и apiUrl: оболочка отдаётся на /, API остаётся на /api и /socket.io, поэтому UI и бэкенд у них общий origin). consoleUrl равен null, если для вашей песочницы оболочка не развёрнута.

Оболочка песочницы монтирует один общий маршрут /sandbox/:slug, который ведут поля remoteEntryUrl, federationName и exposeName из вашей записи реестра; маршруты /<slug> продуктивной оболочки тут ни при чём.

4. Войдите ​

Оболочка песочницы аутентифицируется в реалме Keycloak sandboxes. Самостоятельной регистрации там нет. Войти можно двумя способами.

Приглашённые разработчики. Учётную запись в этом реалме создаёт для вас команда Tango Vision, проставляя в клейм tenant_id значение organizationId вашей песочницы. Пришлите slug песочницы (поддомен из её apiUrl) контакту, указанному в приветственном сообщении, на почту или в Telegram; адрес developers@tango.vision доходит до тех же людей. Отвечаем в тот же рабочий день по московскому времени. Учётная запись создаётся с временным паролем, и при первом входе вас попросят задать собственный.

Забыли пароль от песочницы? На странице входа в песочницу нет ссылки для сброса. Напишите своему контакту — мы зададим новый временный пароль.

Сотрудники Tango Vision. Сотрудники входят под корпоративной учётной записью кнопкой Tango Vision staff на странице входа. Это работает только для участника группы /sandbox-developers, чью учётную запись в песочнице оператор связал с его корпоративной учётной записью. Автоматически ничего не создаётся и не связывается, а собственного пароля у такой учётной записи нет.

Чего ожидать, а чего нет ​

  • Chrome или Firefox, не Safari. Safari блокирует загрузку скрипта с http://localhost на страницу с публичного HTTPS-origin. Chrome при первом запуске может спросить разрешение на доступ к локальной сети — разрешите.
  • Берите токен через getAccessToken() или authorizationHeader() из @tv/extension-sdk/context, а не из localStorage['access_token']. В оболочке песочницы мост к старому ключу выключен: оболочка, зеркалящая живой access-токен в ключ, читаемый любым скриптом, отдавала бы его чужому JavaScript. Модули, читающие этот ключ напрямую, в оболочке песочницы не аутентифицируются; модули, использующие функции токена из SDK, работают как обычно. См. Вызов API из модуля.
  • Remote загрузится, только если его пропустят два независимых барьера — CSP браузера и собственный список разрешённых origin у оболочки. В оболочке песочницы оба настроены пропускать localhost. Remote с другого адреса требует изменения обоих, и это запрос к нам, а не настройка на вашей стороне.
  • Лицензионной проверки на этом маршруте нет, но вход всё равно нужен: маршрут находится внутри защищённой области оболочки.
  • Бэкенд вашего модуля всё это не разворачивает. install регистрирует и лицензирует фронтенд-remote. Бэкенд работает там, где вы его запустили, и обращается к tv-api песочницы по сети, как любой другой клиент.

Правила загрузки модуля с localhost ​

Всё сказанное выше в виде списка. Если страница пустая, одно из этих условий не выполнено.

  1. С localhost загружает только оболочка песочницы. Content-Security-Policy продуктивной оболочки не допускает http://localhost, а универсальный маршрут модулей в ней выключен. Оболочка песочницы допускает loopback-адреса и открывает любой модуль из реестра вашей песочницы по адресу /sandbox/<slug>.
  2. Только loopback. Допускаются http://localhost:<порт> и http://127.0.0.1:<порт>. Адрес в локальной сети, туннель или любой другой хост не допускаются. Регистрируйте localhost: в macOS serve:remote не отвечает на 127.0.0.1.
  3. Отдавайте сборку, а не dev-сервер. vite dev не создаёт assets/remoteEntry.js: federation-remote существует только в сборке. Запустите pnpm dev:remote и pnpm serve:remote одновременно.
  4. Адрес фиксирован: http://localhost:6001/assets/remoteEntry.js. Preview работает со strictPort, поэтому занятый порт даёт ошибку, а не тихий переход на другой, и с включённым CORS.
  5. Запись в реестре должна указывать на него. tv-sdk sandbox install с параметром --remote-entry=http://localhost:6001/assets/remoteEntry.js регистрирует манифест в вашей песочнице и выдаёт лицензию на созданное здание. Slug в нижнем регистре через дефис, не длиннее 64 символов; remote экспортирует ./Shell.
  6. Chrome или Firefox, не Safari. Оболочка открыта по HTTPS и загружает скрипт с HTTP loopback; Safari это блокирует. Chrome может один раз запросить доступ к устройствам в локальной сети: разрешите.
  7. Модуль загружается только в вашем браузере. localhost это ваш компьютер. Коллега, открыв тот же адрес, получит ошибку загрузки. Коллега со своей учётной записью в вашей песочнице может вместо этого отдавать модуль со своей машины (см. Два разработчика, одна песочница). Чтобы показать модуль кому-то ещё, разместите собранный бандл на хосте, который допускает оболочка песочницы, и попросите нас разрешить этот хост.
  8. Авторизация только через SDK, не через localStorage['access_token']. Оболочка песочницы не записывает туда токен, а PlatformContext.api недоступен, потому что React-контекст не пересекает границу federation. На каждый запрос к относительному пути /api/… вызывайте authorizationHeader() из @tv/extension-sdk/context.
  9. Ваш бэкенд работает на вашем компьютере. Политика оболочки позволяет фронтенду обращаться к http://localhost:<порт>, поэтому локальный бэкенд доступен из браузера. Платформа до него не дотянется: у песочницы нет исходящего доступа в интернет и маршрута к вашему компьютеру, поэтому Copilot не сможет вызвать MCP-эндпоинт на localhost. Про проверку вызывающего и настройку CORS для этого origin — см. Добавьте бэкенд.
  10. i18next и react-i18next в shared либо оба, либо ни одного, и сохраняйте alias use-sync-external-store/shim из шаблона. Нарушение проявляется только внутри оболочки, где ваш CI его не видит.

Если страница пустая ​

Что вы видитеОбычная причина
Module failed to load, а в консоли видно, что запрос за remoteEntry.js не прошёлНе запущен pnpm serve:remote, либо запись реестра указывает на 127.0.0.1 (в macOS сервер отвечает только на localhost)
Module failed to load, а консоль сообщает о скрипте-модуле с MIME-типом "text/html"Запись реестра указывает на порт pnpm dev, а dev-сервер remote не создаёт. Переустановите модуль с --remote-entry=http://localhost:6001/assets/remoteEntry.js
Remote грузится с другого портаНет strictPort: vite сменил порт, а запись реестра по-прежнему указывает на 6001
Module not in the registryМодуль не установлен, slug в URL не совпадает с частью id манифеста после module-, либо у вашей учётной записи в песочнице ещё не задан tenant_id (тогда в боковом меню ещё и «Реестр модулей недоступен — показан кэшированный список.»). Запустите sandbox install заново и перезагрузите страницу; если надпись в меню не пропала, напишите своему контакту
Вход выполнен, но все вызовы API дают 401Модуль читает localStorage['access_token']; вместо этого передавайте authorizationHeader() из @tv/extension-sdk/context в каждом запросе
Падение из-за второй копии React при монтированииНет алиаса use-sync-external-store/shim; см. Федерация и оболочка

Создано на платформе Tango Vision. Вопросы? developers@tango.vision