@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,596 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview External API client scaffolding tool for InstantCMS
4
+ * Generates API clients with authentication, rate limiting, and caching support
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.externalApiToolSchema = exports.AuthTypeEnum = exports.HttpMethodEnum = void 0;
8
+ exports.scaffoldExternalApi = scaffoldExternalApi;
9
+ const zod_1 = require("zod");
10
+ const scaffold_1 = require("../types/scaffold");
11
+ /**
12
+ * HTTP methods for API endpoints
13
+ */
14
+ exports.HttpMethodEnum = zod_1.z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']);
15
+ /**
16
+ * Authentication types
17
+ */
18
+ exports.AuthTypeEnum = zod_1.z.enum(['api_key', 'bearer', 'basic', 'oauth2']);
19
+ /**
20
+ * Generates API client class
21
+ */
22
+ function generateApiClient(name, Name, baseUrl, endpoints, options) {
23
+ const endpointMethods = endpoints
24
+ .map(e => {
25
+ const methodName = e.method.toLowerCase();
26
+ const pathPart = e.path.replace(/^\//, '').replace(/\//g, '_').replace(/[{}]/g, '');
27
+ const funcName = `${methodName}_${pathPart}`;
28
+ return ` public function ${funcName}($params = []) {
29
+ return $this->request('${e.method}', '${e.path}', $params);
30
+ }`;
31
+ })
32
+ .join('\n\n');
33
+ return `<?php
34
+ // InstantCMS 2. ${name}/api/client.php
35
+
36
+ class ${Name}ApiClient {
37
+ private $base_url = '${baseUrl}';
38
+ private $auth = null;
39
+ private $timeout = ${options.timeout};
40
+ private $rate_limiter = null;
41
+ private $cache = null;
42
+
43
+ public function __construct() {
44
+ $this->auth = new ${Name}ApiAuth($this);
45
+
46
+ if (${options.use_rate_limit}) {
47
+ $this->rate_limiter = new ${Name}ApiRateLimiter();
48
+ }
49
+
50
+ if (${options.use_cache}) {
51
+ $this->cache = new ${Name}ApiCache();
52
+ }
53
+ }
54
+
55
+ public function setBaseUrl($url) {
56
+ $this->base_url = $url;
57
+ return $this;
58
+ }
59
+
60
+ public function setTimeout($timeout) {
61
+ $this->timeout = $timeout;
62
+ return $this;
63
+ }
64
+
65
+ public function request($method, $path, $params = [], $data = null) {
66
+ $method = strtoupper($method);
67
+
68
+ if ($this->rate_limiter && !$this->rate_limiter->canMakeRequest()) {
69
+ throw new ${Name}ApiRateLimitException('Rate limit exceeded');
70
+ }
71
+
72
+ $url = rtrim($this->base_url, '/') . '/' . ltrim($path, '/');
73
+
74
+ $request = new ${Name}ApiRequest();
75
+ $request->setMethod($method);
76
+ $request->setUrl($url);
77
+ $request->setParams($params);
78
+ $request->setTimeout($this->timeout);
79
+ $request->setHeaders($this->auth->getHeaders());
80
+
81
+ if ($data !== null) {
82
+ $request->setBody($data);
83
+ }
84
+
85
+ $result = $request->execute();
86
+
87
+ if ($this->rate_limiter) {
88
+ $this->rate_limiter->recordRequest();
89
+ }
90
+
91
+ return $result;
92
+ }
93
+
94
+ ${endpointMethods}
95
+
96
+ public function get($path, $params = []) {
97
+ return $this->request('GET', $path, $params);
98
+ }
99
+
100
+ public function post($path, $data, $params = []) {
101
+ return $this->request('POST', $path, $params, $data);
102
+ }
103
+
104
+ public function put($path, $data, $params = []) {
105
+ return $this->request('PUT', $path, $params, $data);
106
+ }
107
+
108
+ public function delete($path, $params = []) {
109
+ return $this->request('DELETE', $path, $params);
110
+ }
111
+
112
+ public function patch($path, $data, $params = []) {
113
+ return $this->request('PATCH', $path, $params, $data);
114
+ }
115
+
116
+ public static function getInstance() {
117
+ static $instance = null;
118
+ if ($instance === null) {
119
+ $instance = new self();
120
+ }
121
+ return $instance;
122
+ }
123
+ }`;
124
+ }
125
+ /**
126
+ * Generates API request class
127
+ */
128
+ function generateApiRequest(name, Name, _options) {
129
+ return `<?php
130
+ // InstantCMS 2. ${name}/api/request.php
131
+
132
+ class ${Name}ApiRequest {
133
+ private $method = 'GET';
134
+ private $url = '';
135
+ private $params = [];
136
+ private $headers = [];
137
+ private $body = null;
138
+ private $timeout = 30;
139
+
140
+ public function setMethod($method) {
141
+ $this->method = strtoupper($method);
142
+ return $this;
143
+ }
144
+
145
+ public function setUrl($url) {
146
+ $this->url = $url;
147
+ return $this;
148
+ }
149
+
150
+ public function setParams($params) {
151
+ $this->params = $params;
152
+ return $this;
153
+ }
154
+
155
+ public function setHeaders($headers) {
156
+ $this->headers = array_merge($this->headers, $headers);
157
+ return $this;
158
+ }
159
+
160
+ public function setBody($body) {
161
+ $this->body = $body;
162
+ return $this;
163
+ }
164
+
165
+ public function setTimeout($timeout) {
166
+ $this->timeout = $timeout;
167
+ return $this;
168
+ }
169
+
170
+ public function execute() {
171
+ $url = $this->url;
172
+
173
+ if (!empty($this->params) && in_array($this->method, ['GET', 'DELETE'])) {
174
+ $url .= '?' . http_build_query($this->params);
175
+ }
176
+
177
+ $ch = curl_init();
178
+
179
+ curl_setopt($ch, CURLOPT_URL, $url);
180
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
181
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
182
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method);
183
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $this->buildHeaders());
184
+
185
+ if ($this->body !== null) {
186
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($this->body));
187
+ $this->headers['Content-Type'] = 'application/json';
188
+ }
189
+
190
+ $response = curl_exec($ch);
191
+ $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
192
+ $error = curl_error($ch);
193
+
194
+ curl_close($ch);
195
+
196
+ if ($error) {
197
+ throw new ${Name}ApiException('cURL Error: ' . $error);
198
+ }
199
+
200
+ return $this->parseResponse($response, $http_code);
201
+ }
202
+
203
+ private function buildHeaders() {
204
+ $headers = [];
205
+ foreach ($this->headers as $key => $value) {
206
+ $headers[] = "$key: $value";
207
+ }
208
+ return $headers;
209
+ }
210
+
211
+ private function parseResponse($response, $http_code) {
212
+ $data = json_decode($response, true);
213
+
214
+ if ($http_code >= 400) {
215
+ $error_msg = $data['message'] ?? $data['error'] ?? 'Unknown error';
216
+ throw new ${Name}ApiHttpException($error_msg, $http_code);
217
+ }
218
+
219
+ return [
220
+ 'success' => $http_code >= 200 && $http_code < 300,
221
+ 'status_code' => $http_code,
222
+ 'data' => $data,
223
+ ];
224
+ }
225
+ }
226
+
227
+ class ${Name}ApiException extends Exception {}
228
+ class ${Name}ApiHttpException extends Exception {
229
+ private $status_code;
230
+
231
+ public function __construct($message, $status_code) {
232
+ parent::__construct($message);
233
+ $this->status_code = $status_code;
234
+ }
235
+
236
+ public function getStatusCode() {
237
+ return $this->status_code;
238
+ }
239
+ }
240
+
241
+ class ${Name}ApiRateLimitException extends Exception {}`;
242
+ }
243
+ /**
244
+ * Generates API authentication class
245
+ */
246
+ function generateApiAuth(name, Name, options) {
247
+ let authImplementation = '';
248
+ switch (options.auth_type) {
249
+ case 'api_key':
250
+ authImplementation = ` public function getHeaders() {
251
+ return [
252
+ 'X-API-Key' => $this->api_key,
253
+ ];
254
+ }`;
255
+ break;
256
+ case 'basic':
257
+ authImplementation = ` public function getHeaders() {
258
+ return [
259
+ 'Authorization' => 'Basic ' . base64_encode($this->api_key . ':' . $this->api_secret),
260
+ ];
261
+ }`;
262
+ break;
263
+ case 'oauth2':
264
+ authImplementation = ` public function getHeaders() {
265
+ if ($this->access_token && $this->isTokenValid()) {
266
+ return [
267
+ 'Authorization' => 'Bearer ' . $this->access_token,
268
+ ];
269
+ }
270
+
271
+ if ($this->refresh_token) {
272
+ $this->refreshAccessToken();
273
+ }
274
+
275
+ return [];
276
+ }
277
+
278
+ private function isTokenValid() {
279
+ if (!$this->access_token || !$this->token_expires_at) {
280
+ return false;
281
+ }
282
+ return time() < $this->token_expires_at;
283
+ }`;
284
+ break;
285
+ default:
286
+ authImplementation = ` public function getHeaders() {
287
+ return [
288
+ 'Authorization' => 'Bearer ' . $this->access_token,
289
+ ];
290
+ }`;
291
+ }
292
+ return `<?php
293
+ // InstantCMS 2. ${name}/api/auth.php
294
+
295
+ class ${Name}ApiAuth {
296
+ private $client = null;
297
+ private $access_token = '';
298
+ private $refresh_token = '';
299
+ private $api_key = '';
300
+ private $api_secret = '';
301
+ private $token_expires_at = 0;
302
+ private $config = [];
303
+
304
+ public function __construct($client) {
305
+ $this->client = $client;
306
+ $this->loadConfig();
307
+ }
308
+
309
+ private function loadConfig() {
310
+ $config_path = cmsConfig::get('root_path') . '/system/config/api/${name}.php';
311
+ if (file_exists($config_path)) {
312
+ $this->config = include $config_path;
313
+ }
314
+
315
+ $this->access_token = $this->config['access_token'] ?? '';
316
+ $this->refresh_token = $this->config['refresh_token'] ?? '';
317
+ $this->api_key = $this->config['api_key'] ?? '';
318
+ $this->api_secret = $this->config['api_secret'] ?? '';
319
+ $this->token_expires_at = $this->config['token_expires_at'] ?? 0;
320
+ }
321
+
322
+ public function saveConfig() {
323
+ $config_path = cmsConfig::get('root_path') . '/system/config/api/${name}.php';
324
+ $config = [
325
+ 'access_token' => $this->access_token,
326
+ 'refresh_token' => $this->refresh_token,
327
+ 'api_key' => $this->api_key,
328
+ 'api_secret' => $this->api_secret,
329
+ 'token_expires_at' => $this->token_expires_at,
330
+ ];
331
+ file_put_contents($config_path, '<?php return ' . var_export($config, true) . ';');
332
+ }
333
+
334
+ ${authImplementation}
335
+
336
+ public function setAccessToken($token, $expires_in = null) {
337
+ $this->access_token = $token;
338
+ if ($expires_in) {
339
+ $this->token_expires_at = time() + $expires_in;
340
+ }
341
+ $this->saveConfig();
342
+ }
343
+
344
+ public function setApiKey($key) {
345
+ $this->api_key = $key;
346
+ $this->saveConfig();
347
+ }
348
+
349
+ public function setApiSecret($secret) {
350
+ $this->api_secret = $secret;
351
+ $this->saveConfig();
352
+ }
353
+
354
+ public function isAuthenticated() {
355
+ return !empty($this->access_token);
356
+ }
357
+
358
+ public function logout() {
359
+ $this->access_token = '';
360
+ $this->refresh_token = '';
361
+ $this->token_expires_at = 0;
362
+ $this->saveConfig();
363
+ }
364
+ }`;
365
+ }
366
+ /**
367
+ * Generates rate limiter class
368
+ */
369
+ function generateRateLimiter(name, Name, options) {
370
+ return `<?php
371
+ // InstantCMS 2. ${name}/api/rate_limiter.php
372
+
373
+ class ${Name}ApiRateLimiter {
374
+ private $requests = [];
375
+ private $limit = ${options.rate_limit};
376
+ private $window = 60;
377
+
378
+ public function __construct() {
379
+ $this->loadState();
380
+ }
381
+
382
+ private function loadState() {
383
+ $cache_key = '${name}_api_rate_limit';
384
+ $cached = cmsCache::getInstance()->get($cache_key);
385
+ if ($cached !== false) {
386
+ $this->requests = $cached;
387
+ }
388
+ }
389
+
390
+ private function saveState() {
391
+ $cache_key = '${name}_api_rate_limit';
392
+ cmsCache::getInstance()->set($cache_key, $this->requests, 120);
393
+ }
394
+
395
+ public function canMakeRequest() {
396
+ $this->cleanupOldRequests();
397
+ return count($this->requests) < $this->limit;
398
+ }
399
+
400
+ public function recordRequest() {
401
+ $this->requests[] = time();
402
+ $this->saveState();
403
+ }
404
+
405
+ public function getRemainingRequests() {
406
+ $this->cleanupOldRequests();
407
+ return max(0, $this->limit - count($this->requests));
408
+ }
409
+
410
+ public function getResetTime() {
411
+ if (empty($this->requests)) {
412
+ return 0;
413
+ }
414
+ $oldest = min($this->requests);
415
+ return $oldest + $this->window - time();
416
+ }
417
+
418
+ private function cleanupOldRequests() {
419
+ $cutoff = time() - $this->window;
420
+ $this->requests = array_filter($this->requests, function ($timestamp) use ($cutoff) {
421
+ return $timestamp > $cutoff;
422
+ });
423
+ }
424
+
425
+ public function reset() {
426
+ $this->requests = [];
427
+ $this->saveState();
428
+ }
429
+ }`;
430
+ }
431
+ /**
432
+ * Generates API cache class
433
+ */
434
+ function generateApiCache(name, Name, _options) {
435
+ return `<?php
436
+ // InstantCMS 2. ${name}/api/cache.php
437
+
438
+ class ${Name}ApiCache {
439
+ private $ttl = 3600;
440
+
441
+ public function __construct($ttl = null) {
442
+ if ($ttl !== null) {
443
+ $this->ttl = $ttl;
444
+ }
445
+ }
446
+
447
+ public function get($key) {
448
+ $cache_key = $this->buildKey($key);
449
+ return cmsCache::getInstance()->get($cache_key);
450
+ }
451
+
452
+ public function set($key, $value, $ttl = null) {
453
+ $cache_key = $this->buildKey($key);
454
+ $ttl = $ttl ?? $this->ttl;
455
+ return cmsCache::getInstance()->set($cache_key, $value, $ttl);
456
+ }
457
+
458
+ public function delete($key) {
459
+ $cache_key = $this->buildKey($key);
460
+ return cmsCache::getInstance()->delete($cache_key);
461
+ }
462
+
463
+ public function flush() {
464
+ return cmsCache::getInstance()->clean();
465
+ }
466
+
467
+ private function buildKey($key) {
468
+ if (is_array($key)) {
469
+ $key = md5(json_encode($key));
470
+ }
471
+ return '${name}_api_' . $key;
472
+ }
473
+ }`;
474
+ }
475
+ /**
476
+ * Generates API hook handlers
477
+ */
478
+ function generateApiHooks(name, Name, _endpoints, _options) {
479
+ return `<?php
480
+ // InstantCMS 2. system/hooks/${name}/api.hooks.php
481
+
482
+ class on${Name}ApiHook {
483
+ public function onBeforeRequest($client, $method, $path, $params) {
484
+ return [$client, $method, $path, $params];
485
+ }
486
+
487
+ public function onAfterRequest($result) {
488
+ return $result;
489
+ }
490
+
491
+ public function onRequestError($error) {
492
+ cmsUser::addSessionMessage('Ошибка API: ' . $error->getMessage(), 'error');
493
+ return false;
494
+ }
495
+ }`;
496
+ }
497
+ /**
498
+ * Generates a complete external API client for an InstantCMS addon
499
+ *
500
+ * @param opts - Configuration options for the API client
501
+ * @returns Object containing generated files and metadata
502
+ *
503
+ * @example
504
+ * ```typescript
505
+ * const result = scaffoldExternalApi({
506
+ * addon_name: 'payment_gateway',
507
+ * base_url: 'https://api.payment.example.com/v1',
508
+ * endpoints: [
509
+ * { path: '/payments', method: 'POST', description: 'Создать платёж' },
510
+ * { path: '/payments/{id}', method: 'GET', description: 'Статус платежа' }
511
+ * ],
512
+ * options: { use_auth: true, auth_type: 'bearer', use_rate_limit: true }
513
+ * });
514
+ * ```
515
+ */
516
+ function scaffoldExternalApi(opts) {
517
+ const { lowercase, UpperCamelCase } = (0, scaffold_1.normalizeAddonName)(opts.addon_name);
518
+ const files = {};
519
+ const options = {
520
+ use_auth: opts.options?.use_auth ?? true,
521
+ auth_type: opts.options?.auth_type ?? 'bearer',
522
+ timeout: opts.options?.timeout ?? 30,
523
+ use_rate_limit: opts.options?.use_rate_limit ?? true,
524
+ rate_limit: opts.options?.rate_limit ?? 60,
525
+ use_cache: opts.options?.use_cache ?? false,
526
+ };
527
+ files[`${lowercase}/api/client.php`] = generateApiClient(lowercase, UpperCamelCase, opts.base_url, opts.endpoints, options);
528
+ files[`${lowercase}/api/request.php`] = generateApiRequest(lowercase, UpperCamelCase, options);
529
+ if (options.use_auth) {
530
+ files[`${lowercase}/api/auth.php`] = generateApiAuth(lowercase, UpperCamelCase, options);
531
+ }
532
+ if (options.use_rate_limit) {
533
+ files[`${lowercase}/api/rate_limiter.php`] = generateRateLimiter(lowercase, UpperCamelCase, options);
534
+ }
535
+ if (options.use_cache) {
536
+ files[`${lowercase}/api/cache.php`] = generateApiCache(lowercase, UpperCamelCase, options);
537
+ }
538
+ files[`system/hooks/${lowercase}/api.hooks.php`] = generateApiHooks(lowercase, UpperCamelCase, opts.endpoints, options);
539
+ return {
540
+ addon_name: lowercase,
541
+ files,
542
+ base_url: opts.base_url,
543
+ endpoints_count: opts.endpoints.length,
544
+ options,
545
+ };
546
+ }
547
+ exports.externalApiToolSchema = {
548
+ name: 'scaffold_external_api',
549
+ description: 'Генерация клиента для внешнего API с поддержкой авторизации и rate limiting',
550
+ inputSchema: {
551
+ type: 'object',
552
+ properties: {
553
+ addon_name: { type: 'string', description: 'Имя дополнения' },
554
+ base_url: { type: 'string', description: 'Базовый URL API' },
555
+ endpoints: {
556
+ type: 'array',
557
+ items: {
558
+ type: 'object',
559
+ properties: {
560
+ path: { type: 'string' },
561
+ method: { type: 'string' },
562
+ description: { type: 'string' },
563
+ },
564
+ },
565
+ description: 'Эндпоинты API',
566
+ },
567
+ options: {
568
+ type: 'object',
569
+ properties: {
570
+ use_auth: { type: 'boolean', description: 'Использовать авторизацию' },
571
+ auth_type: {
572
+ type: 'string',
573
+ enum: ['api_key', 'bearer', 'basic', 'oauth2'],
574
+ description: 'Тип авторизации',
575
+ },
576
+ timeout: { type: 'number', description: 'Таймаут запроса' },
577
+ use_rate_limit: { type: 'boolean', description: 'Ограничение запросов' },
578
+ rate_limit: { type: 'number', description: 'Макс. запросов в минуту' },
579
+ use_cache: { type: 'boolean', description: 'Кэширование ответов' },
580
+ },
581
+ },
582
+ },
583
+ required: ['addon_name', 'base_url', 'endpoints'],
584
+ },
585
+ inputExamples: [
586
+ {
587
+ addon_name: 'payment_gateway',
588
+ base_url: 'https://api.payment.example.com/v1',
589
+ endpoints: [
590
+ { path: '/payments', method: 'POST', description: 'Создать платёж' },
591
+ { path: '/payments/{id}', method: 'GET', description: 'Статус платежа' },
592
+ ],
593
+ options: { use_auth: true, auth_type: 'bearer', use_rate_limit: true },
594
+ },
595
+ ],
596
+ };