@retailcrm/embed-ui 0.9.23-alpha.3 → 0.9.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Changelog
2
2
 
3
3
 
4
+ ## [0.9.24](https://github.com/retailcrm/embed-ui/compare/v0.9.23...v0.9.24) (2026-05-26)
5
+
6
+ ### Bug Fixes
7
+
8
+ * Page manifest descriptors generated for publish ([6c6685e](https://github.com/retailcrm/embed-ui/commit/6c6685e9c52a3437febddf4fdd32b13cb01de5af))
9
+ ## [0.9.23](https://github.com/retailcrm/embed-ui/compare/v0.9.23-alpha.3...v0.9.23) (2026-05-23)
4
10
  ## [0.9.23-alpha.3](https://github.com/retailcrm/embed-ui/compare/v0.9.23-alpha.2...v0.9.23-alpha.3) (2026-05-23)
5
11
 
6
12
  ### Features
package/bin/embed-ui.mjs CHANGED
@@ -1696,6 +1696,86 @@ const assertStringArray = (value, field) => {
1696
1696
  return value
1697
1697
  }
1698
1698
 
1699
+ const assertOptionalNonEmptyString = (value, field) => {
1700
+ if (value === undefined || value === null) {
1701
+ return null
1702
+ }
1703
+
1704
+ return assertNonEmptyString(value, field)
1705
+ }
1706
+
1707
+ const assertOptionalNumber = (value, field) => {
1708
+ if (value === undefined || value === null) {
1709
+ return null
1710
+ }
1711
+
1712
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
1713
+ throw new Error('Field "' + field + '" must be a finite number')
1714
+ }
1715
+
1716
+ return value
1717
+ }
1718
+
1719
+ const assertOptionalBoolean = (value, field) => {
1720
+ if (value === undefined || value === null) {
1721
+ return false
1722
+ }
1723
+
1724
+ if (typeof value !== 'boolean') {
1725
+ throw new Error('Field "' + field + '" must be a boolean')
1726
+ }
1727
+
1728
+ return value
1729
+ }
1730
+
1731
+ const assertTranslation = (value, field, { nullable = false } = {}) => {
1732
+ if (value === undefined || value === null) {
1733
+ return nullable ? null : undefined
1734
+ }
1735
+
1736
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1737
+ throw new Error('Field "' + field + '" must be an object with ru, en and es strings')
1738
+ }
1739
+
1740
+ return {
1741
+ ru: assertNonEmptyString(value.ru, field + '.ru'),
1742
+ en: assertNonEmptyString(value.en, field + '.en'),
1743
+ es: assertNonEmptyString(value.es, field + '.es'),
1744
+ }
1745
+ }
1746
+
1747
+ const normalizePages = (value) => {
1748
+ if (value === undefined) {
1749
+ return []
1750
+ }
1751
+
1752
+ if (!Array.isArray(value)) {
1753
+ throw new Error('Field "pages" must be an array of page descriptor objects')
1754
+ }
1755
+
1756
+ return value.map((page, index) => {
1757
+ const field = 'pages[' + index + ']'
1758
+
1759
+ if (typeof page === 'string') {
1760
+ throw new Error('Field "' + field + '" uses deprecated string page form. Use { "code": "' + page + '", "menu": "...", "menuItemTitle": { "ru": "...", "en": "...", "es": "..." } }')
1761
+ }
1762
+
1763
+ if (!page || typeof page !== 'object' || Array.isArray(page)) {
1764
+ throw new Error('Field "' + field + '" must be a page descriptor object')
1765
+ }
1766
+
1767
+ return {
1768
+ code: assertNonEmptyString(page.code, field + '.code'),
1769
+ menu: assertNonEmptyString(page.menu, field + '.menu'),
1770
+ parentMenuItemCode: assertOptionalNonEmptyString(page.parentMenuItemCode, field + '.parentMenuItemCode'),
1771
+ menuItemOrdering: assertOptionalNumber(page.menuItemOrdering, field + '.menuItemOrdering'),
1772
+ menuItemTitle: assertTranslation(page.menuItemTitle, field + '.menuItemTitle', { nullable: true }) ?? null,
1773
+ pageHelpLink: assertTranslation(page.pageHelpLink, field + '.pageHelpLink', { nullable: true }),
1774
+ isSettingsMainPage: assertOptionalBoolean(page.isSettingsMainPage, field + '.isSettingsMainPage'),
1775
+ }
1776
+ })
1777
+ }
1778
+
1699
1779
  const listFiles = (directoryPath, basePath = directoryPath) => {
1700
1780
  const result = []
1701
1781
 
@@ -1803,7 +1883,7 @@ try {
1803
1883
  const uuid = assertNonEmptyString(config.uuid, 'uuid')
1804
1884
  const version = assertNonEmptyString(config.version, 'version')
1805
1885
  const targets = assertStringArray(config.targets, 'targets')
1806
- const pages = assertStringArray(config.pages, 'pages')
1886
+ const pages = normalizePages(config.pages)
1807
1887
  const runner = config.runner ?? 'worker'
1808
1888
 
1809
1889
  if (targets.length === 0 && pages.length === 0) {
@@ -1918,9 +1998,9 @@ try {
1918
1998
  process.exit(1)
1919
1999
  }
1920
2000
  `;
1921
- const readmeEnGBTemplate = "# RetailCRM extension frontend\n\nThis project was generated by `embed-ui init`.\n\n## What Was Added\n\n- `package.json` with scripts for Vite build, ESLint, and extension publishing.\n- `extensionrc.json` with the generated extension manifest source.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` with `defineRunner`, one page runner, and one widget runner.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` as a starter settings page.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` as a starter order widget.\n- `__SOURCE_ROOT__/i18n/` with shared JSON message files.\n- `scripts/publish-extension.mjs` for creating `dist/extension.zip` and publishing the integration module through RetailCRM API.\n- `AGENTS.md` when agent instructions were enabled during init.\n\n## Replace Generic Values\n\nReview these generated placeholders before using the project in a real integration:\n\n- Extension code in `extensionrc.json`: `retailcrm-extension-frontend`.\n- Extension name in `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Page code: `__PAGE_CODE__`.\n- Widget target: `__WIDGET_TARGET__`.\n- Sample controls and fake data in `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Sample toolbar actions and fake order data in `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Shared messages in `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nThe generated page and widget are intentionally generic. Keep the structure you need, but replace the sample labels, fields, and fake data with real product behavior.\n\n## Vue File Names\n\n`SettingsPage.vue` and `OrderCommonAfterWidget.vue` are generic starter names. In product code, rename Vue files after the role they play in the extension, and update imports in `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nExamples from RetailCRM extension examples:\n\n- `ReturnsPage.vue` is a full returns-management page.\n- `TasksPage.vue` is a task list/workspace page.\n- `SummaryPage.vue` is a summary dashboard page.\n- `RecordToCalendlyWidget.vue` is a focused widget for one scenario.\n\nUse the same idea for your code: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue`, or another name that describes the real scenario.\n\n## Commands\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Publishing\n\nCreate `.env` in the project root when you want `publish-extension` to update RetailCRM:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nRun `__PACKAGE_MANAGER_RUN__ build` before publishing. The archive-only mode creates `dist/extension.zip` without sending API requests.\n";
1922
- const readmeEsESTemplate = "# Frontend de extension RetailCRM\n\nEste proyecto fue generado por `embed-ui init`.\n\n## Que Se Agrego\n\n- `package.json` con scripts para Vite build, ESLint y publicacion de la extension.\n- `extensionrc.json` con la fuente del manifiesto de la extension.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` con `defineRunner`, un runner de pagina y un runner de widget.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` como pagina inicial de configuracion.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` como widget inicial del pedido.\n- `__SOURCE_ROOT__/i18n/` con archivos JSON de mensajes compartidos.\n- `scripts/publish-extension.mjs` para crear `dist/extension.zip` y publicar el modulo de integracion por RetailCRM API.\n- `AGENTS.md` si las instrucciones para agentes estaban activadas durante init.\n\n## Sustituya Los Valores Genericos\n\nRevise estos valores generados antes de usar el proyecto en una integracion real:\n\n- Codigo de extension en `extensionrc.json`: `retailcrm-extension-frontend`.\n- Nombre de extension en `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Codigo de pagina: `__PAGE_CODE__`.\n- Target del widget: `__WIDGET_TARGET__`.\n- Controles de ejemplo y datos ficticios en `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Acciones toolbar de ejemplo y datos ficticios del pedido en `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Mensajes compartidos en `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nLa pagina y el widget generados son intencionalmente genericos. Mantenga la estructura que necesite, pero sustituya etiquetas, campos y datos ficticios por comportamiento real del producto.\n\n## Nombres De Archivos Vue\n\n`SettingsPage.vue` y `OrderCommonAfterWidget.vue` son nombres iniciales genericos. En codigo de producto, renombre los archivos Vue segun la funcion que cumplen en la extension y actualice los imports en `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nEjemplos del repositorio de extensiones RetailCRM:\n\n- `ReturnsPage.vue` es una pagina completa de gestion de devoluciones.\n- `TasksPage.vue` es una pagina de lista o espacio de trabajo de tareas.\n- `SummaryPage.vue` es una pagina de resumen o dashboard.\n- `RecordToCalendlyWidget.vue` es un widget enfocado en un escenario.\n\nUse la misma idea para su codigo: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue` u otro nombre que describa el escenario real.\n\n## Comandos\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Publicacion\n\nCree `.env` en la raiz del proyecto cuando quiera que `publish-extension` actualice RetailCRM:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nEjecute `__PACKAGE_MANAGER_RUN__ build` antes de publicar. El modo archive-only crea `dist/extension.zip` sin enviar peticiones API.\n";
1923
- const readmeRuRUTemplate = "# Фронтенд расширения RetailCRM\n\nПроект создан командой `embed-ui init`.\n\n## Что Добавлено\n\n- `package.json` со скриптами для сборки Vite, ESLint и публикации расширения.\n- `extensionrc.json` с исходным описанием манифеста расширения.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` с `defineRunner`, одним runner страницы и одним runner виджета.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` как стартовая страница настроек.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` как стартовый виджет заказа.\n- `__SOURCE_ROOT__/i18n/` с общими JSON-файлами переводов.\n- `scripts/publish-extension.mjs` для создания `dist/extension.zip` и публикации интеграционного модуля через RetailCRM API.\n- `AGENTS.md`, если при инициализации были включены инструкции для агентов.\n\n## Замените Generic Значения\n\nПеред использованием проекта в реальной интеграции проверьте сгенерированные общие значения:\n\n- Код расширения в `extensionrc.json`: `retailcrm-extension-frontend`.\n- Название расширения в `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Код страницы: `__PAGE_CODE__`.\n- Цель виджета: `__WIDGET_TARGET__`.\n- Демонстрационные контролы и ненастоящие данные в `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Демонстрационные toolbar-действия и ненастоящие данные заказа в `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Общие сообщения в `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nСгенерированные страница и виджет намеренно сделаны универсальными. Оставьте нужную структуру, но замените примерные подписи, поля и ненастоящие данные на реальное поведение продукта.\n\n## Имена Vue-Файлов\n\n`SettingsPage.vue` и `OrderCommonAfterWidget.vue` — универсальные стартовые имена. В продуктовом коде переименуйте Vue-файлы по роли, которую они выполняют в расширении, и обновите импорты в `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nПримеры из репозитория расширений RetailCRM:\n\n- `ReturnsPage.vue` — полноценная страница управления возвратами.\n- `TasksPage.vue` — страница списка задач или рабочей области задач.\n- `SummaryPage.vue` — страница сводки или дашборда.\n- `RecordToCalendlyWidget.vue` — сфокусированный виджет под один сценарий.\n\nИспользуйте тот же принцип: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue` или другое имя, которое описывает реальный сценарий.\n\n## Команды\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Публикация\n\nСоздайте `.env` в корне проекта, когда потребуется обновлять RetailCRM через `publish-extension`:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nПеред публикацией выполните `__PACKAGE_MANAGER_RUN__ build`. Режим archive-only создает `dist/extension.zip` без API-запросов.\n";
2001
+ const readmeEnGBTemplate = "# RetailCRM extension frontend\n\nThis project was generated by `embed-ui init`.\n\n## What Was Added\n\n- `package.json` with scripts for Vite build, ESLint, and extension publishing.\n- `extensionrc.json` with the generated extension manifest source.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` with `defineRunner`, one page runner, and one widget runner.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` as a starter settings page.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` as a starter order widget.\n- `__SOURCE_ROOT__/i18n/` with shared JSON message files.\n- `scripts/publish-extension.mjs` for creating `dist/extension.zip` and publishing the integration module through RetailCRM API.\n- `AGENTS.md` when agent instructions were enabled during init.\n\n## Replace Generic Values\n\nReview these generated placeholders before using the project in a real integration:\n\n- Extension code in `extensionrc.json`: `retailcrm-extension-frontend`.\n- Extension name in `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Page code: `__PAGE_CODE__`.\n- Page descriptor in `extensionrc.json`: keep `pages[]` as an object with `code`, `menu`, and `menuItemTitle`; string page form is not valid for RetailCRM API publishing.\n- Widget target: `__WIDGET_TARGET__`.\n- Sample controls and fake data in `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Sample toolbar actions and fake order data in `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Shared messages in `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nThe generated page and widget are intentionally generic. Keep the structure you need, but replace the sample labels, fields, and fake data with real product behavior.\n\n## Vue File Names\n\n`SettingsPage.vue` and `OrderCommonAfterWidget.vue` are generic starter names. In product code, rename Vue files after the role they play in the extension, and update imports in `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nExamples from RetailCRM extension examples:\n\n- `ReturnsPage.vue` is a full returns-management page.\n- `TasksPage.vue` is a task list/workspace page.\n- `SummaryPage.vue` is a summary dashboard page.\n- `RecordToCalendlyWidget.vue` is a focused widget for one scenario.\n\nUse the same idea for your code: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue`, or another name that describes the real scenario.\n\n## Commands\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Publishing\n\nCreate `.env` in the project root when you want `publish-extension` to update RetailCRM:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nRun `__PACKAGE_MANAGER_RUN__ build` before publishing. The archive-only mode creates `dist/extension.zip` without sending API requests.\n\nFor local CRM checks, `MODULE_URL` must point to a dev/static server that serves\n`/extension/<uuid>/script` and `/extension/<uuid>/stylesheet`. `publish-extension` registers these URLs in CRM,\nbut it does not start that server.\n";
2002
+ const readmeEsESTemplate = "# Frontend de extension RetailCRM\n\nEste proyecto fue generado por `embed-ui init`.\n\n## Que Se Agrego\n\n- `package.json` con scripts para Vite build, ESLint y publicacion de la extension.\n- `extensionrc.json` con la fuente del manifiesto de la extension.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` con `defineRunner`, un runner de pagina y un runner de widget.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` como pagina inicial de configuracion.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` como widget inicial del pedido.\n- `__SOURCE_ROOT__/i18n/` con archivos JSON de mensajes compartidos.\n- `scripts/publish-extension.mjs` para crear `dist/extension.zip` y publicar el modulo de integracion por RetailCRM API.\n- `AGENTS.md` si las instrucciones para agentes estaban activadas durante init.\n\n## Sustituya Los Valores Genericos\n\nRevise estos valores generados antes de usar el proyecto en una integracion real:\n\n- Codigo de extension en `extensionrc.json`: `retailcrm-extension-frontend`.\n- Nombre de extension en `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Codigo de pagina: `__PAGE_CODE__`.\n- Descriptor de pagina en `extensionrc.json`: mantenga `pages[]` como objeto con `code`, `menu` y `menuItemTitle`; la forma de cadena no sirve para publicar por la API RetailCRM.\n- Target del widget: `__WIDGET_TARGET__`.\n- Controles de ejemplo y datos ficticios en `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Acciones toolbar de ejemplo y datos ficticios del pedido en `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Mensajes compartidos en `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nLa pagina y el widget generados son intencionalmente genericos. Mantenga la estructura que necesite, pero sustituya etiquetas, campos y datos ficticios por comportamiento real del producto.\n\n## Nombres De Archivos Vue\n\n`SettingsPage.vue` y `OrderCommonAfterWidget.vue` son nombres iniciales genericos. En codigo de producto, renombre los archivos Vue segun la funcion que cumplen en la extension y actualice los imports en `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nEjemplos del repositorio de extensiones RetailCRM:\n\n- `ReturnsPage.vue` es una pagina completa de gestion de devoluciones.\n- `TasksPage.vue` es una pagina de lista o espacio de trabajo de tareas.\n- `SummaryPage.vue` es una pagina de resumen o dashboard.\n- `RecordToCalendlyWidget.vue` es un widget enfocado en un escenario.\n\nUse la misma idea para su codigo: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue` u otro nombre que describa el escenario real.\n\n## Comandos\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Publicacion\n\nCree `.env` en la raiz del proyecto cuando quiera que `publish-extension` actualice RetailCRM:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nEjecute `__PACKAGE_MANAGER_RUN__ build` antes de publicar. El modo archive-only crea `dist/extension.zip` sin enviar peticiones API.\n\nPara comprobar localmente en CRM, `MODULE_URL` debe apuntar a un dev/static server que sirva\n`/extension/<uuid>/script` y `/extension/<uuid>/stylesheet`. `publish-extension` registra estas URL en CRM,\npero no arranca ese servidor.\n";
2003
+ const readmeRuRUTemplate = "# Фронтенд расширения RetailCRM\n\nПроект создан командой `embed-ui init`.\n\n## Что Добавлено\n\n- `package.json` со скриптами для сборки Vite, ESLint и публикации расширения.\n- `extensionrc.json` с исходным описанием манифеста расширения.\n- `__SOURCE_ROOT__/endpoint/endpoint.worker.ts` с `defineRunner`, одним runner страницы и одним runner виджета.\n- `__SOURCE_ROOT__/pages/SettingsPage.vue` как стартовая страница настроек.\n- `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue` как стартовый виджет заказа.\n- `__SOURCE_ROOT__/i18n/` с общими JSON-файлами переводов.\n- `scripts/publish-extension.mjs` для создания `dist/extension.zip` и публикации интеграционного модуля через RetailCRM API.\n- `AGENTS.md`, если при инициализации были включены инструкции для агентов.\n\n## Замените Generic Значения\n\nПеред использованием проекта в реальной интеграции проверьте сгенерированные общие значения:\n\n- Код расширения в `extensionrc.json`: `retailcrm-extension-frontend`.\n- Название расширения в `extensionrc.json`: `RetailCRM Extension Frontend`.\n- Код страницы: `__PAGE_CODE__`.\n- Описание страницы в `extensionrc.json`: `pages[]` должен оставаться объектом с `code`, `menu` и `menuItemTitle`; строковая форма не подходит для публикации через RetailCRM API.\n- Цель виджета: `__WIDGET_TARGET__`.\n- Демонстрационные контролы и ненастоящие данные в `__SOURCE_ROOT__/pages/SettingsPage.vue`.\n- Демонстрационные toolbar-действия и ненастоящие данные заказа в `__SOURCE_ROOT__/widgets/OrderCommonAfterWidget.vue`.\n- Общие сообщения в `__SOURCE_ROOT__/i18n/locales/*.json`.\n\nСгенерированные страница и виджет намеренно сделаны универсальными. Оставьте нужную структуру, но замените примерные подписи, поля и ненастоящие данные на реальное поведение продукта.\n\n## Имена Vue-Файлов\n\n`SettingsPage.vue` и `OrderCommonAfterWidget.vue` — универсальные стартовые имена. В продуктовом коде переименуйте Vue-файлы по роли, которую они выполняют в расширении, и обновите импорты в `__SOURCE_ROOT__/endpoint/endpoint.worker.ts`.\n\nПримеры из репозитория расширений RetailCRM:\n\n- `ReturnsPage.vue` — полноценная страница управления возвратами.\n- `TasksPage.vue` — страница списка задач или рабочей области задач.\n- `SummaryPage.vue` — страница сводки или дашборда.\n- `RecordToCalendlyWidget.vue` — сфокусированный виджет под один сценарий.\n\nИспользуйте тот же принцип: `LoyaltySettingsPage.vue`, `OrderNotesWidget.vue`, `PaymentStatusSidebar.vue` или другое имя, которое описывает реальный сценарий.\n\n## Команды\n\n```bash\n__PACKAGE_MANAGER__ install\n__PACKAGE_MANAGER_RUN__ eslint\n__PACKAGE_MANAGER_RUN__ build\n__PACKAGE_MANAGER_RUN__ publish-extension -- --archive-only\n```\n\n## Публикация\n\nСоздайте `.env` в корне проекта, когда потребуется обновлять RetailCRM через `publish-extension`:\n\n```dotenv\nCRM_API_HOST=https://example.retailcrm.pro\nCRM_API_KEY=your-api-key\nMODULE_URL=https://example.com\n```\n\nПеред публикацией выполните `__PACKAGE_MANAGER_RUN__ build`. Режим archive-only создает `dist/extension.zip` без API-запросов.\n\nДля локальной проверки в CRM `MODULE_URL` должен указывать на dev/static server, который отдаёт\n`/extension/<uuid>/script` и `/extension/<uuid>/stylesheet`. `publish-extension` регистрирует эти URL в CRM,\nно сам dev-server не запускает.\n";
1924
2004
  const settingsPageTemplate = `<template>
1925
2005
  <main :class="$style['settings-page']">
1926
2006
  <UiPageHeader :value="t('title')">
@@ -2322,7 +2402,18 @@ const createExtensionConfig = (options) => `${JSON.stringify({
2322
2402
  uuid: randomUUID(),
2323
2403
  version: "1.0.0",
2324
2404
  targets: [options.widgetTarget],
2325
- pages: [options.pageCode],
2405
+ pages: [{
2406
+ code: options.pageCode,
2407
+ menu: "private_main_menu",
2408
+ parentMenuItemCode: "settings",
2409
+ menuItemOrdering: 100,
2410
+ menuItemTitle: {
2411
+ ru: "Настройки",
2412
+ en: "Settings",
2413
+ es: "Configuración"
2414
+ },
2415
+ pageHelpLink: null
2416
+ }],
2326
2417
  stylesheet: true,
2327
2418
  entrypointType: "script",
2328
2419
  runner: "worker"
package/dist/meta.json CHANGED
@@ -1570,9 +1570,9 @@
1570
1570
  "name": "image.workers",
1571
1571
  "type": "Array<string>",
1572
1572
  "description": {
1573
- "en-GB": "A list of servers that process images.",
1574
- "es-ES": "Una lista de servidores que procesan imágenes.",
1575
- "ru-RU": "Список серверов, обрабатывающих изображения."
1573
+ "en-GB": "List of image preview worker hosts used to build resized or cropped image URLs.",
1574
+ "es-ES": "Lista de hosts de workers de previsualización de imágenes usados para crear URLs de imágenes redimensionadas o recortadas.",
1575
+ "ru-RU": "Список host-ов image preview workers для построения URL уменьшенных или обрезанных изображений."
1576
1576
  },
1577
1577
  "readonly": true
1578
1578
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@retailcrm/embed-ui",
3
3
  "type": "module",
4
- "version": "0.9.23-alpha.3",
4
+ "version": "0.9.24",
5
5
  "description": "API and components for creating RetailCRM UI extensions",
6
6
  "repository": {
7
7
  "type": "git",
@@ -57,10 +57,10 @@
57
57
  "@omnicajs/symfony-router": "^1.0.0",
58
58
  "@omnicajs/vue-remote": "^0.2.24",
59
59
  "@remote-ui/rpc": "^1.4.5",
60
- "@retailcrm/embed-ui-v1-components": "^0.9.23-alpha.3",
61
- "@retailcrm/embed-ui-v1-contexts": "^0.9.23-alpha.3",
62
- "@retailcrm/embed-ui-v1-endpoint": "^0.9.23-alpha.3",
63
- "@retailcrm/embed-ui-v1-types": "^0.9.23-alpha.3",
60
+ "@retailcrm/embed-ui-v1-components": "^0.9.24",
61
+ "@retailcrm/embed-ui-v1-contexts": "^0.9.24",
62
+ "@retailcrm/embed-ui-v1-endpoint": "^0.9.24",
63
+ "@retailcrm/embed-ui-v1-types": "^0.9.24",
64
64
  "yargs": "^17.7.2"
65
65
  },
66
66
  "devDependencies": {
@@ -69,7 +69,7 @@
69
69
  "@modulify/git-toolkit": "^0.0.2",
70
70
  "@modulify/pkg": "^1.0.1",
71
71
  "@omnicajs/eslint-plugin-dependencies": "^0.0.2",
72
- "@retailcrm/embed-ui-v1-testing": "^0.9.23-alpha.3",
72
+ "@retailcrm/embed-ui-v1-testing": "^0.9.24",
73
73
  "@types/git-semver-tags": "^7.0.0",
74
74
  "@types/node": "^22.19.2",
75
75
  "@types/semver": "^7.7.1",