@retailcrm/embed-ui-v1-contexts 0.9.23-alpha.2 → 0.9.23

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.
@@ -0,0 +1,54 @@
1
+ "context": "settings"
2
+ "summary": "Readonly CRM settings context with UI locale, Symfony router data, and image preview worker hosts."
3
+ "language": "en-GB"
4
+ "audience": "ai"
5
+ "public_import":
6
+ "usage_import": "import { useContext } from '@retailcrm/embed-ui-v1-contexts/remote/settings'"
7
+ "usage_call": "const settings = useContext()"
8
+ "fields":
9
+ -
10
+ "name": "image.workers"
11
+ "type": "Array<string>"
12
+ "readonly": true
13
+ "description": "List of image preview worker hosts used to build resized or cropped image URLs."
14
+ "source_of_truth": "List of image preview worker hosts used to build resized or cropped image URLs."
15
+ "mutation":
16
+ "mode": "readonly"
17
+ "notes": "Readonly context field; use it for reading and UI calculations."
18
+ "related_actions": []
19
+ "ai_notes":
20
+ - "Pass these workers to usePreview or @retailcrm/image-preview preview()."
21
+ - "If the list is empty, preview helpers return the original image URL."
22
+ - "Workers are used for image preview resizing and cropping, not for uploading or storing images."
23
+ -
24
+ "name": "system.locale"
25
+ "type": "\"en-GB\"|\"es-ES\"|\"ru-RU\""
26
+ "readonly": true
27
+ "description": "Current system's locale"
28
+ "source_of_truth": "Current CRM UI locale for the opened account session."
29
+ "mutation":
30
+ "mode": "readonly"
31
+ "notes": "Readonly context field; use it for reading and UI calculations."
32
+ "related_actions": []
33
+ "ai_notes":
34
+ - "Use this locale for extension UI localization."
35
+ -
36
+ "name": "system.routing"
37
+ "type": "RoutingData"
38
+ "readonly": true
39
+ "description": "Data for Symfony's JS router"
40
+ "source_of_truth": "Symfony router dump for CRM routes available to the extension."
41
+ "mutation":
42
+ "mode": "readonly"
43
+ "notes": "Readonly context field; use it for reading and UI calculations."
44
+ "related_actions": []
45
+ "ai_notes":
46
+ - "Use this Symfony router data to build CRM route URLs."
47
+ - "Pass the routing data to @omnicajs/symfony-router instead of concatenating CRM URLs manually."
48
+ "field_groups": []
49
+ "types": []
50
+ "usage":
51
+ "import": "import { useContext } from '@retailcrm/embed-ui-v1-contexts/remote/settings'"
52
+ "call": "const settings = useContext()"
53
+ "related_actions": []
54
+ "ai_notes": []
@@ -0,0 +1,119 @@
1
+ "context": "user/current"
2
+ "summary": "Readonly current user context with identity, groups, permissions and quick role flags."
3
+ "language": "en-GB"
4
+ "audience": "ai"
5
+ "public_import":
6
+ "usage_import": "import { useContext } from '@retailcrm/embed-ui-v1-contexts/remote/user/current'"
7
+ "usage_call": "const user = useContext()"
8
+ "fields":
9
+ -
10
+ "name": "id"
11
+ "type": "number|null"
12
+ "readonly": true
13
+ "description": "User ID"
14
+ "mutation":
15
+ "mode": "readonly"
16
+ "notes": "Readonly context field; use it for reading and UI calculations."
17
+ "related_actions": []
18
+ "ai_notes": []
19
+ -
20
+ "name": "email"
21
+ "type": "string"
22
+ "readonly": true
23
+ "description": "User email"
24
+ "mutation":
25
+ "mode": "readonly"
26
+ "notes": "Readonly context field; use it for reading and UI calculations."
27
+ "related_actions": []
28
+ "ai_notes": []
29
+ -
30
+ "name": "firstName"
31
+ "type": "string|null"
32
+ "readonly": true
33
+ "description": "User name"
34
+ "mutation":
35
+ "mode": "readonly"
36
+ "notes": "Readonly context field; use it for reading and UI calculations."
37
+ "related_actions": []
38
+ "ai_notes": []
39
+ -
40
+ "name": "lastName"
41
+ "type": "string|null"
42
+ "readonly": true
43
+ "description": "User last name"
44
+ "mutation":
45
+ "mode": "readonly"
46
+ "notes": "Readonly context field; use it for reading and UI calculations."
47
+ "related_actions": []
48
+ "ai_notes": []
49
+ -
50
+ "name": "patronymic"
51
+ "type": "string|null"
52
+ "readonly": true
53
+ "description": "Patronymic of the user"
54
+ "mutation":
55
+ "mode": "readonly"
56
+ "notes": "Readonly context field; use it for reading and UI calculations."
57
+ "related_actions": []
58
+ "ai_notes": []
59
+ -
60
+ "name": "photo"
61
+ "type": "string|null"
62
+ "readonly": true
63
+ "description": "User photo"
64
+ "mutation":
65
+ "mode": "readonly"
66
+ "notes": "Readonly context field; use it for reading and UI calculations."
67
+ "related_actions": []
68
+ "ai_notes": []
69
+ -
70
+ "name": "groups"
71
+ "type": "Array<string>"
72
+ "readonly": true
73
+ "description": "Symbolic codes of the groups the user belongs to"
74
+ "mutation":
75
+ "mode": "readonly"
76
+ "notes": "Readonly context field; use it for reading and UI calculations."
77
+ "related_actions": []
78
+ "ai_notes":
79
+ - "Use group codes for role/group-based UI decisions."
80
+ -
81
+ "name": "permissions"
82
+ "type": "Array<string>"
83
+ "readonly": true
84
+ "description": "Character codes of available user permissions"
85
+ "mutation":
86
+ "mode": "readonly"
87
+ "notes": "Readonly context field; use it for reading and UI calculations."
88
+ "related_actions": []
89
+ "ai_notes":
90
+ - "Use permission codes for feature gating and conditional action visibility."
91
+ -
92
+ "name": "isAdmin"
93
+ "type": "boolean"
94
+ "readonly": true
95
+ "description": "Indicates whether the user has administrator privileges"
96
+ "mutation":
97
+ "mode": "readonly"
98
+ "notes": "Readonly context field; use it for reading and UI calculations."
99
+ "related_actions": []
100
+ "ai_notes":
101
+ - "Quick flag for administrator-specific UI branches."
102
+ -
103
+ "name": "isManager"
104
+ "type": "boolean"
105
+ "readonly": true
106
+ "description": "Indicates whether the user has manager privileges"
107
+ "mutation":
108
+ "mode": "readonly"
109
+ "notes": "Readonly context field; use it for reading and UI calculations."
110
+ "related_actions": []
111
+ "ai_notes":
112
+ - "Quick flag for manager-specific UI branches."
113
+ "field_groups": []
114
+ "types": []
115
+ "usage":
116
+ "import": "import { useContext } from '@retailcrm/embed-ui-v1-contexts/remote/user/current'"
117
+ "call": "const user = useContext()"
118
+ "related_actions": []
119
+ "ai_notes": []
@@ -0,0 +1,10 @@
1
+ {
2
+ "package": "@retailcrm/embed-ui-v1-contexts",
3
+ "resources": [
4
+ {
5
+ "id": "order",
6
+ "uri": "embed-ui-v1-contexts://custom-contexts/order",
7
+ "file": "docs/custom-contexts/order.yml"
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,65 @@
1
+ "custom_context": "order"
2
+ "summary": "Custom fields context for order entity custom fields."
3
+ "language": "en-GB"
4
+ "audience": "ai"
5
+ "public_import":
6
+ "from": "@retailcrm/embed-ui-v1-contexts/remote/custom"
7
+ "named":
8
+ - "useContext"
9
+ - "useDictionary"
10
+ - "isTypeOf"
11
+ "supported_kinds":
12
+ -
13
+ "kind": "boolean"
14
+ "type": "boolean|null"
15
+ "requires_dictionary": false
16
+ -
17
+ "kind": "date"
18
+ "type": "string|null"
19
+ "requires_dictionary": false
20
+ -
21
+ "kind": "datetime"
22
+ "type": "string|null"
23
+ "requires_dictionary": false
24
+ -
25
+ "kind": "dictionary"
26
+ "type": "string|null"
27
+ "requires_dictionary": true
28
+ -
29
+ "kind": "multiselect_dictionary"
30
+ "type": "string[]"
31
+ "requires_dictionary": true
32
+ -
33
+ "kind": "email"
34
+ "type": "string|null"
35
+ "requires_dictionary": false
36
+ -
37
+ "kind": "integer"
38
+ "type": "number|null"
39
+ "requires_dictionary": false
40
+ -
41
+ "kind": "numeric"
42
+ "type": "number|null"
43
+ "requires_dictionary": false
44
+ -
45
+ "kind": "string"
46
+ "type": "string|null"
47
+ "requires_dictionary": false
48
+ -
49
+ "kind": "text"
50
+ "type": "string|null"
51
+ "requires_dictionary": false
52
+ "usage":
53
+ "initialize": "const custom = useContext('order'); await custom.initialize()"
54
+ "read": "custom.values[code]"
55
+ "write": "custom.set(code, value)"
56
+ "dictionary": "const dictionary = useDictionary(); await dictionary.query(dictionaryCode, { first: 20 })"
57
+ "write_rules":
58
+ - "Call initialize before reading or writing custom field values."
59
+ - "Do not write fields marked readonly in the custom schema."
60
+ - "Use values matching the field kind; invalid values are rejected by the remote store."
61
+ - "Load dictionaries for dictionary and multiselect_dictionary fields when labels/options are needed."
62
+ "ai_notes":
63
+ - "Call initialize before reading custom field values."
64
+ - "Do not write readonly custom fields; the remote store rejects writes according to schema."
65
+ - "Dictionary and multiselect_dictionary fields require dictionary loading for option labels."
@@ -1,13 +1,198 @@
1
- # Концепт [DRAFT]
1
+ # Предустановленные контексты
2
2
 
3
- Данный пакет предоставляет логику и типы для host и remote окружения. Часть предложенных типов используются одновременно
4
- в обоих окружениях, в частности `ContextAccessor` и `CustomContextAccessor` на стороне host'а создаются два таких
5
- объекта и смешиваются в один, чтобы затем их методы предоставить в качестве удаленного API, который потребляется
6
- расширениями в remote окружении.
3
+ `@retailcrm/embed-ui-v1-contexts` предоставляет реактивные контексты RetailCRM для JS-расширений.
4
+ Контекст дает расширению доступ к данным страницы CRM, на которой оно запущено: например к форме заказа,
5
+ карточке клиента, текущему пользователю или системным настройкам.
7
6
 
8
- `ContextAccessor` используется для получения/изменения данных некоторого предустановленного контекста, состав которого
9
- известен заранее. Для доступа к полям указывается название частичного контекста, например, `order/card` и название поля
10
- в частичном контексте.
7
+ Контексты используются в remote-коде расширения. CRM host передает данные и события через endpoint,
8
+ а расширение работает с ними через публичные composable-утилиты пакета.
11
9
 
12
- `CustomContextAccessor` используется для получения/изменения данных некоторого пользовательского контекста, который
13
- основан на пользовательских полях. Состав такого контекста заранее неизвестен.
10
+ ## Виды контекстов
11
+
12
+ В пакете есть два вида контекстов:
13
+
14
+ - Предустановленные контексты — имеют заранее известный набор полей, типы и readonly/writable статус.
15
+ Примеры: `order/card`, `order/card:settings`, `user/current`, `settings`.
16
+ - Пользовательские контексты — строятся по схеме пользовательских полей CRM, поэтому состав полей заранее
17
+ неизвестен. Они описаны отдельно в [`CUSTOM.md`](./CUSTOM.md).
18
+
19
+ Этот документ описывает предустановленные контексты.
20
+
21
+ ## Как выбрать доступный контекст
22
+
23
+ Доступность контекста зависит от widget target. Для виджетов source of truth находится в
24
+ `@retailcrm/embed-ui-v1-endpoint`: target profile перечисляет `contexts`, `custom_contexts` и `action_scopes`,
25
+ которые доступны в конкретной точке встраивания.
26
+
27
+ Не нужно выводить доступность контекста из названия страницы или target id. Используйте target config.
28
+ Если target не перечисляет нужный контекст, расширение не должно полагаться на его наличие.
29
+
30
+ ## Использование в remote-коде
31
+
32
+ Каждый предустановленный контекст экспортирует `useContext` из своего public entrypoint:
33
+
34
+ ```typescript
35
+ import { useContext } from '@retailcrm/embed-ui-v1-contexts/remote/order/card'
36
+
37
+ const order = useContext()
38
+ ```
39
+
40
+ Контекст работает как Pinia store с реактивными getters/setters для полей схемы. Поля и типы известны из
41
+ соответствующего `types/*.d.ts` и generated profiles.
42
+
43
+ Пример чтения данных заказа:
44
+
45
+ ```typescript
46
+ import { computed } from 'vue'
47
+
48
+ import { useContext } from '@retailcrm/embed-ui-v1-contexts/remote/order/card'
49
+
50
+ const order = useContext()
51
+
52
+ const hasItems = computed(() => order.items.length > 0)
53
+ const customerEmail = computed(() => order['customer.email'])
54
+ ```
55
+
56
+ Пример записи writable поля:
57
+
58
+ ```typescript
59
+ import { useContext } from '@retailcrm/embed-ui-v1-contexts/remote/order/card'
60
+
61
+ const order = useContext()
62
+
63
+ order['discount.percent'] = 10
64
+ order['delivery.address'] = 'Москва, Тверская, 1'
65
+ ```
66
+
67
+ ## Readonly и writable поля
68
+
69
+ Каждое поле схемы имеет флаг `readonly`.
70
+
71
+ - Readonly поля предназначены для чтения и расчетов UI. Их нельзя менять напрямую.
72
+ - Writable поля можно менять через context store, если изменение соответствует контракту CRM.
73
+ - Если поле является агрегатом или управляется сложной логикой формы, правильный способ изменения может быть action,
74
+ даже если UI-задача выглядит как изменение одного значения.
75
+
76
+ Например, в `order/card` поле `items` является readonly source of truth для состава заказа. Для изменения товарных
77
+ позиций используются actions: `changeItemQuantity`, `changeItemPriceType`, `changeItemDiscount`, `removeItem` и другие.
78
+
79
+ ## Actions
80
+
81
+ Некоторые контексты имеют отдельный action scope. Actions нужны для host-mediated изменений, где прямой set поля
82
+ не отражает бизнес-операцию или невозможен из-за readonly-поля.
83
+
84
+ Для `order/card` actions экспортируются рядом с context:
85
+
86
+ ```typescript
87
+ import {
88
+ useActions,
89
+ useContext,
90
+ } from '@retailcrm/embed-ui-v1-contexts/remote/order/card'
91
+
92
+ const order = useContext()
93
+ const actions = useActions()
94
+
95
+ const firstItem = order.items[0]
96
+
97
+ if (firstItem) {
98
+ await actions.changeItemQuantity(firstItem.index, firstItem.quantity + 1)
99
+ }
100
+ ```
101
+
102
+ Используйте `OrderItem.index` из текущего `items` как идентификатор позиции при вызове item actions.
103
+
104
+ ## Основные предустановленные контексты
105
+
106
+ ### `order/card`
107
+
108
+ Данные формы заказа:
109
+
110
+ - идентификаторы и служебные поля заказа;
111
+ - customer fields;
112
+ - company fields;
113
+ - `items` — readonly список товарных позиций;
114
+ - `delivery.address` — writable адрес доставки;
115
+ - `discount.amount`, `discount.percent` — writable одноразовая скидка заказа;
116
+ - `discount.total` — readonly итоговая скидка;
117
+ - `status` — readonly статус заказа.
118
+
119
+ Для изменения товарных позиций используйте `useActions()` из
120
+ `@retailcrm/embed-ui-v1-contexts/remote/order/card`.
121
+
122
+ ### `order/card:settings`
123
+
124
+ Readonly настройки формы заказа. Они нужны, чтобы UI расширения уважал возможности текущей CRM-формы:
125
+
126
+ - `priceEditable`;
127
+ - `productsRemoveAllowed`;
128
+ - `quantityIsFractional`;
129
+ - `showPriceTypes`;
130
+ - `useStores`;
131
+ - `useReserve`.
132
+
133
+ Например, если `quantityIsFractional` равен `false`, UI ввода количества не должен предлагать дробные значения.
134
+
135
+ ### `customer/card`
136
+
137
+ Данные карточки клиента:
138
+
139
+ - `id`;
140
+ - `externalId`;
141
+ - `type`;
142
+ - `firstName`;
143
+ - `lastName`;
144
+ - `patronymic`.
145
+
146
+ ### `customer/card:phone`
147
+
148
+ Телефонный контекст карточки клиента. Используется в target, где CRM предоставляет телефон клиента.
149
+
150
+ ### `user/current`
151
+
152
+ Readonly данные текущего пользователя:
153
+
154
+ - идентификатор и ФИО;
155
+ - `groups`;
156
+ - `permissions`;
157
+ - `isAdmin`;
158
+ - `isManager`.
159
+
160
+ Используйте `permissions`, `groups` и quick flags для условного отображения действий в UI расширения.
161
+
162
+ ### `settings`
163
+
164
+ Readonly системные настройки:
165
+
166
+ - `system.locale` — локаль CRM;
167
+ - `system.routing` — данные Symfony router для построения CRM route URL;
168
+ - `image.workers` — worker endpoints для обработки изображений.
169
+
170
+ ## Generated AI profiles
171
+
172
+ При сборке пакета генерируются AI-friendly profiles:
173
+
174
+ - `docs/contexts/*.yml` — описание предустановленных контекстов;
175
+ - `docs/actions/*.yml` — описание action scopes;
176
+ - `docs/custom-contexts/*.yml` — описание custom context entities;
177
+ - `docs/*/index.json` — индексы generated resources.
178
+
179
+ Profiles генерируются из typed source metadata и не редактируются вручную:
180
+
181
+ ```bash
182
+ yarn workspace @retailcrm/embed-ui-v1-contexts run build:docs
183
+ ```
184
+
185
+ Полная сборка workspace тоже запускает генерацию:
186
+
187
+ ```bash
188
+ yarn workspace @retailcrm/embed-ui-v1-contexts run build
189
+ ```
190
+
191
+ Release workflow выполняет `yarn workspaces foreach -A --topological-dev run build`, поэтому profiles
192
+ генерируются перед публикацией и входят в published package вместе с `docs`.
193
+
194
+ ## Связанные документы
195
+
196
+ - [`CUSTOM.md`](./CUSTOM.md) — пользовательские контексты для custom fields.
197
+ - [`@retailcrm/embed-ui-v1-endpoint` targets](../../../v1-endpoint/docs/targets.md) — как определить,
198
+ какие contexts доступны в widget target.
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "@retailcrm/embed-ui-v1-contexts",
3
+ "bin": {
4
+ "embed-ui-v1-contexts": "bin/embed-ui-v1-contexts.mjs",
5
+ "embed-ui-v1-contexts-mcp": "bin/embed-ui-v1-contexts-mcp.mjs"
6
+ },
3
7
  "description": "Reactive contexts for RetailCRM JS API",
4
8
  "type": "module",
5
- "version": "0.9.23-alpha.2",
9
+ "version": "0.9.23",
6
10
  "license": "MIT",
7
11
  "author": "RetailDriverLLC <integration@retailcrm.ru>",
8
12
  "repository": {
@@ -23,6 +27,12 @@
23
27
  "require": "./dist/remote.cjs",
24
28
  "default": "./dist/remote.js"
25
29
  },
30
+ "./mcp": {
31
+ "types": "./dist/mcp/server.d.ts",
32
+ "import": "./dist/mcp/server.js",
33
+ "require": "./dist/mcp/server.cjs",
34
+ "default": "./dist/mcp/server.js"
35
+ },
26
36
  "./remote/customer/*": {
27
37
  "types": "./dist/remote/customer/*.d.ts",
28
38
  "import": "./dist/remote/customer/*.js",
@@ -63,6 +73,9 @@
63
73
  "remote": [
64
74
  "./dist/remote.d.ts"
65
75
  ],
76
+ "mcp": [
77
+ "./dist/mcp/server.d.ts"
78
+ ],
66
79
  "remote/customer/card": [
67
80
  "./dist/remote/customer/card.d.ts"
68
81
  ],
@@ -87,30 +100,34 @@
87
100
  }
88
101
  },
89
102
  "files": [
103
+ "bin",
90
104
  "dist",
91
105
  "docs",
92
106
  "types",
93
107
  "README.md"
94
108
  ],
95
109
  "scripts": {
96
- "build": "yarn prepare && yarn build:code && yarn build:meta",
110
+ "build": "yarn prepare && yarn build:docs && yarn build:code && yarn build:mcp && yarn build:meta",
97
111
  "build:code": "vite build",
112
+ "build:docs": "npx tsx scripts/build.docs.ts",
113
+ "build:mcp": "vite build -c ./vite.config.mcp.ts",
98
114
  "build:meta": "npx tsx scripts/build.meta.ts",
99
115
  "generate:known-types": "npx tsx scripts/generate.known-types.ts",
100
116
  "prepare": "yarn generate:known-types",
101
- "test": "yarn prepare && vitest --run"
117
+ "test": "yarn prepare && yarn build:docs && vitest --run"
102
118
  },
103
119
  "peerDependencies": {
104
120
  "@remote-ui/rpc": "^1.4",
105
121
  "pinia": "^2.2"
106
122
  },
107
123
  "dependencies": {
124
+ "@modelcontextprotocol/sdk": "^1.29.0",
108
125
  "@omnicajs/symfony-router": "^1.0.0",
109
- "@retailcrm/embed-ui-v1-types": "^0.9.23-alpha.2"
126
+ "@retailcrm/embed-ui-v1-types": "^0.9.23"
110
127
  },
111
128
  "devDependencies": {
112
129
  "@remote-ui/rpc": "^1.4.7",
113
- "@retailcrm/embed-ui-v1-testing": "^0.9.23-alpha.2",
130
+ "@retailcrm/embed-ui-v1-testing": "^0.9.23",
114
131
  "tsx": "^4.21.0",
115
132
  "typescript": "^5.9.3",
116
133
  "vite": "^7.3.2",