@appaflytech/zeyrek-ai-mcp 0.0.1

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 (88) hide show
  1. package/.env.example +46 -0
  2. package/README.md +260 -0
  3. package/dist/config.js +128 -0
  4. package/dist/index.js +88 -0
  5. package/dist/knowledge/componentCatalog.js +438 -0
  6. package/dist/knowledge/componentEvents.js +164 -0
  7. package/dist/knowledge/coverage.js +60 -0
  8. package/dist/knowledge/normalize.js +1309 -0
  9. package/dist/knowledge/outlines.js +167 -0
  10. package/dist/knowledge/policy.js +44 -0
  11. package/dist/knowledge/reservedTables.js +75 -0
  12. package/dist/knowledge/rules.js +1725 -0
  13. package/dist/observability/trace.js +337 -0
  14. package/dist/platform/errors.js +132 -0
  15. package/dist/platform/http.js +169 -0
  16. package/dist/platform/responses.js +94 -0
  17. package/dist/platform/token.js +79 -0
  18. package/dist/resources/examples/entity-pair-m2m.json +105 -0
  19. package/dist/resources/examples/flow-list-to-form.json +65 -0
  20. package/dist/resources/examples/flow-load-table.json +178 -0
  21. package/dist/resources/examples/microservice-table-list.json +49 -0
  22. package/dist/resources/examples/middleware-authenticate.json +194 -0
  23. package/dist/resources/examples/page-detail-profile.json +95 -0
  24. package/dist/resources/examples/page-dynamic-form.json +221 -0
  25. package/dist/resources/examples/page-form-upsert.json +279 -0
  26. package/dist/resources/examples/page-html-embed.json +106 -0
  27. package/dist/resources/examples/page-sign-in.json +194 -0
  28. package/dist/resources/examples/workflow-basic.json +94 -0
  29. package/dist/resources/guides/component.md +108 -0
  30. package/dist/resources/guides/entity.md +348 -0
  31. package/dist/resources/guides/expressions.md +139 -0
  32. package/dist/resources/guides/getting-started.md +109 -0
  33. package/dist/resources/guides/html.md +106 -0
  34. package/dist/resources/guides/microservice.md +313 -0
  35. package/dist/resources/guides/middleware.md +271 -0
  36. package/dist/resources/guides/modify-existing.md +35 -0
  37. package/dist/resources/guides/page.md +1574 -0
  38. package/dist/resources/guides/view.md +89 -0
  39. package/dist/resources/guides/workflow.md +359 -0
  40. package/dist/resources/knowledge.js +44 -0
  41. package/dist/resources/schemas/CreateDatasourceCommand.json +54 -0
  42. package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +133 -0
  43. package/dist/resources/schemas/CreateEntityCommand.json +387 -0
  44. package/dist/resources/schemas/CreateMicroserviceCommand.json +528 -0
  45. package/dist/resources/schemas/CreateQueryCommand.json +43 -0
  46. package/dist/resources/schemas/CreateViewCommand.json +158 -0
  47. package/dist/resources/schemas/CreateWorkflowCommand.json +1719 -0
  48. package/dist/resources/schemas/Filter.json +124 -0
  49. package/dist/resources/schemas/GetRowsQuery.json +122 -0
  50. package/dist/resources/schemas/PreviewMicroserviceCommand.json +565 -0
  51. package/dist/resources/schemas/PreviewQueryCommand.json +74 -0
  52. package/dist/resources/schemas/PreviewWorkflowCommand.json +981 -0
  53. package/dist/resources/schemas/StepDto.json +900 -0
  54. package/dist/resources/schemas/UpdateDatasourceCommand.json +58 -0
  55. package/dist/resources/schemas/UpdateEntityCommand.json +679 -0
  56. package/dist/resources/schemas/UpdateMicroserviceCommand.json +512 -0
  57. package/dist/resources/schemas/UpdateQueryCommand.json +86 -0
  58. package/dist/resources/schemas/UpdateViewCommand.json +153 -0
  59. package/dist/resources/schemas/UpdateWorkflowCommand.json +1719 -0
  60. package/dist/resources/schemas.js +40 -0
  61. package/dist/server.js +63 -0
  62. package/dist/tools/access.js +27 -0
  63. package/dist/tools/applications.js +59 -0
  64. package/dist/tools/automations.js +103 -0
  65. package/dist/tools/common.js +18 -0
  66. package/dist/tools/components.js +280 -0
  67. package/dist/tools/datasources.js +82 -0
  68. package/dist/tools/dependencies.js +17 -0
  69. package/dist/tools/deployments.js +17 -0
  70. package/dist/tools/dtos.js +54 -0
  71. package/dist/tools/entities.js +166 -0
  72. package/dist/tools/files.js +138 -0
  73. package/dist/tools/flows.js +226 -0
  74. package/dist/tools/folders.js +51 -0
  75. package/dist/tools/layouts.js +105 -0
  76. package/dist/tools/microservices.js +198 -0
  77. package/dist/tools/organizations.js +65 -0
  78. package/dist/tools/pages.js +597 -0
  79. package/dist/tools/platformInfo.js +44 -0
  80. package/dist/tools/projects.js +152 -0
  81. package/dist/tools/queries.js +48 -0
  82. package/dist/tools/rows.js +115 -0
  83. package/dist/tools/screens.js +97 -0
  84. package/dist/tools/templates.js +65 -0
  85. package/dist/tools/variables.js +94 -0
  86. package/dist/tools/views.js +58 -0
  87. package/dist/tools/workflows.js +196 -0
  88. package/package.json +49 -0
@@ -0,0 +1,82 @@
1
+ import { guid, projectParam, environmentParam, pagingParams, readOnly, writes, updates, destructive } from './common.js';
2
+ import { handle } from '../platform/responses.js';
3
+ import { z } from 'zod';
4
+ const connectionInput = {
5
+ name: z.string().min(1),
6
+ description: z.string().optional(),
7
+ dbName: z.string().optional(),
8
+ type: z.string().describe('DatasourceType (ör. Postgres); datasource_resources tool\'u geçerli tipleri listeler'),
9
+ host: z.string().optional(),
10
+ port: z.number().int().optional(),
11
+ properties: z.record(z.unknown()).optional(),
12
+ connectionOptions: z.record(z.string()).optional()
13
+ };
14
+ export function registerDatasourceTools(server, platform) {
15
+ const config = platform.config;
16
+ server.registerTool('datasource_list', {
17
+ title: 'Datasource listele',
18
+ description: 'Projedeki datasource\'ları listeler; tree=true entity ağacıyla birlikte döner.',
19
+ inputSchema: {
20
+ project: projectParam,
21
+ environment: environmentParam,
22
+ tree: z.boolean().optional(),
23
+ searchTerm: z.string().optional(),
24
+ type: z.string().optional(),
25
+ ...pagingParams
26
+ },
27
+ annotations: readOnly
28
+ }, handle(config, ({ project, environment, tree, ...query }) => platform.tenant('GET', project, tree ? '/datasources/tree' : '/datasources', { environment, query })));
29
+ server.registerTool('datasource_get', {
30
+ title: 'Datasource getir',
31
+ description: 'Tek datasource\'u id ile getirir.',
32
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
33
+ annotations: readOnly
34
+ }, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/datasources/${id}`, { environment })));
35
+ server.registerTool('datasource_create', {
36
+ title: 'Datasource oluştur',
37
+ description: 'Projeye yeni datasource ekler; önce datasource_test_connection ile bağlantıyı doğrulamak iyi pratiktir.',
38
+ inputSchema: { project: projectParam, environment: environmentParam, ...connectionInput },
39
+ annotations: writes
40
+ }, handle(config, ({ project, environment, ...body }) => platform.tenant('POST', project, '/datasources', { environment, body })));
41
+ server.registerTool('datasource_update', {
42
+ title: 'Datasource güncelle',
43
+ description: 'Datasource bağlantı bilgilerini günceller.',
44
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid, ...connectionInput },
45
+ annotations: updates
46
+ }, handle(config, ({ project, environment, id, ...body }) => platform.tenant('PUT', project, `/datasources/${id}`, { environment, body })));
47
+ server.registerTool('datasource_delete', {
48
+ title: 'Datasource sil',
49
+ description: 'Datasource\'u siler; altındaki entity tanımları da etkilenir.',
50
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
51
+ annotations: destructive
52
+ }, handle(config, ({ project, environment, id }) => platform.tenant('DELETE', project, `/datasources/${id}`, { environment })));
53
+ server.registerTool('datasource_test_connection', {
54
+ title: 'Bağlantıyı test et',
55
+ description: "Kayıtlı datasource için 'id', kaydedilmemiş bağlantı için type/host/port alanlarını verin.",
56
+ inputSchema: {
57
+ project: projectParam,
58
+ environment: environmentParam,
59
+ id: guid.optional(),
60
+ type: z.string().optional(),
61
+ host: z.string().optional(),
62
+ port: z.number().int().optional(),
63
+ properties: z.record(z.unknown()).optional(),
64
+ connectionOptions: z.record(z.string()).optional()
65
+ },
66
+ annotations: readOnly
67
+ }, handle(config, ({ project, environment, id, ...body }) => id
68
+ ? platform.tenant('POST', project, `/datasources/${id}/test-connection`, { environment })
69
+ : platform.tenant('POST', project, '/datasources/test-connection', { environment, body })));
70
+ server.registerTool('datasource_resources', {
71
+ title: 'Datasource tiplerini listele',
72
+ description: 'Platformun desteklediği datasource tiplerini ve yapılandırma bilgilerini döner.',
73
+ inputSchema: { project: projectParam, environment: environmentParam },
74
+ annotations: readOnly
75
+ }, handle(config, ({ project, environment }) => platform.tenant('GET', project, '/datasources/resources', { environment })));
76
+ server.registerTool('datasource_configuration_options', {
77
+ title: 'Yapılandırma seçenekleri',
78
+ description: 'Kayıtlı datasource\'un tipine özel yapılandırma seçeneklerini döner.',
79
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
80
+ annotations: readOnly
81
+ }, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/datasources/${id}/configuration-options`, { environment })));
82
+ }
@@ -0,0 +1,17 @@
1
+ import { guid, projectParam, environmentParam, readOnly } from './common.js';
2
+ import { handle } from '../platform/responses.js';
3
+ import { z } from 'zod';
4
+ export function registerDependencyTools(server, platform) {
5
+ const config = platform.config;
6
+ server.registerTool('dependency_graph', {
7
+ title: 'Bağımlılık grafiği',
8
+ description: "Herhangi bir modül kaydının 'kim buna bağımlı' grafiğini döner. Silmeden önce çağırın — entity_dependencies/workflow_dependencies'in genel hâli (query, view, dto, microservice vb. için).",
9
+ inputSchema: {
10
+ project: projectParam,
11
+ environment: environmentParam,
12
+ module: z.string().describe('Modül adı: entity | field | microservice | workflow | query | view | dataTransferObject vb. (platform Module enum değeri)'),
13
+ id: guid
14
+ },
15
+ annotations: readOnly
16
+ }, handle(config, ({ project, environment, module, id }) => platform.tenant('GET', project, `/dependencies/${module}/${id}`, { environment })));
17
+ }
@@ -0,0 +1,17 @@
1
+ import { guid, readOnly, writes } from './common.js';
2
+ import { handle } from '../platform/responses.js';
3
+ export function registerDeploymentTools(server, platform) {
4
+ const config = platform.config;
5
+ server.registerTool('deployment_start', {
6
+ title: 'Deployment başlat',
7
+ description: 'Projeyi kaynak environment\'tan hedef environment\'a deploy eder. Asenkron bir saga\'dır: sonuç bu yanıtta bitmez, deployment_status ile izleyin. Environment id\'lerini project_get çıktısından alın.',
8
+ inputSchema: { projectId: guid, sourceEnvironmentId: guid, targetEnvironmentId: guid },
9
+ annotations: writes
10
+ }, handle(config, ({ projectId, ...body }) => platform.org('POST', `/deployments/${projectId}/deploy`, { body })));
11
+ server.registerTool('deployment_status', {
12
+ title: 'Deployment durumu',
13
+ description: 'Projenin son deployment durumunu döner.',
14
+ inputSchema: { projectId: guid },
15
+ annotations: readOnly
16
+ }, handle(config, ({ projectId }) => platform.org('GET', `/deployments/${projectId}`)));
17
+ }
@@ -0,0 +1,54 @@
1
+ import { guid, projectParam, environmentParam, definitionParam, pagingParams, readOnly, writes, updates, destructive } from './common.js';
2
+ import { handle } from '../platform/responses.js';
3
+ import { z } from 'zod';
4
+ export function registerDtoTools(server, platform) {
5
+ const config = platform.config;
6
+ server.registerTool('dto_list', {
7
+ title: 'DTO listele',
8
+ description: "DataTransferObject'leri listeler. Workflow/automation'a returnDtoId atamadan önce mevcut DTO'ları buradan arayın — platform entity başına DTO'lar üretir, çoğu zaman yenisini yazmak gerekmez.",
9
+ inputSchema: { project: projectParam, environment: environmentParam, searchTerm: z.string().optional(), ...pagingParams },
10
+ annotations: readOnly
11
+ }, handle(config, ({ project, environment, ...query }) => platform.tenant('GET', project, '/datatransferobjects', { environment, query })));
12
+ server.registerTool('dto_get', {
13
+ title: 'DTO getir',
14
+ description: 'Tek DTO tanımını alan ağacıyla getirir; dto_create için en iyi gövde şablonudur.',
15
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
16
+ annotations: readOnly
17
+ }, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/datatransferobjects/${id}`, { environment })));
18
+ server.registerTool('dto_scheme', {
19
+ title: 'DTO şeması',
20
+ description: "DTO'nun çözülmüş şemasını (alan sözlüğü) döner — workflow input./returnDto alanlarını doğrulamak için kullanın.",
21
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
22
+ annotations: readOnly
23
+ }, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/datatransferobjects/${id}/scheme`, { environment })));
24
+ server.registerTool('dto_create', {
25
+ title: 'DTO oluştur',
26
+ description: "Yeni DataTransferObject tanımlar (definition = CreateDataTransferObjectCommand). Workflow'un parameterDtoId/returnDtoId sözleşmeleri buradan çıkar; şablon için dto_get kullanın.",
27
+ inputSchema: { project: projectParam, environment: environmentParam, definition: definitionParam },
28
+ annotations: writes
29
+ }, handle(config, ({ project, environment, definition }) => platform.tenant('POST', project, '/datatransferobjects', { environment, body: definition })));
30
+ server.registerTool('dto_update', {
31
+ title: 'DTO güncelle',
32
+ description: 'DTO tanımını günceller (definition = UpdateDataTransferObjectCommand); mevcut hâli dto_get ile alın.',
33
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid, definition: definitionParam },
34
+ annotations: updates
35
+ }, handle(config, ({ project, environment, id, definition }) => platform.tenant('PUT', project, `/datatransferobjects/${id}`, { environment, body: definition })));
36
+ server.registerTool('dto_clone', {
37
+ title: 'DTO klonla',
38
+ description: "DTO'nun kopyasını oluşturur.",
39
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
40
+ annotations: writes
41
+ }, handle(config, ({ project, environment, id }) => platform.tenant('POST', project, `/datatransferobjects/${id}/clone`, { environment })));
42
+ server.registerTool('dto_sync_primitives', {
43
+ title: 'İlkel DTO tiplerini senkronla',
44
+ description: "Platformun ilkel (primitive) DTO tanımlarını projeye yeniden yazar; DTO listesinde temel tipler eksikse çalıştırılır. Bakım işidir.",
45
+ inputSchema: { project: projectParam, environment: environmentParam },
46
+ annotations: updates
47
+ }, handle(config, ({ project, environment }) => platform.tenant('POST', project, '/datatransferobjects/sync-primitives', { environment })));
48
+ server.registerTool('dto_delete', {
49
+ title: 'DTO sil',
50
+ description: "DTO'yu siler; workflow/query'lerde referans varsa platform reddeder.",
51
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
52
+ annotations: destructive
53
+ }, handle(config, ({ project, environment, id }) => platform.tenant('DELETE', project, `/datatransferobjects/${id}`, { environment })));
54
+ }
@@ -0,0 +1,166 @@
1
+ import { guid, projectParam, environmentParam, definitionParam, pagingParams, readOnly, writes, updates, destructive } from './common.js';
2
+ import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
3
+ import { splitJunctionFields, withNormalization } from '../knowledge/normalize.js';
4
+ import { entityOutline, resolvePart } from '../knowledge/outlines.js';
5
+ import { isJunctionField, policyRules } from '../knowledge/rules.js';
6
+ import { handle } from '../platform/responses.js';
7
+ import fastJsonPatch from 'fast-json-patch';
8
+ import { z } from 'zod';
9
+ const policyOverrideParam = z.boolean().optional()
10
+ .describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)');
11
+ const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
12
+ .describe("RFC 6902 JSON Patch işlemleri; path'leri view:'outline'/'part' ile keşfedin");
13
+ function preserveApplicationBinding(definition) {
14
+ if (Array.isArray(definition.applicationIds))
15
+ return;
16
+ const applications = Array.isArray(definition.applications) ? definition.applications : [];
17
+ const applicationIds = applications
18
+ .map(entry => (entry && typeof entry === 'object' ? entry.applicationId : undefined))
19
+ .filter((applicationId) => typeof applicationId === 'string');
20
+ if (applicationIds.length > 0)
21
+ definition.applicationIds = applicationIds;
22
+ }
23
+ export function registerEntityTools(server, platform) {
24
+ const config = platform.config;
25
+ server.registerTool('entity_list', {
26
+ title: 'Entity listele',
27
+ description: "Datasource altındaki entity'leri listeler. DİKKAT: applicationId verirseniz platformun HAZIR entity'leri (users, roles, user_roles, permissions, role_permissions, audit_trails) listede GÖRÜNMEZ — seed onlara application bağı açmaz. Kimlik tablosunu görmek için applicationId vermeden çağırın; ayrıntı platform_guide('entity') §'Hazır entity'ler'. (files/folders her hâlükârda gizlidir.)",
28
+ inputSchema: {
29
+ project: projectParam,
30
+ environment: environmentParam,
31
+ datasourceId: guid,
32
+ searchTerm: z.string().optional(),
33
+ hasPrimaryKey: z.boolean().optional(),
34
+ applicationId: guid.optional().describe("Verilirse yalnız bu application'a bağlı entity'ler döner; platformun hazır entity'leri (users/roles/…) bağsız olduğu için elenir"),
35
+ ...pagingParams
36
+ },
37
+ annotations: readOnly
38
+ }, handle(config, ({ project, environment, datasourceId, ...query }) => platform.tenant('GET', project, `/entities/${datasourceId}`, { environment, query })));
39
+ server.registerTool('entity_get', {
40
+ title: 'Entity getir',
41
+ description: "Entity'yi alan tanımlarıyla getirir. Çok alanlı entity'de önce view:'outline' (alan listesi), sonra view:'part' ile tek alan çekin.",
42
+ inputSchema: {
43
+ project: projectParam,
44
+ environment: environmentParam,
45
+ datasourceId: guid,
46
+ id: guid,
47
+ view: z.enum(['full', 'outline', 'part']).optional().describe('varsayılan full'),
48
+ part: z.string().optional().describe("view:'part' için yol, ör. fields[slug=email] veya indexes[0]")
49
+ },
50
+ annotations: readOnly
51
+ }, handle(config, async ({ project, environment, datasourceId, id, view, part }) => {
52
+ const payload = await platform.tenant('GET', project, `/entities/${datasourceId}/${id}`, { environment });
53
+ const definition = (payload?.data ?? payload);
54
+ if (view === 'outline')
55
+ return entityOutline(definition);
56
+ if (view === 'part') {
57
+ if (!part)
58
+ throw new Error("view:'part' için 'part' parametresi zorunlu.");
59
+ return { part, value: resolvePart(definition, part) };
60
+ }
61
+ return payload;
62
+ }));
63
+ server.registerTool('entity_create', {
64
+ title: 'Entity oluştur',
65
+ description: "Datasource altında yeni entity oluşturur (definition = CreateEntityCommand: name, fields[], applicationIds, ...). İlişkiler ve alan tipi kararı için platform_guide('entity') okuyun. Gövde politika kontrolünden geçer. applicationIds create'te platformca bağlanır (CreateEntityCommandHandler entityApplications'ı Entity ctor'una geçirir); satır uçları bu bağa İHTİYAÇ DUYMAZ — bağ yalnız Studio'nun application'a göre entity listesini ve bağımlılık sorgularını etkiler.",
66
+ inputSchema: { project: projectParam, environment: environmentParam, datasourceId: guid, definition: definitionParam, policyOverride: policyOverrideParam },
67
+ annotations: writes
68
+ }, handle(config, async ({ project, environment, datasourceId, definition, policyOverride }) => {
69
+ const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'entity', definition, { operation: 'create' }, policyOverride));
70
+ const { base, deferred } = splitJunctionFields(definition, isJunctionField);
71
+ const payload = await platform.tenant('POST', project, `/entities/${datasourceId}`, { environment, body: base });
72
+ if (deferred.length === 0)
73
+ return attachFindings(payload, findings);
74
+ const created = (payload?.data ?? payload);
75
+ const createdId = String(created?.id ?? '');
76
+ if (!createdId) {
77
+ throw new Error(`Entity kuruldu ama id okunamadı; m2m alanları (${deferred.map(field => field.slug ?? field.name).join(', ')}) eklenmedi — entity_get ile kaydı bulup entity_patch ile ekleyin.`);
78
+ }
79
+ const current = await platform.tenant('GET', project, `/entities/${datasourceId}/${createdId}`, { environment });
80
+ const full = structuredClone((current?.data ?? current));
81
+ full.fields = [...(Array.isArray(full.fields) ? full.fields : []), ...deferred];
82
+ preserveApplicationBinding(full);
83
+ const updated = await platform.tenant('PUT', project, `/entities/${createdId}`, { environment, body: full });
84
+ const note = `m2m/çoklu alanlar (${deferred.map(field => field.slug ?? field.name).join(', ')}) ayrı bir güncelleme turunda eklendi: create yolu junction kaydını açar ama fiziksel tabloyu kurmaz (platform bug'ı P-01), update yolu kurar.`;
85
+ return attachFindings(withNormalization(updated, [note]), findings);
86
+ }));
87
+ server.registerTool('entity_create_discovered', {
88
+ title: 'Keşfedilen entity\'leri içe al',
89
+ description: 'entity_discover çıktısından seçilen tabloları toplu entity olarak içe alır. definition = CreateDiscoveredEntitiesCommand gövdesi.',
90
+ inputSchema: { project: projectParam, environment: environmentParam, datasourceId: guid, definition: definitionParam },
91
+ annotations: writes
92
+ }, handle(config, ({ project, environment, datasourceId, definition }) => platform.tenant('POST', project, `/entities/${datasourceId}/discovered`, { environment, body: definition })));
93
+ server.registerTool('entity_update', {
94
+ title: 'Entity güncelle',
95
+ description: 'Entity tanımını günceller (tam gövde). Hedefli değişiklik için entity_patch tercih edin. Gövde politika kontrolünden geçer.',
96
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid, definition: definitionParam, policyOverride: policyOverrideParam },
97
+ annotations: updates
98
+ }, handle(config, async ({ project, environment, id, definition, policyOverride }) => {
99
+ const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'entity', definition, { operation: 'update' }, policyOverride));
100
+ const payload = await platform.tenant('PUT', project, `/entities/${id}`, { environment, body: definition });
101
+ return attachFindings(payload, findings);
102
+ }));
103
+ server.registerTool('entity_patch', {
104
+ title: 'Entity\'ye patch uygula',
105
+ description: "Tam gövdeyi bağlama almadan hedefli değişiklik: gateway mevcut tanımı çeker, JSON Patch uygular, politika kontrolünden geçirir, geri yazar. Yanıt outline özetidir. GET 'applications' döner ama UpdateEntityCommand 'applicationIds' okur; gateway bu çeviriyi kendisi yapar, yoksa her patch application bağını sessizce siler.",
106
+ inputSchema: { project: projectParam, environment: environmentParam, datasourceId: guid, id: guid, operations: patchOperationsParam, policyOverride: policyOverrideParam },
107
+ annotations: updates
108
+ }, handle(config, async ({ project, environment, datasourceId, id, operations, policyOverride }) => {
109
+ const current = await platform.tenant('GET', project, `/entities/${datasourceId}/${id}`, { environment });
110
+ const definition = structuredClone((current?.data ?? current));
111
+ const patched = fastJsonPatch.applyPatch(definition, operations, true, false).newDocument;
112
+ preserveApplicationBinding(patched);
113
+ const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'entity', patched, { operation: 'update' }, policyOverride));
114
+ await platform.tenant('PUT', project, `/entities/${id}`, { environment, body: patched });
115
+ return attachFindings({ applied: operations.length, outline: entityOutline(patched) }, findings);
116
+ }));
117
+ server.registerTool('entity_delete', {
118
+ title: 'Entity sil',
119
+ description: 'Entity tanımını siler; önce entity_dependencies ile bağımlılıklarını kontrol edin.',
120
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
121
+ annotations: destructive
122
+ }, handle(config, ({ project, environment, id }) => platform.tenant('DELETE', project, `/entities/${id}`, { environment })));
123
+ server.registerTool('entity_clone', {
124
+ title: 'Entity klonla',
125
+ description: 'Entity\'nin kopyasını oluşturur.',
126
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
127
+ annotations: writes
128
+ }, handle(config, ({ project, environment, id }) => platform.tenant('POST', project, `/entities/${id}/clone`, { environment })));
129
+ server.registerTool('entity_discover', {
130
+ title: 'Dış şemadan entity keşfet',
131
+ description: 'Datasource\'un bağlı olduğu veritabanındaki tabloları entity adayı olarak listeler.',
132
+ inputSchema: { project: projectParam, environment: environmentParam, datasourceId: guid },
133
+ annotations: readOnly
134
+ }, handle(config, ({ project, environment, datasourceId }) => platform.tenant('GET', project, `/entities/${datasourceId}/discover`, { environment })));
135
+ server.registerTool('entity_relation_tree', {
136
+ title: 'İlişki ağacı',
137
+ description: 'Entity\'nin ilişki ağacını döner; mode: simple | full.',
138
+ inputSchema: {
139
+ project: projectParam,
140
+ environment: environmentParam,
141
+ id: guid,
142
+ mode: z.enum(['simple', 'full']).optional(),
143
+ parentEntityId: guid.optional()
144
+ },
145
+ annotations: readOnly
146
+ }, handle(config, ({ project, environment, id, ...query }) => platform.tenant('GET', project, `/entities/${id}/tree`, { environment, query })));
147
+ server.registerTool('entity_dependencies', {
148
+ title: 'Entity bağımlılıkları',
149
+ description: 'Entity\'ye bağımlı microservice/workflow/page kayıtlarının grafiğini döner.',
150
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
151
+ annotations: readOnly
152
+ }, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/entities/${id}/dependencies`, { environment })));
153
+ server.registerTool('entity_audit_trails', {
154
+ title: 'Audit kayıtları',
155
+ description: 'Entity\'nin satır bazlı audit trail kayıtlarını listeler (audit trail açık olmalı).',
156
+ inputSchema: {
157
+ project: projectParam,
158
+ environment: environmentParam,
159
+ entityId: guid,
160
+ rowId: z.string().optional(),
161
+ userId: z.string().optional(),
162
+ ...pagingParams
163
+ },
164
+ annotations: readOnly
165
+ }, handle(config, ({ project, environment, entityId, ...query }) => platform.tenant('GET', project, `/entities/${entityId}/audit-trails`, { environment, query })));
166
+ }
@@ -0,0 +1,138 @@
1
+ import { guid, projectParam, environmentParam, pagingParams, readOnly, updates, destructive, writes } from './common.js';
2
+ import { PlatformApiError } from '../platform/errors.js';
3
+ import { handle } from '../platform/responses.js';
4
+ import { readFile, writeFile } from 'node:fs/promises';
5
+ import { basename, extname, resolve } from 'node:path';
6
+ import { z } from 'zod';
7
+ const maxInlineBytes = 8 * 1024 * 1024;
8
+ const maxUploadBytes = 50 * 1024 * 1024;
9
+ const forbiddenNameChars = `\\|!#~$%&/=?»«@£§€{};'<>,`;
10
+ const mimeTypes = {
11
+ '.css': 'text/css',
12
+ '.csv': 'text/csv',
13
+ '.doc': 'application/msword',
14
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
15
+ '.gif': 'image/gif',
16
+ '.htm': 'text/html',
17
+ '.html': 'text/html',
18
+ '.ico': 'image/x-icon',
19
+ '.jpeg': 'image/jpeg',
20
+ '.jpg': 'image/jpeg',
21
+ '.js': 'text/javascript',
22
+ '.json': 'application/json',
23
+ '.mp3': 'audio/mpeg',
24
+ '.mp4': 'video/mp4',
25
+ '.pdf': 'application/pdf',
26
+ '.png': 'image/png',
27
+ '.ppt': 'application/vnd.ms-powerpoint',
28
+ '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
29
+ '.svg': 'image/svg+xml',
30
+ '.txt': 'text/plain',
31
+ '.webp': 'image/webp',
32
+ '.woff2': 'font/woff2',
33
+ '.xls': 'application/vnd.ms-excel',
34
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
35
+ '.xml': 'application/xml',
36
+ '.zip': 'application/zip'
37
+ };
38
+ export function registerFileTools(server, platform) {
39
+ const config = platform.config;
40
+ server.registerTool('file_list', {
41
+ title: 'Dosyaları listele',
42
+ description: 'Projedeki dosya kayıtlarını listeler (metadata; içerik değil). İçerik aktarımı için file_upload / file_download kullanın.',
43
+ inputSchema: { project: projectParam, environment: environmentParam, searchTerm: z.string().optional(), folderId: guid.optional(), ...pagingParams },
44
+ annotations: readOnly
45
+ }, handle(config, ({ project, environment, ...query }) => platform.tenant('GET', project, '/files', { environment, query })));
46
+ server.registerTool('file_get', {
47
+ title: 'Dosya bilgisi getir',
48
+ description: 'Tek dosyanın metadata kaydını getirir (ad, boyut, yol; içerik değil). İçerik için file_download.',
49
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
50
+ annotations: readOnly
51
+ }, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/files/${id}`, { environment })));
52
+ server.registerTool('file_upload', {
53
+ title: 'Dosya yükle',
54
+ description: "Dosyayı projenin depolamasına yükler ve FileDto (id + serve adresleri) döner. İçerik iki yoldan verilir: `path` — gateway sürecinin okuyabildiği yerel yol (büyük dosyalar için tercih edilir, içerik model bağlamına girmez), ya da `content` — base64 (8 MB'a kadar) + `filename`. Platform sınırı 50 MB; dosya adı \\|!#~$%&/=?»«@£§€{};'<>, karakterlerini içeremez. Yüklenen dosya sayfada `image`/`file-viewer` komponentiyle gösterilir ya da satır alanına yol olarak yazılır.",
55
+ inputSchema: {
56
+ project: projectParam,
57
+ environment: environmentParam,
58
+ path: z.string().min(1).optional().describe("Gateway sürecinin okuyabildiği yerel dosya yolu; `content` ile birlikte verilmez"),
59
+ content: z.string().min(1).optional().describe('Base64 kodlanmış dosya içeriği; `filename` ile birlikte zorunludur'),
60
+ filename: z.string().min(1).optional().describe("`content` ile zorunlu; `path` verildiğinde dosya adını ezer"),
61
+ contentType: z.string().min(1).optional().describe('Belirtilmezse uzantıdan çözülür, bilinmeyen uzantıda application/octet-stream'),
62
+ folderId: guid.optional().describe('Hedef klasör (folder_list); boşsa kök')
63
+ },
64
+ annotations: writes
65
+ }, handle(config, async ({ project, environment, path, content, filename, contentType, folderId }) => {
66
+ if (!path === !content) {
67
+ throw new PlatformApiError("file_upload: `path` ya da `content` parametrelerinden tam olarak biri verilmeli — `path` gateway'in okuyabildiği yerel dosya, `content` base64 içerik (`filename` ile).");
68
+ }
69
+ let bytes;
70
+ let name;
71
+ if (path) {
72
+ const absolute = resolve(path);
73
+ try {
74
+ bytes = await readFile(absolute);
75
+ }
76
+ catch (error) {
77
+ throw new PlatformApiError(`file_upload: dosya okunamadı — ${absolute} (${error instanceof Error ? error.message : String(error)}). Yol gateway sürecinin çalıştığı makineye göre çözülür.`);
78
+ }
79
+ name = filename ?? basename(absolute);
80
+ }
81
+ else {
82
+ if (!filename)
83
+ throw new PlatformApiError('file_upload: `content` verildiğinde `filename` zorunludur.');
84
+ bytes = Buffer.from(content, 'base64');
85
+ if (bytes.byteLength === 0)
86
+ throw new PlatformApiError('file_upload: `content` geçerli base64 değil ya da boş.');
87
+ if (bytes.byteLength > maxInlineBytes) {
88
+ throw new PlatformApiError(`file_upload: base64 içerik ${maxInlineBytes} bayt sınırını aşıyor (${bytes.byteLength} B). Büyük dosyalar için \`path\` kullanın.`);
89
+ }
90
+ name = filename;
91
+ }
92
+ if (bytes.byteLength > maxUploadBytes) {
93
+ throw new PlatformApiError(`file_upload: dosya ${maxUploadBytes} bayt platform sınırını aşıyor (${bytes.byteLength} B).`);
94
+ }
95
+ const offendingChar = [...forbiddenNameChars].find(character => name.includes(character));
96
+ if (offendingChar) {
97
+ throw new PlatformApiError(`file_upload: dosya adı '${offendingChar}' karakterini içeriyor; platform doğrulaması bunu reddeder. Yasak karakterler: ${forbiddenNameChars}`);
98
+ }
99
+ const resolvedType = contentType ?? mimeTypes[extname(name).toLowerCase()] ?? 'application/octet-stream';
100
+ const multipart = folderId
101
+ ? [{ name: 'FolderId', value: folderId }, { name: 'File', filename: name, contentType: resolvedType, content: bytes }]
102
+ : [{ name: 'File', filename: name, contentType: resolvedType, content: bytes }];
103
+ return platform.tenant('POST', project, '/files/upload', { environment, multipart });
104
+ }));
105
+ server.registerTool('file_download', {
106
+ title: 'Dosya indir',
107
+ description: "Dosyanın içeriğini indirir ve `outPath` ile verilen yerel yola yazar; dönen gövde yalnız özet (yol, boyut, tip) — ikili içerik model bağlamına girmez. Yol gateway sürecinin çalıştığı makineye göre çözülür.",
108
+ inputSchema: {
109
+ project: projectParam,
110
+ environment: environmentParam,
111
+ id: guid,
112
+ outPath: z.string().min(1).describe('İçeriğin yazılacağı yerel dosya yolu')
113
+ },
114
+ annotations: writes
115
+ }, handle(config, async ({ project, environment, id, outPath }) => {
116
+ const payload = await platform.tenant('GET', project, `/files/${id}/download`, { environment, expectBinary: true });
117
+ const absolute = resolve(outPath);
118
+ try {
119
+ await writeFile(absolute, payload.bytes);
120
+ }
121
+ catch (error) {
122
+ throw new PlatformApiError(`file_download: dosya yazılamadı — ${absolute} (${error instanceof Error ? error.message : String(error)}).`);
123
+ }
124
+ return { path: absolute, sizeBytes: payload.bytes.byteLength, contentType: payload.contentType };
125
+ }));
126
+ server.registerTool('file_rename', {
127
+ title: 'Dosyayı yeniden adlandır',
128
+ description: 'Dosya kaydının adını değiştirir (içerik aktarımı gerekmez).',
129
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid, name: z.string().min(1) },
130
+ annotations: updates
131
+ }, handle(config, ({ project, environment, id, name }) => platform.tenant('PATCH', project, `/files/${id}/rename`, { environment, body: { name } })));
132
+ server.registerTool('file_delete', {
133
+ title: 'Dosya sil',
134
+ description: 'Dosya kaydını siler.',
135
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid },
136
+ annotations: destructive
137
+ }, handle(config, ({ project, environment, id }) => platform.tenant('DELETE', project, `/files/${id}`, { environment })));
138
+ }