iwgt 2.4.6 → 2.4.9
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/dist/data/references/block-templates-full.json +163 -160
- package/dist/data/references/category-block-templates.json +25 -11
- package/dist/data/references/category-settings.json +1209 -318
- package/dist/data/references/commonjs-api-complete.json +1037 -0
- package/dist/data/references/commonjs-reference.json +1 -1
- package/dist/data/references/libraries-api-reference.json +199 -0
- package/dist/data/references/libraries-registry.json +58 -28
- package/dist/data/references/liquid-filters.json +1 -1
- package/dist/data/references/liquid-variables.json +1 -1
- package/dist/server-http.js +17 -41
- package/dist/server.js +48 -1
- package/dist/tools/index.d.ts +7 -1
- package/dist/tools/index.js +301 -74
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "2.0",
|
|
3
|
-
"generatedAt": "2025-10-
|
|
3
|
+
"generatedAt": "2025-10-08T21:45:54.929Z",
|
|
4
4
|
"description": "Справочник по библиотеке common.v2.js для InSales - набор готовых скриптов для разработки шаблонов",
|
|
5
5
|
"installation": {
|
|
6
6
|
"method": "liquid_tag",
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Справочник API библиотек InSales",
|
|
3
|
+
"description": "Полная документация по API доступных библиотек в виджетах InSales",
|
|
4
|
+
"libraries": [
|
|
5
|
+
{
|
|
6
|
+
"name": "InsalesCutList",
|
|
7
|
+
"handle": "cut-list",
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"type": "jquery-plugin",
|
|
10
|
+
"description": "jQuery-плагин для обработки списков с автоматическим сворачиванием элементов, которые не помещаются в одну строку. Идеален для навигационных меню и списков категорий.",
|
|
11
|
+
"categories": ["navigation", "headers", "lite", "landing", "product-homepage"],
|
|
12
|
+
"dependencies": ["jquery"],
|
|
13
|
+
"usage": {
|
|
14
|
+
"initialization": {
|
|
15
|
+
"jquery": "$('.cut-list').cutList(options);",
|
|
16
|
+
"class": "new InsalesCutList($('.cut-list'), options);"
|
|
17
|
+
},
|
|
18
|
+
"html": "<div class=\"cut-list\">\n <div><a href=\"#\">Item 1</a></div>\n <div><a href=\"#\">Item 2</a></div>\n <div><a href=\"#\">Item 3</a></div>\n</div>"
|
|
19
|
+
},
|
|
20
|
+
"options": [
|
|
21
|
+
{
|
|
22
|
+
"name": "moreBtnTitle",
|
|
23
|
+
"type": "string",
|
|
24
|
+
"default": "Еще",
|
|
25
|
+
"description": "Текст кнопки 'Еще'. Может быть HTML строкой (например, '<i class=\"icon icon-ellipsis-h\"></i>')."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "showMoreOnHover",
|
|
29
|
+
"type": "boolean",
|
|
30
|
+
"default": false,
|
|
31
|
+
"description": "Показывать скрытые элементы при наведении мыши на кнопку 'Еще'."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "alwaysVisibleElem",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"default": "undefined",
|
|
37
|
+
"description": "CSS селектор элемента, который всегда должен быть видимым. Только первый найденный элемент будет учтен. Полезно для активных элементов меню."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "onBeforeCalc",
|
|
41
|
+
"type": "function",
|
|
42
|
+
"default": "() => {}",
|
|
43
|
+
"description": "Колбек перед расчетом видимых/скрытых элементов."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "onBeforeOpen",
|
|
47
|
+
"type": "function",
|
|
48
|
+
"default": "() => {}",
|
|
49
|
+
"description": "Колбек перед открытием выпадающего списка скрытых элементов."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "onOpen",
|
|
53
|
+
"type": "function",
|
|
54
|
+
"default": "() => {}",
|
|
55
|
+
"description": "Колбек после открытия выпадающего списка."
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "onBeforeClose",
|
|
59
|
+
"type": "function",
|
|
60
|
+
"default": "() => {}",
|
|
61
|
+
"description": "Колбек перед закрытием выпадающего списка."
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "onClose",
|
|
65
|
+
"type": "function",
|
|
66
|
+
"default": "() => {}",
|
|
67
|
+
"description": "Колбек после закрытия выпадающего списка."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "resizeDelay",
|
|
71
|
+
"type": "number",
|
|
72
|
+
"default": 50,
|
|
73
|
+
"description": "Задержка в миллисекундах для дебаунса события resize."
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "minWidth",
|
|
77
|
+
"type": "number",
|
|
78
|
+
"default": "null",
|
|
79
|
+
"description": "Минимальная ширина экрана (в пикселях) для инициализации плагина. Если ширина экрана меньше или равна этому значению, плагин не будет инициализирован или будет уничтожен."
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"methods": [
|
|
83
|
+
{
|
|
84
|
+
"name": "init",
|
|
85
|
+
"description": "Инициализация плагина на элементах",
|
|
86
|
+
"parameters": [],
|
|
87
|
+
"returns": "void"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "destroy",
|
|
91
|
+
"description": "Уничтожение плагина и очистка ресурсов",
|
|
92
|
+
"parameters": [],
|
|
93
|
+
"returns": "void"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "redrawList",
|
|
97
|
+
"description": "Пересчет и перерисовка списка (вызывается автоматически при resize)",
|
|
98
|
+
"parameters": [],
|
|
99
|
+
"returns": "void"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"examples": [
|
|
103
|
+
{
|
|
104
|
+
"title": "Базовая инициализация",
|
|
105
|
+
"description": "Простейший пример использования",
|
|
106
|
+
"code": {
|
|
107
|
+
"liquid": "<div class=\"cut-list\">\n <div><a href=\"#\">Категория 1</a></div>\n <div><a href=\"#\">Категория 2</a></div>\n <div><a href=\"#\">Категория 3</a></div>\n</div>",
|
|
108
|
+
"javascript": "$('.cut-list').cutList({\n moreBtnTitle: 'Ещё',\n showMoreOnHover: false\n});"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"title": "С иконкой вместо текста",
|
|
113
|
+
"description": "Кнопка 'Еще' с иконкой",
|
|
114
|
+
"code": {
|
|
115
|
+
"liquid": "<div class=\"cut-list\">\n <div><a href=\"#\">Категория 1</a></div>\n <div><a href=\"#\">Категория 2</a></div>\n <div class=\"is-current\"><a href=\"#\">Активная категория</a></div>\n <div><a href=\"#\">Категория 4</a></div>\n</div>",
|
|
116
|
+
"javascript": "new InsalesCutList($('.cut-list'), {\n moreBtnTitle: '<i class=\"icon icon-ellipsis-h\"></i>',\n alwaysVisibleElem: '.is-current',\n showMoreOnHover: true\n});"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"title": "С минимальной шириной экрана",
|
|
121
|
+
"description": "Плагин работает только на экранах шире 768px",
|
|
122
|
+
"code": {
|
|
123
|
+
"liquid": "<ul class=\"cut-list\">\n <li>Item 1</li>\n <li>Item 2</li>\n <li class=\"my-active\">Item 3</li>\n <li>Item 4</li>\n</ul>",
|
|
124
|
+
"javascript": "new InsalesCutList($('.cut-list'), {\n moreBtnTitle: 'Показать еще',\n alwaysVisibleElem: '.my-active',\n minWidth: 767 // Работает на экранах > 767px\n});"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"title": "С колбеками",
|
|
129
|
+
"description": "Использование событий открытия/закрытия",
|
|
130
|
+
"code": {
|
|
131
|
+
"javascript": "$('.cut-list').cutList({\n moreBtnTitle: 'Ещё',\n onBeforeOpen: function($elements) {\n console.log('Открываем меню');\n },\n onOpen: function($elements) {\n console.log('Меню открыто');\n },\n onBeforeClose: function($elements) {\n console.log('Закрываем меню');\n },\n onClose: function($elements) {\n console.log('Меню закрыто');\n }\n});"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"title": "Меню категорий в шапке",
|
|
136
|
+
"description": "Полный пример для навигации в header",
|
|
137
|
+
"code": {
|
|
138
|
+
"liquid": "<nav class=\"header-nav\">\n <ul class=\"cut-list\">\n {% for collection in collections %}\n <li {% if collection.id == current_collection.id %}class=\"is-active\"{% endif %}>\n <a href=\"{{ collection.url }}\">{{ collection.title }}</a>\n </li>\n {% endfor %}\n </ul>\n</nav>",
|
|
139
|
+
"javascript": "new InsalesCutList($('.header-nav .cut-list'), {\n moreBtnTitle: '<i class=\"icon icon-bars\"></i>',\n alwaysVisibleElem: '.is-active',\n showMoreOnHover: true,\n minWidth: 767\n});",
|
|
140
|
+
"scss": ".header-nav {\n .cut-list {\n display: flex;\n gap: 1rem;\n \n &__dropdown {\n position: relative;\n }\n \n &__more {\n position: absolute;\n top: 100%;\n right: 0;\n background: white;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n padding: 0.5rem 0;\n min-width: 200px;\n }\n }\n}"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
"cssClasses": [
|
|
145
|
+
{
|
|
146
|
+
"name": ".cut-list",
|
|
147
|
+
"description": "Основной контейнер списка (добавляется автоматически)"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"name": ".cut-list__elem",
|
|
151
|
+
"description": "Элемент списка (добавляется автоматически)"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": ".cut-list__dropdown",
|
|
155
|
+
"description": "Контейнер для кнопки 'Еще' и выпадающего меню (создается автоматически)"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": ".cut-list__btn",
|
|
159
|
+
"description": "Кнопка 'Еще' (создается автоматически)"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"name": ".cut-list__more",
|
|
163
|
+
"description": "Выпадающее меню со скрытыми элементами (создается автоматически)"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"name": ".is-show",
|
|
167
|
+
"description": "Класс для открытого состояния выпадающего меню"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"name": ".is-top",
|
|
171
|
+
"description": "Класс для меню, открывающегося вверх"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"name": ".is-left",
|
|
175
|
+
"description": "Класс для меню, открывающегося влево"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"name": ".cut-list-ready",
|
|
179
|
+
"description": "Класс, добавляемый после инициализации"
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"bestPractices": [
|
|
183
|
+
"Используйте `alwaysVisibleElem` для активных элементов навигации, чтобы они всегда были видны",
|
|
184
|
+
"Для мобильных версий используйте `minWidth` для отключения плагина на узких экранах",
|
|
185
|
+
"Кастомизируйте кнопку 'Еще' через `moreBtnTitle` - можно использовать HTML и иконки",
|
|
186
|
+
"Используйте `showMoreOnHover: true` для более удобного UX",
|
|
187
|
+
"Плагин автоматически пересчитывает элементы при изменении размера окна",
|
|
188
|
+
"ResizeObserver автоматически отслеживает изменения размеров элементов"
|
|
189
|
+
],
|
|
190
|
+
"notes": [
|
|
191
|
+
"Плагин автоматически создает структуру .cut-list__dropdown с кнопкой и выпадающим меню",
|
|
192
|
+
"При инициализации элементам автоматически добавляются data-index атрибуты",
|
|
193
|
+
"Плагин использует ResizeObserver для отслеживания изменений размеров",
|
|
194
|
+
"При достижении minWidth плагин автоматически уничтожается и восстанавливается",
|
|
195
|
+
"Выпадающее меню автоматически позиционируется (вверх/вниз, влево/вправо) в зависимости от доступного пространства"
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
{
|
|
4
4
|
"name": "my-layout",
|
|
5
5
|
"description": "CSS фреймворк InSales",
|
|
6
|
-
"usage":
|
|
6
|
+
"usage": 356,
|
|
7
7
|
"frequency": 0.99,
|
|
8
8
|
"categories": [
|
|
9
9
|
"text",
|
|
@@ -23,10 +23,13 @@
|
|
|
23
23
|
"compare",
|
|
24
24
|
"delimeters",
|
|
25
25
|
"footers",
|
|
26
|
+
"gallery",
|
|
26
27
|
"headers",
|
|
27
28
|
"lite",
|
|
29
|
+
"marquee",
|
|
28
30
|
"modal_age",
|
|
29
31
|
"modal_cookie",
|
|
32
|
+
"modals",
|
|
30
33
|
"multilink",
|
|
31
34
|
"notification_add_to_cart",
|
|
32
35
|
"pagination",
|
|
@@ -54,7 +57,7 @@
|
|
|
54
57
|
{
|
|
55
58
|
"name": "jquery",
|
|
56
59
|
"description": "jQuery",
|
|
57
|
-
"usage":
|
|
60
|
+
"usage": 260,
|
|
58
61
|
"frequency": 0.72,
|
|
59
62
|
"categories": [
|
|
60
63
|
"text",
|
|
@@ -74,9 +77,12 @@
|
|
|
74
77
|
"filters",
|
|
75
78
|
"collection-subcollections",
|
|
76
79
|
"compare",
|
|
80
|
+
"gallery",
|
|
77
81
|
"headers",
|
|
78
82
|
"landing",
|
|
79
83
|
"lite",
|
|
84
|
+
"marquee",
|
|
85
|
+
"modals",
|
|
80
86
|
"multilink",
|
|
81
87
|
"notification_add_to_cart",
|
|
82
88
|
"employees",
|
|
@@ -100,8 +106,8 @@
|
|
|
100
106
|
{
|
|
101
107
|
"name": "commonjs_v2",
|
|
102
108
|
"description": "Фреймворк InSales (Products, Cart, EventBus)",
|
|
103
|
-
"usage":
|
|
104
|
-
"frequency": 0.
|
|
109
|
+
"usage": 188,
|
|
110
|
+
"frequency": 0.52,
|
|
105
111
|
"categories": [
|
|
106
112
|
"notices",
|
|
107
113
|
"forms",
|
|
@@ -139,7 +145,7 @@
|
|
|
139
145
|
{
|
|
140
146
|
"name": "splide",
|
|
141
147
|
"description": "Слайдер Splide v2",
|
|
142
|
-
"usage":
|
|
148
|
+
"usage": 107,
|
|
143
149
|
"frequency": 0.3,
|
|
144
150
|
"categories": [
|
|
145
151
|
"blog",
|
|
@@ -189,12 +195,13 @@
|
|
|
189
195
|
{
|
|
190
196
|
"name": "vanilla-lazyload",
|
|
191
197
|
"description": "Ленивая загрузка изображений",
|
|
192
|
-
"usage":
|
|
198
|
+
"usage": 50,
|
|
193
199
|
"frequency": 0.14,
|
|
194
200
|
"categories": [
|
|
195
201
|
"collection-products",
|
|
196
202
|
"headers",
|
|
197
203
|
"lite",
|
|
204
|
+
"marquee",
|
|
198
205
|
"multilink",
|
|
199
206
|
"sliders",
|
|
200
207
|
"product-homepage",
|
|
@@ -203,49 +210,51 @@
|
|
|
203
210
|
"documentation": null
|
|
204
211
|
},
|
|
205
212
|
{
|
|
206
|
-
"name": "
|
|
207
|
-
"description": "
|
|
208
|
-
"usage":
|
|
209
|
-
"frequency": 0.
|
|
213
|
+
"name": "micromodal",
|
|
214
|
+
"description": "Модальные окна",
|
|
215
|
+
"usage": 42,
|
|
216
|
+
"frequency": 0.12,
|
|
210
217
|
"categories": [
|
|
211
|
-
"forms",
|
|
212
218
|
"blog",
|
|
219
|
+
"cart",
|
|
213
220
|
"collection-products",
|
|
214
|
-
"text",
|
|
215
221
|
"lite",
|
|
222
|
+
"modals",
|
|
223
|
+
"reviews",
|
|
216
224
|
"products-cards",
|
|
217
225
|
"product-related",
|
|
218
226
|
"product-similar",
|
|
219
|
-
"sliders",
|
|
220
227
|
"product-promo",
|
|
221
|
-
"product-homepage"
|
|
222
|
-
"stories"
|
|
228
|
+
"product-homepage"
|
|
223
229
|
],
|
|
224
|
-
"documentation": "https://
|
|
230
|
+
"documentation": "https://micromodal.vercel.app/"
|
|
225
231
|
},
|
|
226
232
|
{
|
|
227
|
-
"name": "
|
|
228
|
-
"description": "
|
|
229
|
-
"usage":
|
|
233
|
+
"name": "fslightbox",
|
|
234
|
+
"description": "Лайтбокс для изображений",
|
|
235
|
+
"usage": 41,
|
|
230
236
|
"frequency": 0.11,
|
|
231
237
|
"categories": [
|
|
238
|
+
"forms",
|
|
232
239
|
"blog",
|
|
233
|
-
"cart",
|
|
234
240
|
"collection-products",
|
|
241
|
+
"gallery",
|
|
242
|
+
"text",
|
|
235
243
|
"lite",
|
|
236
|
-
"reviews",
|
|
237
244
|
"products-cards",
|
|
238
245
|
"product-related",
|
|
239
246
|
"product-similar",
|
|
247
|
+
"sliders",
|
|
240
248
|
"product-promo",
|
|
241
|
-
"product-homepage"
|
|
249
|
+
"product-homepage",
|
|
250
|
+
"stories"
|
|
242
251
|
],
|
|
243
|
-
"documentation": "https://
|
|
252
|
+
"documentation": "https://fslightbox.com/"
|
|
244
253
|
},
|
|
245
254
|
{
|
|
246
255
|
"name": "body-scroll-lock",
|
|
247
256
|
"description": "Блокировка скролла",
|
|
248
|
-
"usage":
|
|
257
|
+
"usage": 29,
|
|
249
258
|
"frequency": 0.08,
|
|
250
259
|
"categories": [
|
|
251
260
|
"blog",
|
|
@@ -254,6 +263,7 @@
|
|
|
254
263
|
"headers",
|
|
255
264
|
"lite",
|
|
256
265
|
"modal_age",
|
|
266
|
+
"modals",
|
|
257
267
|
"products-cards",
|
|
258
268
|
"product-related",
|
|
259
269
|
"product-similar",
|
|
@@ -265,13 +275,14 @@
|
|
|
265
275
|
{
|
|
266
276
|
"name": "cut-list",
|
|
267
277
|
"description": "cut-list",
|
|
268
|
-
"usage":
|
|
269
|
-
"frequency": 0.
|
|
278
|
+
"usage": 24,
|
|
279
|
+
"frequency": 0.07,
|
|
270
280
|
"categories": [
|
|
271
281
|
"navigation",
|
|
272
282
|
"headers",
|
|
273
283
|
"lite",
|
|
274
284
|
"landing",
|
|
285
|
+
"sliders",
|
|
275
286
|
"product-homepage"
|
|
276
287
|
],
|
|
277
288
|
"documentation": null
|
|
@@ -279,13 +290,14 @@
|
|
|
279
290
|
{
|
|
280
291
|
"name": "js-cookie",
|
|
281
292
|
"description": "Работа с cookies",
|
|
282
|
-
"usage":
|
|
293
|
+
"usage": 8,
|
|
283
294
|
"frequency": 0.02,
|
|
284
295
|
"categories": [
|
|
285
296
|
"notices",
|
|
286
297
|
"banner",
|
|
287
298
|
"collection-products",
|
|
288
299
|
"modal_cookie",
|
|
300
|
+
"modals",
|
|
289
301
|
"drugie"
|
|
290
302
|
],
|
|
291
303
|
"documentation": null
|
|
@@ -459,6 +471,11 @@
|
|
|
459
471
|
"footers": [
|
|
460
472
|
"my-layout"
|
|
461
473
|
],
|
|
474
|
+
"gallery": [
|
|
475
|
+
"jquery",
|
|
476
|
+
"fslightbox",
|
|
477
|
+
"my-layout"
|
|
478
|
+
],
|
|
462
479
|
"headers": [
|
|
463
480
|
"commonjs_v2",
|
|
464
481
|
"jquery",
|
|
@@ -480,6 +497,11 @@
|
|
|
480
497
|
"cut-list",
|
|
481
498
|
"fslightbox"
|
|
482
499
|
],
|
|
500
|
+
"marquee": [
|
|
501
|
+
"jquery",
|
|
502
|
+
"vanilla-lazyload",
|
|
503
|
+
"my-layout"
|
|
504
|
+
],
|
|
483
505
|
"modal_age": [
|
|
484
506
|
"my-layout",
|
|
485
507
|
"microalert",
|
|
@@ -489,6 +511,13 @@
|
|
|
489
511
|
"my-layout",
|
|
490
512
|
"js-cookie"
|
|
491
513
|
],
|
|
514
|
+
"modals": [
|
|
515
|
+
"my-layout",
|
|
516
|
+
"jquery",
|
|
517
|
+
"micromodal",
|
|
518
|
+
"js-cookie",
|
|
519
|
+
"body-scroll-lock"
|
|
520
|
+
],
|
|
492
521
|
"multilink": [
|
|
493
522
|
"my-layout",
|
|
494
523
|
"jquery",
|
|
@@ -569,7 +598,8 @@
|
|
|
569
598
|
"splide",
|
|
570
599
|
"vanilla-lazyload",
|
|
571
600
|
"splide-grid",
|
|
572
|
-
"fslightbox"
|
|
601
|
+
"fslightbox",
|
|
602
|
+
"cut-list"
|
|
573
603
|
],
|
|
574
604
|
"seo-filters": [
|
|
575
605
|
"my-layout"
|
package/dist/server-http.js
CHANGED
|
@@ -7,7 +7,6 @@ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
|
7
7
|
import { createServer } from 'http';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { dirname } from 'path';
|
|
10
|
-
import crypto from 'crypto';
|
|
11
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
11
|
const __dirname = dirname(__filename);
|
|
13
12
|
// Импортируем класс WidgetServer
|
|
@@ -58,7 +57,7 @@ const httpServer = createServer(async (req, res) => {
|
|
|
58
57
|
res.end(JSON.stringify({
|
|
59
58
|
status: 'ok',
|
|
60
59
|
service: 'InSales Widgets MCP Server',
|
|
61
|
-
version: '2.4.
|
|
60
|
+
version: '2.4.7',
|
|
62
61
|
transport: 'SSE',
|
|
63
62
|
endpoints: {
|
|
64
63
|
sse: '/sse',
|
|
@@ -72,23 +71,22 @@ const httpServer = createServer(async (req, res) => {
|
|
|
72
71
|
if (req.url === '/sse' && req.method === 'GET') {
|
|
73
72
|
console.log('📡 New SSE connection established');
|
|
74
73
|
try {
|
|
75
|
-
// Генерируем уникальный sessionId
|
|
76
|
-
const sessionId = crypto.randomUUID();
|
|
77
74
|
// Создаем новый MCP сервер для этого соединения
|
|
78
75
|
const widgetServer = new WidgetServer();
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
// SSEServerTransport автоматически генерирует sessionId
|
|
77
|
+
const transport = new SSEServerTransport('/message', res);
|
|
78
|
+
// Сохраняем сессию используя sessionId от транспорта
|
|
79
|
+
activeSessions.set(transport.sessionId, { server: widgetServer, transport });
|
|
80
|
+
console.log(`📝 Session created: ${transport.sessionId} (active: ${activeSessions.size})`);
|
|
83
81
|
// Подключаем транспорт через публичный метод
|
|
84
82
|
await widgetServer.connect(transport);
|
|
85
83
|
console.log('✅ MCP server connected via SSE');
|
|
86
84
|
// Обработка закрытия соединения
|
|
87
85
|
req.on('close', () => {
|
|
88
|
-
console.log(`📡 SSE connection closed for session ${sessionId}`);
|
|
89
|
-
activeSessions.delete(sessionId);
|
|
86
|
+
console.log(`📡 SSE connection closed for session ${transport.sessionId}`);
|
|
87
|
+
activeSessions.delete(transport.sessionId);
|
|
90
88
|
transport.close();
|
|
91
|
-
console.log(`📝 Session deleted: ${sessionId} (active: ${activeSessions.size})`);
|
|
89
|
+
console.log(`📝 Session deleted: ${transport.sessionId} (active: ${activeSessions.size})`);
|
|
92
90
|
});
|
|
93
91
|
}
|
|
94
92
|
catch (error) {
|
|
@@ -99,9 +97,8 @@ const httpServer = createServer(async (req, res) => {
|
|
|
99
97
|
return;
|
|
100
98
|
}
|
|
101
99
|
// Message endpoint для отправки сообщений
|
|
102
|
-
// Проверяем, что URL начинается с /message (может быть /message?sessionId=xxx)
|
|
103
100
|
if (req.url?.startsWith('/message') && req.method === 'POST') {
|
|
104
|
-
// Извлекаем sessionId из
|
|
101
|
+
// Извлекаем sessionId из query параметров
|
|
105
102
|
const urlObj = new URL(req.url, `http://${req.headers.host}`);
|
|
106
103
|
const sessionId = urlObj.searchParams.get('sessionId');
|
|
107
104
|
if (!sessionId) {
|
|
@@ -116,36 +113,15 @@ const httpServer = createServer(async (req, res) => {
|
|
|
116
113
|
return;
|
|
117
114
|
}
|
|
118
115
|
try {
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
if (typeof session.transport.handlePostMessage === 'function') {
|
|
122
|
-
await session.transport.handlePostMessage(req, res);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// Fallback: читаем тело и отправляем ответ вручную
|
|
126
|
-
let body = '';
|
|
127
|
-
req.on('data', (chunk) => {
|
|
128
|
-
body += chunk.toString();
|
|
129
|
-
});
|
|
130
|
-
req.on('end', async () => {
|
|
131
|
-
try {
|
|
132
|
-
const message = JSON.parse(body);
|
|
133
|
-
console.log(`📥 Received POST message:`, message.method || 'unknown');
|
|
134
|
-
// Просто подтверждаем получение
|
|
135
|
-
res.writeHead(202, { 'Content-Type': 'application/json' });
|
|
136
|
-
res.end(JSON.stringify({ status: 'accepted' }));
|
|
137
|
-
}
|
|
138
|
-
catch (error) {
|
|
139
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
140
|
-
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
}
|
|
116
|
+
// Используем handlePostMessage из SSEServerTransport
|
|
117
|
+
await session.transport.handlePostMessage(req, res);
|
|
144
118
|
}
|
|
145
119
|
catch (error) {
|
|
146
|
-
console.error('❌ Error handling POST:', error);
|
|
147
|
-
res.
|
|
148
|
-
|
|
120
|
+
console.error('❌ Error handling POST message:', error);
|
|
121
|
+
if (!res.headersSent) {
|
|
122
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
123
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
124
|
+
}
|
|
149
125
|
}
|
|
150
126
|
return;
|
|
151
127
|
}
|
package/dist/server.js
CHANGED
|
@@ -16,6 +16,7 @@ import liquidVariables from './data/references/liquid-variables.json' with { typ
|
|
|
16
16
|
import liquidFilters from './data/references/liquid-filters.json' with { type: 'json' };
|
|
17
17
|
import commonjsReference from './data/references/commonjs-reference.json' with { type: 'json' };
|
|
18
18
|
import collectionsMenuPatterns from './data/references/collections-menu-patterns.json' with { type: 'json' };
|
|
19
|
+
import librariesApiReference from './data/references/libraries-api-reference.json' with { type: 'json' };
|
|
19
20
|
// Импорт модулей
|
|
20
21
|
import { generateWidgetFiles } from './generators/index.js';
|
|
21
22
|
import * as tools from './tools/index.js';
|
|
@@ -25,7 +26,7 @@ export class WidgetServer {
|
|
|
25
26
|
constructor() {
|
|
26
27
|
this.server = new Server({
|
|
27
28
|
name: 'insales-widgets',
|
|
28
|
-
version: '2.4.
|
|
29
|
+
version: '2.4.9',
|
|
29
30
|
}, {
|
|
30
31
|
capabilities: {
|
|
31
32
|
tools: {},
|
|
@@ -216,6 +217,27 @@ export class WidgetServer {
|
|
|
216
217
|
},
|
|
217
218
|
},
|
|
218
219
|
},
|
|
220
|
+
{
|
|
221
|
+
name: 'get_libraries_api',
|
|
222
|
+
description: 'Получить подробную API документацию библиотек, доступных в виджетах InSales. Включает опции, методы, примеры кода, best practices. Доступны: InsalesCutList (cut-list) - jQuery плагин для сворачивания списков, и другие библиотеки.',
|
|
223
|
+
inputSchema: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: {
|
|
226
|
+
library: {
|
|
227
|
+
type: 'string',
|
|
228
|
+
description: 'Handle или название библиотеки для получения полной API документации (например: "cut-list", "InsalesCutList")',
|
|
229
|
+
},
|
|
230
|
+
search: {
|
|
231
|
+
type: 'string',
|
|
232
|
+
description: 'Поиск по опциям, методам, примерам библиотек',
|
|
233
|
+
},
|
|
234
|
+
category: {
|
|
235
|
+
type: 'string',
|
|
236
|
+
description: 'Фильтр по категории виджетов (headers, navigation, и т.д.)',
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
219
241
|
],
|
|
220
242
|
}));
|
|
221
243
|
// Список ресурсов
|
|
@@ -281,6 +303,12 @@ export class WidgetServer {
|
|
|
281
303
|
mimeType: 'text/markdown',
|
|
282
304
|
description: 'КРИТИЧЕСКИ ВАЖНО: Системная обёртка виджетов, контекст выполнения, data.blocks, запрещённые практики',
|
|
283
305
|
},
|
|
306
|
+
{
|
|
307
|
+
uri: 'insales://libraries-api',
|
|
308
|
+
name: 'API библиотек',
|
|
309
|
+
mimeType: 'application/json',
|
|
310
|
+
description: 'Подробная API документация библиотек: InsalesCutList и другие',
|
|
311
|
+
},
|
|
284
312
|
],
|
|
285
313
|
}));
|
|
286
314
|
// Чтение ресурсов
|
|
@@ -391,6 +419,16 @@ export class WidgetServer {
|
|
|
391
419
|
],
|
|
392
420
|
};
|
|
393
421
|
}
|
|
422
|
+
case 'insales://libraries-api':
|
|
423
|
+
return {
|
|
424
|
+
contents: [
|
|
425
|
+
{
|
|
426
|
+
uri,
|
|
427
|
+
mimeType: 'application/json',
|
|
428
|
+
text: JSON.stringify(librariesApiReference, null, 2),
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
};
|
|
394
432
|
default:
|
|
395
433
|
throw new Error(`Unknown resource: ${uri}`);
|
|
396
434
|
}
|
|
@@ -474,6 +512,15 @@ export class WidgetServer {
|
|
|
474
512
|
},
|
|
475
513
|
],
|
|
476
514
|
};
|
|
515
|
+
case 'get_libraries_api':
|
|
516
|
+
return {
|
|
517
|
+
content: [
|
|
518
|
+
{
|
|
519
|
+
type: 'text',
|
|
520
|
+
text: JSON.stringify(tools.getLibrariesAPI(args || {}), null, 2),
|
|
521
|
+
},
|
|
522
|
+
],
|
|
523
|
+
};
|
|
477
524
|
default:
|
|
478
525
|
throw new Error(`Unknown tool: ${name}`);
|
|
479
526
|
}
|