@maxisoft/instantcms-mcp 1.2.3

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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/__tests__/artifact-tool.test.js +196 -0
  4. package/dist/__tests__/db-tool.test.js +152 -0
  5. package/dist/__tests__/define-tool.test.js +106 -0
  6. package/dist/__tests__/find-tool.test.js +185 -0
  7. package/dist/__tests__/get-component-api.test.js +144 -0
  8. package/dist/__tests__/hardening.test.js +73 -0
  9. package/dist/__tests__/hooks-tool.test.js +173 -0
  10. package/dist/__tests__/mcp-integration-extra.test.js +166 -0
  11. package/dist/__tests__/mcp-integration.test.js +53 -0
  12. package/dist/__tests__/pagination.test.js +114 -0
  13. package/dist/__tests__/performance-baseline.test.js +56 -0
  14. package/dist/__tests__/project-patch.test.js +144 -0
  15. package/dist/__tests__/project-source.test.js +44 -0
  16. package/dist/__tests__/project-workflows-extra.test.js +165 -0
  17. package/dist/__tests__/project-workflows.test.js +51 -0
  18. package/dist/__tests__/scaffold-addon-roundtrip.test.js +287 -0
  19. package/dist/__tests__/serialization.test.js +170 -0
  20. package/dist/__tests__/source-knowledge-parsers.test.js +42 -0
  21. package/dist/__tests__/template-development.test.js +78 -0
  22. package/dist/__tests__/template-productivity.test.js +87 -0
  23. package/dist/__tests__/tools.test.js +2143 -0
  24. package/dist/data/components.js +2818 -0
  25. package/dist/data/controllers-map.js +7571 -0
  26. package/dist/data/core-api.js +9356 -0
  27. package/dist/data/database-schema.js +4555 -0
  28. package/dist/data/events-map.js +1339 -0
  29. package/dist/data/fields-map.js +3692 -0
  30. package/dist/data/hooks.js +2257 -0
  31. package/dist/data/js-api.js +123 -0
  32. package/dist/data/libs-api.js +264 -0
  33. package/dist/data/routes-map.js +203 -0
  34. package/dist/data/schemas-validation.js +255 -0
  35. package/dist/data/schemas.js +1404 -0
  36. package/dist/data/traits-map.js +1004 -0
  37. package/dist/data/version-profiles.js +41 -0
  38. package/dist/data/widgets-map.js +131 -0
  39. package/dist/data/wysiwyg-map.js +486 -0
  40. package/dist/generated/components-source.js +14748 -0
  41. package/dist/generated/hooks-source.js +3399 -0
  42. package/dist/generated/knowledge-meta.js +101 -0
  43. package/dist/index.js +13 -0
  44. package/dist/registry/database-tools.js +112 -0
  45. package/dist/registry/extension-tools.js +473 -0
  46. package/dist/registry/generator-tools.js +506 -0
  47. package/dist/registry/knowledge-tools.js +441 -0
  48. package/dist/registry/language-tools.js +99 -0
  49. package/dist/registry/meta-tools.js +152 -0
  50. package/dist/registry/project-tools.js +48 -0
  51. package/dist/registry/resources.js +98 -0
  52. package/dist/registry/source-tools.js +211 -0
  53. package/dist/registry/template-development-tools.js +79 -0
  54. package/dist/server.js +32 -0
  55. package/dist/tools/addon-tool.js +1437 -0
  56. package/dist/tools/admin-partial-tool.js +498 -0
  57. package/dist/tools/api-tool.js +294 -0
  58. package/dist/tools/artifact-tool.js +95 -0
  59. package/dist/tools/cache-tool.js +360 -0
  60. package/dist/tools/component-tool.js +415 -0
  61. package/dist/tools/controllers-tool.js +125 -0
  62. package/dist/tools/cron-tool.js +197 -0
  63. package/dist/tools/crud-tool.js +659 -0
  64. package/dist/tools/db-tool.js +198 -0
  65. package/dist/tools/email-tool.js +222 -0
  66. package/dist/tools/external-api-tool.js +596 -0
  67. package/dist/tools/filter-tool.js +341 -0
  68. package/dist/tools/form-tool.js +275 -0
  69. package/dist/tools/grid-tool.js +189 -0
  70. package/dist/tools/hooks-tool.js +104 -0
  71. package/dist/tools/import-export-tool.js +548 -0
  72. package/dist/tools/lang-tool.js +251 -0
  73. package/dist/tools/layout-override-tool.js +125 -0
  74. package/dist/tools/layout-tool.js +548 -0
  75. package/dist/tools/maria-tool.js +127 -0
  76. package/dist/tools/mariadb.js +201 -0
  77. package/dist/tools/migration-tool.js +329 -0
  78. package/dist/tools/oauth-tool.js +520 -0
  79. package/dist/tools/parser/components-parser.js +76 -0
  80. package/dist/tools/parser/controllers-parser.js +313 -0
  81. package/dist/tools/parser/core-parser.js +294 -0
  82. package/dist/tools/parser/coverage-generator.js +424 -0
  83. package/dist/tools/parser/events-parser.js +127 -0
  84. package/dist/tools/parser/fields-parser.js +382 -0
  85. package/dist/tools/parser/hooks-parser.js +106 -0
  86. package/dist/tools/parser/sql-parser.js +197 -0
  87. package/dist/tools/parser/traits-parser.js +161 -0
  88. package/dist/tools/parser/widgets-parser.js +150 -0
  89. package/dist/tools/permission-tool.js +348 -0
  90. package/dist/tools/project-patch-tool.js +73 -0
  91. package/dist/tools/project-source-tool.js +188 -0
  92. package/dist/tools/project-workflow-tool.js +186 -0
  93. package/dist/tools/requirement-tool.js +212 -0
  94. package/dist/tools/scaffold-tool.js +815 -0
  95. package/dist/tools/seo-tool.js +412 -0
  96. package/dist/tools/source-tool.js +155 -0
  97. package/dist/tools/template-development-tool.js +271 -0
  98. package/dist/tools/template-overrides-tool.js +294 -0
  99. package/dist/tools/template-productivity-tool.js +319 -0
  100. package/dist/tools/template-tool.js +665 -0
  101. package/dist/tools/test-tool.js +183 -0
  102. package/dist/tools/webhook-tool.js +427 -0
  103. package/dist/tools/widget-tool.js +331 -0
  104. package/dist/tools/wysiwyg-tool.js +137 -0
  105. package/dist/types/scaffold.js +68 -0
  106. package/dist/utils/define-tool.js +37 -0
  107. package/dist/utils/find-tool.js +97 -0
  108. package/dist/utils/mcp-result.js +18 -0
  109. package/dist/utils/pagination.js +27 -0
  110. package/dist/utils/serialization.js +27 -0
  111. package/package.json +94 -0
@@ -0,0 +1,548 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Import/Export scaffolding tool for InstantCMS
4
+ * Generates import/export classes for CSV, Excel, JSON, and XML formats
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.importExportToolSchema = exports.FieldTypeEnum = void 0;
8
+ exports.scaffoldImportExport = scaffoldImportExport;
9
+ const zod_1 = require("zod");
10
+ const scaffold_1 = require("../types/scaffold");
11
+ /**
12
+ * Available field types for import/export
13
+ */
14
+ exports.FieldTypeEnum = zod_1.z.enum([
15
+ 'string',
16
+ 'text',
17
+ 'number',
18
+ 'date',
19
+ 'datetime',
20
+ 'bool',
21
+ 'select',
22
+ 'image',
23
+ 'file',
24
+ ]);
25
+ /**
26
+ * Normalizes field with label defaults
27
+ */
28
+ function normalizeField(f) {
29
+ return {
30
+ field: f.field,
31
+ type: f.type,
32
+ label: f.label || f.field,
33
+ required: f.required ?? false,
34
+ default: f.default,
35
+ options: f.options,
36
+ };
37
+ }
38
+ /**
39
+ * Generates import class
40
+ */
41
+ function generateImportClass(name, Name, fields, options) {
42
+ const fieldParsing = fields
43
+ .map(f => {
44
+ switch (f.type) {
45
+ case 'number':
46
+ return ` '${f.field}' => isset($row['${f.label}']) ? floatval($row['${f.label}']) : null,`;
47
+ case 'bool':
48
+ return ` '${f.field}' => isset($row['${f.label}']) ? (in_array(strtolower($row['${f.label}']), ['1', 'yes', 'true', 'да'], true) ? 1 : 0) : 0,`;
49
+ case 'date':
50
+ return ` '${f.field}' => isset($row['${f.label}']) ? date('Y-m-d', strtotime($row['${f.label}'])) : null,`;
51
+ case 'datetime':
52
+ return ` '${f.field}' => isset($row['${f.label}']) ? date('Y-m-d H:i:s', strtotime($row['${f.label}'])) : null,`;
53
+ case 'select':
54
+ return ` '${f.field}' => \\$row['${f.label}'] ?? null,`;
55
+ default:
56
+ return ` '${f.field}' => \\$row['${f.label}'] ?? null,`;
57
+ }
58
+ })
59
+ .join('\n');
60
+ const validation = fields
61
+ .filter(f => f.required)
62
+ .map(f => {
63
+ return ` if (empty(\\$item['${f.field}'])) {
64
+ throw new Exception('Поле ${f.label || f.field} обязательно для заполнения');
65
+ }`;
66
+ })
67
+ .join('\n');
68
+ return `<?php
69
+ // InstantCMS 2. ${name}/import.php
70
+
71
+ class ${Name}Import {
72
+ private $model;
73
+ private $options = [];
74
+ private $stats = [
75
+ 'total' => 0,
76
+ 'imported' => 0,
77
+ 'updated' => 0,
78
+ 'skipped' => 0,
79
+ 'errors' => 0,
80
+ ];
81
+
82
+ public function __construct($options = []) {
83
+ $this->model = cmsModel::getInstance();
84
+ $this->options = array_merge([
85
+ 'batch_size' => ${options.batch_size},
86
+ 'skip_header' => ${options.skip_header},
87
+ 'update_existing' => ${options.update_existing},
88
+ ], $options);
89
+ }
90
+
91
+ public function importFromArray($data) {
92
+ $this->stats['total'] = count($data);
93
+
94
+ if ($this->options['skip_header'] && !empty($data[0])) {
95
+ array_shift($data);
96
+ }
97
+
98
+ $batches = array_chunk($data, $this->options['batch_size']);
99
+
100
+ foreach ($batches as $batch) {
101
+ $this->processBatch($batch);
102
+ }
103
+
104
+ return $this->stats;
105
+ }
106
+
107
+ private function processBatch($rows) {
108
+ foreach ($rows as $row) {
109
+ try {
110
+ $this->importRow($row);
111
+ } catch (Exception $e) {
112
+ $this->stats['errors']++;
113
+ if ($this->options['stop_on_error'] ?? false) {
114
+ throw $e;
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ private function importRow($row) {
121
+ $item = [
122
+ ${fieldParsing}
123
+ ];
124
+
125
+ ${validation}
126
+
127
+ if ($this->options['update_existing'] && !empty($item['slug'])) {
128
+ $existing = $this->model->getItem('${name}', ['slug' => $item['slug']]);
129
+ if ($existing) {
130
+ $this->model->update('${name}', $existing['id'], $item);
131
+ $this->stats['updated']++;
132
+ return;
133
+ }
134
+ }
135
+
136
+ $id = $this->model->insert('${name}', $item);
137
+
138
+ if ($id) {
139
+ $this->stats['imported']++;
140
+ } else {
141
+ $this->stats['skipped']++;
142
+ }
143
+ }
144
+
145
+ public function getStats() {
146
+ return $this->stats;
147
+ }
148
+
149
+ public function validateCsv($content) {
150
+ $lines = explode("\\n", trim($content));
151
+ if (empty($lines)) {
152
+ throw new Exception('Пустой файл');
153
+ }
154
+
155
+ $delimiter = $this->detectDelimiter($content);
156
+ $rows = [];
157
+
158
+ foreach ($lines as $line) {
159
+ $rows[] = str_getcsv($line, $delimiter);
160
+ }
161
+
162
+ return $rows;
163
+ }
164
+
165
+ private function detectDelimiter($content) {
166
+ $firstLine = explode("\\n", $content)[0];
167
+ $commas = substr_count($firstLine, ',');
168
+ $semicolons = substr_count($firstLine, ';');
169
+ $tabs = substr_count($firstLine, "\\t");
170
+
171
+ if ($tabs > $commas && $tabs > $semicolons) {
172
+ return "\\t";
173
+ }
174
+ if ($semicolons > $commas) {
175
+ return ';';
176
+ }
177
+ return ',';
178
+ }
179
+ }`;
180
+ }
181
+ /**
182
+ * Generates export class
183
+ */
184
+ function generateExportClass(name, Name, fields, _options) {
185
+ const fieldHeaders = fields.map(f => `'${f.label || f.field}'`).join(', ');
186
+ const fieldMapping = fields
187
+ .map(f => {
188
+ return ` '${f.field}' => \\$item['${f.field}'],`;
189
+ })
190
+ .join('\n');
191
+ return `<?php
192
+ // InstantCMS 2. ${name}/export.php
193
+
194
+ class ${Name}Export {
195
+ private $model;
196
+ private $options = [];
197
+
198
+ public function __construct($options = []) {
199
+ $this->model = cmsModel::getInstance();
200
+ $this->options = $options;
201
+ }
202
+
203
+ public function exportToArray($filters = []) {
204
+ $items = $this->getItems($filters);
205
+ $result = [];
206
+
207
+ $result[] = [${fieldHeaders}];
208
+
209
+ foreach ($items as $item) {
210
+ $result[] = [
211
+ ${fieldMapping}
212
+ ];
213
+ }
214
+
215
+ return $result;
216
+ }
217
+
218
+ public function exportToCsv($filters = []) {
219
+ $data = $this->exportToArray($filters);
220
+
221
+ if (empty($data)) {
222
+ return '';
223
+ }
224
+
225
+ $output = fopen('php://temp', 'r+');
226
+
227
+ foreach ($data as $row) {
228
+ fputcsv($output, $row);
229
+ }
230
+
231
+ rewind($output);
232
+ $csv = stream_get_contents($output);
233
+ fclose($output);
234
+
235
+ return $csv;
236
+ }
237
+
238
+ public function exportToJson($filters = []) {
239
+ $items = $this->getItems($filters);
240
+ return json_encode($items, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
241
+ }
242
+
243
+ public function exportToXml($filters = []) {
244
+ $items = $this->getItems($filters);
245
+
246
+ $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><${name}_list></${name}_list>');
247
+
248
+ foreach ($items as $item) {
249
+ $itemXml = $xml->addChild('item');
250
+ foreach ($item as $key => $value) {
251
+ if (is_array($value) || is_object($value)) {
252
+ continue;
253
+ }
254
+ $itemXml->addChild($key, htmlspecialchars($value));
255
+ }
256
+ }
257
+
258
+ return $xml->asXML();
259
+ }
260
+
261
+ private function getItems($filters = []) {
262
+ $query = $this->model->get('${name}', null, function ($model, $item) {
263
+ return $item;
264
+ });
265
+
266
+ if (!empty($filters)) {
267
+ foreach ($filters as $key => $value) {
268
+ if ($value !== null && $value !== '') {
269
+ $query->where($key, '=', $value);
270
+ }
271
+ }
272
+ }
273
+
274
+ $page = $this->options['page'] ?? 1;
275
+ $per_page = $this->options['per_page'] ?? 100;
276
+
277
+ return $query->orderBy('id', 'DESC')->limit($page, $per_page)->fetchAll();
278
+ }
279
+
280
+ public function getTotalCount($filters = []) {
281
+ return $this->model->getCount('${name}', function ($model) use ($filters) {
282
+ if (!empty($filters)) {
283
+ foreach ($filters as $key => $value) {
284
+ if ($value !== null && $value !== '') {
285
+ $model->where($key, '=', $value);
286
+ }
287
+ }
288
+ }
289
+ });
290
+ }
291
+ }`;
292
+ }
293
+ /**
294
+ * Generates import form class
295
+ */
296
+ function generateImportForm(name, Name, _fields, options) {
297
+ return `<?php
298
+ // InstantCMS 2. ${name}/import.form.php
299
+
300
+ class ${Name}ImportForm {
301
+ public function __construct($form) {
302
+ $form->addField('import_file', new fieldFile('Файл для импорта', [
303
+ 'extensions' => ${options.use_xlsx ? "['csv', 'xlsx', 'xls']" : "['csv']"},
304
+ 'max_size' => 10 * 1024 * 1024,
305
+ 'required' => true,
306
+ ]));
307
+
308
+ $form->addField('update_existing', new fieldCheckbox('Обновлять существующие записи', [
309
+ 'is_checked' => ${options.update_existing},
310
+ ]));
311
+
312
+ $form->addField('skip_header', new fieldCheckbox('Пропустить первую строку (заголовки)', [
313
+ 'is_checked' => ${options.skip_header},
314
+ ]));
315
+
316
+ $form->addField('encoding', new fieldList('Кодировка файла', [
317
+ 'options' => [
318
+ 'utf-8' => 'UTF-8',
319
+ 'windows-1251' => 'Windows-1251',
320
+ 'koi8-r' => 'KOI8-R',
321
+ ],
322
+ 'default' => 'utf-8',
323
+ ]));
324
+ }
325
+
326
+ public static function create($form) {
327
+ return new self($form);
328
+ }
329
+ }`;
330
+ }
331
+ /**
332
+ * Generates API import/export controller
333
+ */
334
+ function generateApiImport(name, Name, _fields, options) {
335
+ return `<?php
336
+ // InstantCMS 2. ${name}/api.import.php
337
+
338
+ class ${Name}ApiImport {
339
+ public function __construct($controller) {
340
+ $this->controller = $controller;
341
+ }
342
+
343
+ public function actionImport() {
344
+ $request = $this->controller->request;
345
+
346
+ $data = $request->get('data');
347
+ if (empty($data)) {
348
+ $this->controller->halt(400, json_encode(['error' => 'No data provided']));
349
+ }
350
+
351
+ if (is_string($data)) {
352
+ $data = json_decode($data, true);
353
+ }
354
+
355
+ if (!is_array($data)) {
356
+ $this->controller->halt(400, json_encode(['error' => 'Invalid data format']));
357
+ }
358
+
359
+ $import = new ${Name}Import([
360
+ 'update_existing' => $request->get('update_existing', ${options.update_existing}),
361
+ ]);
362
+
363
+ try {
364
+ $stats = $import->importFromArray($data);
365
+ $this->controller->halt(200, json_encode([
366
+ 'success' => true,
367
+ 'stats' => $stats,
368
+ ]));
369
+ } catch (Exception $e) {
370
+ $this->controller->halt(500, json_encode([
371
+ 'error' => $e->getMessage(),
372
+ ]));
373
+ }
374
+ }
375
+
376
+ public function actionExport() {
377
+ $request = $this->controller->request;
378
+ $format = $request->get('format', 'json');
379
+
380
+ $filters = [];
381
+ $filters['is_published'] = $request->get('published', null);
382
+
383
+ $export = new ${Name}Export([
384
+ 'page' => $request->get('page', 1),
385
+ 'per_page' => $request->get('per_page', 100),
386
+ ]);
387
+
388
+ switch ($format) {
389
+ case 'csv':
390
+ $content = $export->exportToCsv($filters);
391
+ $this->controller->halt(200, $content);
392
+ break;
393
+ case 'xml':
394
+ $content = $export->exportToXml($filters);
395
+ $this->controller->halt(200, $content);
396
+ break;
397
+ default:
398
+ $content = $export->exportToJson($filters);
399
+ $this->controller->halt(200, $content);
400
+ }
401
+ }
402
+
403
+ public function actionValidate() {
404
+ $request = $this->controller->request;
405
+ $data = $request->get('data');
406
+
407
+ if (empty($data)) {
408
+ $this->controller->halt(400, json_encode(['error' => 'No data provided']));
409
+ }
410
+
411
+ if (is_string($data)) {
412
+ $data = json_decode($data, true);
413
+ }
414
+
415
+ $errors = [];
416
+ $rowNum = 0;
417
+
418
+ foreach ($data as $row) {
419
+ $rowNum++;
420
+ foreach ($row as $key => $value) {
421
+ if (empty($value) && in_array($key, ['title', 'name'])) {
422
+ $errors[] = "Row {$rowNum}: Field '{$key}' is required";
423
+ }
424
+ }
425
+ }
426
+
427
+ if (empty($errors)) {
428
+ $this->controller->halt(200, json_encode([
429
+ 'valid' => true,
430
+ 'rows' => count($data),
431
+ ]));
432
+ } else {
433
+ $this->controller->halt(400, json_encode([
434
+ 'valid' => false,
435
+ 'errors' => $errors,
436
+ ]));
437
+ }
438
+ }
439
+ }`;
440
+ }
441
+ /**
442
+ * Generates a complete import/export system for an InstantCMS addon
443
+ *
444
+ * @param opts - Configuration options for import/export
445
+ * @returns Object containing generated files and metadata
446
+ *
447
+ * @example
448
+ * ```typescript
449
+ * const result = scaffoldImportExport({
450
+ * addon_name: 'products',
451
+ * fields: [
452
+ * { field: 'title', type: 'string', label: 'Название', required: true },
453
+ * { field: 'price', type: 'number', label: 'Цена' }
454
+ * ],
455
+ * options: { use_csv: true, use_json: true, batch_size: 100 }
456
+ * });
457
+ * ```
458
+ */
459
+ function scaffoldImportExport(opts) {
460
+ const { lowercase, UpperCamelCase } = (0, scaffold_1.normalizeAddonName)(opts.addon_name);
461
+ const files = {};
462
+ const fields = opts.fields.map(normalizeField);
463
+ const options = {
464
+ use_csv: opts.options?.use_csv ?? true,
465
+ use_xlsx: opts.options?.use_xlsx ?? true,
466
+ use_json: opts.options?.use_json ?? true,
467
+ use_xml: opts.options?.use_xml ?? false,
468
+ batch_size: opts.options?.batch_size ?? 100,
469
+ skip_header: opts.options?.skip_header ?? true,
470
+ update_existing: opts.options?.update_existing ?? true,
471
+ };
472
+ files[`${lowercase}/import.php`] = generateImportClass(lowercase, UpperCamelCase, fields, options);
473
+ files[`${lowercase}/export.php`] = generateExportClass(lowercase, UpperCamelCase, fields, options);
474
+ if (options.use_csv || options.use_xlsx) {
475
+ files[`${lowercase}/import.form.php`] = generateImportForm(lowercase, UpperCamelCase, fields, options);
476
+ }
477
+ if (options.use_json) {
478
+ files[`${lowercase}/api.import.php`] = generateApiImport(lowercase, UpperCamelCase, fields, options);
479
+ }
480
+ return {
481
+ addon_name: lowercase,
482
+ files,
483
+ fields_count: fields.length,
484
+ options,
485
+ };
486
+ }
487
+ exports.importExportToolSchema = {
488
+ name: 'scaffold_import_export',
489
+ description: 'Генерация системы импорта/экспорта данных для InstantCMS',
490
+ inputSchema: {
491
+ type: 'object',
492
+ properties: {
493
+ addon_name: { type: 'string', description: 'Имя дополнения' },
494
+ fields: {
495
+ type: 'array',
496
+ items: {
497
+ type: 'object',
498
+ properties: {
499
+ field: { type: 'string', description: 'Имя поля' },
500
+ type: {
501
+ type: 'string',
502
+ enum: [
503
+ 'string',
504
+ 'text',
505
+ 'number',
506
+ 'date',
507
+ 'datetime',
508
+ 'bool',
509
+ 'select',
510
+ 'image',
511
+ 'file',
512
+ ],
513
+ description: 'Тип поля',
514
+ },
515
+ label: { type: 'string', description: 'Название в CSV/заголовке' },
516
+ required: { type: 'boolean', description: 'Обязательное' },
517
+ default: { type: 'string', description: 'Значение по умолчанию' },
518
+ },
519
+ },
520
+ description: 'Поля для импорта/экспорта',
521
+ },
522
+ options: {
523
+ type: 'object',
524
+ properties: {
525
+ use_csv: { type: 'boolean', description: 'Поддержка CSV' },
526
+ use_xlsx: { type: 'boolean', description: 'Поддержка Excel' },
527
+ use_json: { type: 'boolean', description: 'Поддержка JSON API' },
528
+ use_xml: { type: 'boolean', description: 'Поддержка XML' },
529
+ batch_size: { type: 'number', description: 'Размер батча' },
530
+ skip_header: { type: 'boolean', description: 'Пропускать заголовки' },
531
+ update_existing: { type: 'boolean', description: 'Обновлять существующие' },
532
+ },
533
+ },
534
+ },
535
+ required: ['addon_name'],
536
+ },
537
+ inputExamples: [
538
+ {
539
+ addon_name: 'products',
540
+ fields: [
541
+ { field: 'title', type: 'string', label: 'Название', required: true },
542
+ { field: 'price', type: 'number', label: 'Цена' },
543
+ { field: 'description', type: 'text', label: 'Описание' },
544
+ ],
545
+ options: { use_csv: true, use_json: true },
546
+ },
547
+ ],
548
+ };