@appaflytech/zeyrek-ai-mcp 0.0.28 → 0.0.30
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/.env.example +15 -0
- package/README.md +5 -5
- package/dist/config.js +37 -0
- package/dist/index.js +2 -0
- package/dist/knowledge/access.js +802 -0
- package/dist/knowledge/backendConstraints.js +18 -1
- package/dist/knowledge/case.js +41 -0
- package/dist/knowledge/componentCatalog.js +494 -34
- package/dist/knowledge/componentEvents.js +132 -7
- package/dist/knowledge/connectDataBind.js +819 -0
- package/dist/knowledge/connectDataDefinition.js +341 -0
- package/dist/knowledge/connectDataExecute.js +93 -0
- package/dist/knowledge/connectDataRules.js +128 -0
- package/dist/knowledge/decision.js +121 -0
- package/dist/knowledge/expressionPrelude.js +59 -0
- package/dist/knowledge/layoutSummary.js +140 -2
- package/dist/knowledge/microserviceParameters.js +58 -0
- package/dist/knowledge/mining.js +94 -0
- package/dist/knowledge/mobileComponentCatalog.js +859 -0
- package/dist/knowledge/mobileComponentEvents.js +239 -0
- package/dist/knowledge/normalize.js +236 -67
- package/dist/knowledge/outlines.js +36 -0
- package/dist/knowledge/platform/lint.js +385 -0
- package/dist/knowledge/platform/mobile.js +142 -0
- package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
- package/dist/knowledge/platform/mobileRules.js +231 -0
- package/dist/knowledge/platform/mobileSpacing.js +82 -0
- package/dist/knowledge/platform/mobileTabs.js +108 -0
- package/dist/knowledge/platform/nativeBoxModel.js +44 -0
- package/dist/knowledge/platform/profile.js +25 -0
- package/dist/knowledge/platform/resolve.js +122 -0
- package/dist/knowledge/platform/web.js +39 -0
- package/dist/knowledge/policy.js +18 -4
- package/dist/knowledge/process.js +510 -0
- package/dist/knowledge/reservedTables.js +79 -0
- package/dist/knowledge/rowFilter.js +43 -0
- package/dist/knowledge/rules.js +319 -21
- package/dist/knowledge/schemaGuard.js +11 -0
- package/dist/knowledge/styleResolve.js +50 -4
- package/dist/knowledge/styleResolveNative.js +527 -0
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/observability/trace.js +6 -3
- package/dist/platform/argumentAliases.js +128 -0
- package/dist/platform/bodyFile.js +103 -0
- package/dist/platform/capture/actions.js +333 -0
- package/dist/platform/capture/browser.js +1 -0
- package/dist/platform/{screenshot.js → capture/capture.js} +105 -519
- package/dist/platform/capture/console-log.js +122 -0
- package/dist/platform/capture/index.js +11 -0
- package/dist/platform/capture/readiness.js +103 -0
- package/dist/platform/capture/summary.js +77 -0
- package/dist/platform/capture/target.js +5 -0
- package/dist/platform/capture/targets/studio-mobile.js +15 -0
- package/dist/platform/capture/targets/studio-web.js +5 -0
- package/dist/platform/diagnostics.js +10 -4
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/errors.js +162 -10
- package/dist/platform/http.js +29 -8
- package/dist/platform/impersonation.js +45 -0
- package/dist/platform/jsonArray.js +24 -0
- package/dist/platform/responses.js +39 -5
- package/dist/platform/schemaReadMemory.js +60 -0
- package/dist/platform/secrets.js +17 -1
- package/dist/platform/strictArguments.js +68 -12
- package/dist/platform/tokenVault.js +187 -4
- package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
- package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
- package/dist/resources/examples/bpm-satinalma.json +376 -0
- package/dist/resources/examples/connect-data-convert-verify.json +107 -0
- package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
- package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
- package/dist/resources/examples/connect-data-query-params.json +50 -0
- package/dist/resources/examples/connect-data-table-entity.json +147 -0
- package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
- package/dist/resources/examples/mobile-app-shell-drawer.json +243 -0
- package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
- package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
- package/dist/resources/examples/mobile-form-screen.json +365 -0
- package/dist/resources/examples/mobile-list-detail-form.json +672 -0
- package/dist/resources/examples/page-detail-profile.json +2 -1
- package/dist/resources/examples/page-dynamic-form.json +3 -2
- package/dist/resources/examples/page-flex-sections.json +1 -1
- package/dist/resources/examples/page-html-embed.json +1 -1
- package/dist/resources/examples/workflow-basic.json +8 -2
- package/dist/resources/guides/access.md +796 -0
- package/dist/resources/guides/bpm.md +686 -0
- package/dist/resources/guides/case.md +153 -0
- package/dist/resources/guides/component.md +91 -4
- package/dist/resources/guides/decision.md +185 -0
- package/dist/resources/guides/entity.md +50 -8
- package/dist/resources/guides/expressions.md +14 -5
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/getting-started.md +38 -1
- package/dist/resources/guides/layout.md +11 -7
- package/dist/resources/guides/microservice.md +81 -2
- package/dist/resources/guides/middleware.md +44 -2
- package/dist/resources/guides/mobile-layout.md +193 -0
- package/dist/resources/guides/mobile.md +495 -0
- package/dist/resources/guides/page.md +454 -75
- package/dist/resources/guides/theme.md +8 -2
- package/dist/resources/guides/translation.md +1 -1
- package/dist/resources/guides/workflow.md +58 -1
- package/dist/resources/read.js +41 -0
- package/dist/resources/rules.js +11 -5
- package/dist/resources/schema-fingerprint.json +7 -5
- package/dist/resources/schemas/AccessExplanationDto.json +144 -0
- package/dist/resources/schemas/AccessMatrixDto.json +170 -0
- package/dist/resources/schemas/AccessPermissionDto.json +57 -0
- package/dist/resources/schemas/AccessPolicyDto.json +223 -0
- package/dist/resources/schemas/AccessResourceDto.json +86 -0
- package/dist/resources/schemas/AppSessionDto.json +53 -0
- package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
- package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
- package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
- package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
- package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
- package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
- package/dist/resources/schemas/CreateEntityCommand.json +118 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
- package/dist/resources/schemas/CreateQueryCommand.json +4 -0
- package/dist/resources/schemas/CreateWorkflowCommand.json +143 -1
- package/dist/resources/schemas/DataJobDto.json +6 -1
- package/dist/resources/schemas/DecisionDto.json +302 -0
- package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
- package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
- package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +21 -1
- package/dist/resources/schemas/MicroserviceDto.json +15 -3
- package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
- package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
- package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
- package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +10 -1
- package/dist/resources/schemas/PreviewWorkflowCommand.json +22 -1
- package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
- package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
- package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
- package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
- package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
- package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
- package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
- package/dist/resources/schemas/StepDto.json +22 -1
- package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +118 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
- package/dist/resources/schemas/UpdateQueryCommand.json +4 -0
- package/dist/resources/schemas/UpdateViewCommand.json +0 -2
- package/dist/resources/schemas/UpdateWorkflowCommand.json +143 -1
- package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
- package/dist/server.js +27 -1
- package/dist/tools/access.js +369 -2
- package/dist/tools/accessOperations.js +135 -0
- package/dist/tools/accessPolicies.js +170 -0
- package/dist/tools/accessRuntime.js +203 -0
- package/dist/tools/applications.js +60 -3
- package/dist/tools/bpm.js +343 -0
- package/dist/tools/bpmGovernance.js +266 -0
- package/dist/tools/bpmOperations.js +230 -0
- package/dist/tools/bpmReporting.js +154 -0
- package/dist/tools/bpmRouting.js +150 -0
- package/dist/tools/bpmRuntime.js +396 -0
- package/dist/tools/case.js +178 -0
- package/dist/tools/caseRuntime.js +89 -0
- package/dist/tools/common.js +7 -0
- package/dist/tools/components.js +118 -14
- package/dist/tools/connectData.js +449 -0
- package/dist/tools/connectors.js +193 -0
- package/dist/tools/datasources.js +3 -3
- package/dist/tools/decisions.js +206 -0
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +2 -2
- package/dist/tools/designSchemaPatch.js +34 -9
- package/dist/tools/dtos.js +36 -5
- package/dist/tools/entities.js +79 -12
- package/dist/tools/externalComponents.js +26 -5
- package/dist/tools/flows.js +122 -14
- package/dist/tools/folders.js +1 -1
- package/dist/tools/imports.js +5 -2
- package/dist/tools/layouts.js +50 -17
- package/dist/tools/merges.js +1 -1
- package/dist/tools/microservices.js +77 -25
- package/dist/tools/mobile.js +221 -0
- package/dist/tools/modules.js +48 -0
- package/dist/tools/organizationStructure.js +137 -0
- package/dist/tools/pages.js +465 -98
- package/dist/tools/platformInfo.js +27 -8
- package/dist/tools/profileWrite.js +92 -0
- package/dist/tools/projects.js +71 -9
- package/dist/tools/rows.js +69 -13
- package/dist/tools/schemaOps.js +61 -1
- package/dist/tools/screenWrite.js +37 -8
- package/dist/tools/screens.js +95 -5
- package/dist/tools/templates.js +26 -1
- package/dist/tools/translations.js +1 -1
- package/dist/tools/variables.js +11 -5
- package/dist/tools/workflows.js +10 -5
- package/package.json +2 -2
package/dist/tools/layouts.js
CHANGED
|
@@ -4,13 +4,16 @@ import { patchResult, baseVersionOf } from '../platform/patch.js';
|
|
|
4
4
|
import fastJsonPatch from 'fast-json-patch';
|
|
5
5
|
import { normalizeComponentDefaults, componentDefaultsNote, flexSizeWarnings, spacingLayerWarnings, verticalGapWarnings, withNormalization } from '../knowledge/normalize.js';
|
|
6
6
|
import { fetchHost, layoutUpdateBody, schemaParam, eventsParam, modeParam, summarize, findNode } from './screens.js';
|
|
7
|
-
import { assertScreenWriteGuards,
|
|
7
|
+
import { assertScreenWriteGuards, assertScreenCatalog } from './screenWrite.js';
|
|
8
8
|
import { applyPropTypesToSchema, isSetPropTypeOp, setPropTypeErrors } from '../knowledge/propTypes.js';
|
|
9
9
|
import { writeDiff, withWriteDiff } from '../platform/writeDiff.js';
|
|
10
10
|
import { PlatformApiError } from '../platform/errors.js';
|
|
11
11
|
import { handle } from '../platform/responses.js';
|
|
12
|
+
import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
|
|
13
|
+
import { screenProfileWarnings } from './profileWrite.js';
|
|
14
|
+
import { jsonArray } from '../platform/jsonArray.js';
|
|
12
15
|
import { z } from 'zod';
|
|
13
|
-
const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
|
|
16
|
+
const patchOperationsParam = jsonArray(z.array(z.record(z.unknown())).min(1))
|
|
14
17
|
.describe("JSON Patch listesi (RFC 6902): { op, path, value }. Yol seçici alabilir — '/views/0/children[elementId=baslik]/props/content/data'.");
|
|
15
18
|
const viewsParam = schemaParam.describe("Layout'un komponent ağacı. DİKKAT: layout'ta şema alanının adı 'schema' değil 'views'tir; ağaçta hedefli değişiklik için tam ağaç yerine layout_schema_patch micro-op'larını kullanın. İçinde MUTLAKA bir { type: 'slot' } komponenti olmalı — sayfa içeriği YALNIZ slot'un içine render edilir, slot'suz layout'a bağlanan sayfalar boş görünür. 2026-09-08'den beri views, page_schema_patch'in doğrulama duvarından geçer: tanınmayan prop adı ve geçersiz enum değeri 422 ile REDDEDİLİR (kabul edilen değer listesiyle) ve hiçbir şey kaydedilmez — eskiden sessizce kaydediliyordu (P1-2).");
|
|
16
19
|
function countSlots(nodes) {
|
|
@@ -46,7 +49,13 @@ export function registerLayoutTools(server, platform) {
|
|
|
46
49
|
description: "Layout'u komponent ağacı (views), widget'ları, akışları ve olaylarıyla getirir.",
|
|
47
50
|
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid },
|
|
48
51
|
annotations: readOnly
|
|
49
|
-
}, handle(config, ({ project, environment, applicationId, id }) =>
|
|
52
|
+
}, handle(config, async ({ project, environment, applicationId, id }) => {
|
|
53
|
+
const response = await platform.tenant('GET', project, `/layouts/${applicationId}/${id}`, { environment });
|
|
54
|
+
const typeField = applicationTypeField(await resolveProfile(platform, applicationId));
|
|
55
|
+
return response && typeof response === 'object' && !Array.isArray(response) && Object.keys(typeField).length > 0
|
|
56
|
+
? { ...response, ...typeField }
|
|
57
|
+
: response;
|
|
58
|
+
}));
|
|
50
59
|
server.registerTool('layout_schema_get', {
|
|
51
60
|
title: "Layout komponent ağacını oku",
|
|
52
61
|
description: "Layout'un komponent ağacını (views) okur — page_schema_get'in layout karşılığı. Ağaçta hedefli değişiklik için layout_schema_patch (sayfa ile aynı micro-op sözlüğü, PATCH /layouts/{app}/{id}/schema). Ad/parametre/olay alanlarında ya da düz JSON Patch yolu gerektiğinde layout_patch — o araç buradaki updatedAt'i expectedUpdatedAt olarak kabul eder. Tam ağacı kendiniz yazacaksanız layout_update.",
|
|
@@ -61,20 +70,21 @@ export function registerLayoutTools(server, platform) {
|
|
|
61
70
|
annotations: readOnly
|
|
62
71
|
}, handle(config, async ({ project, environment, applicationId, id, mode, componentId }) => {
|
|
63
72
|
const layout = await fetchHost(platform, 'layout', project, environment, applicationId, id);
|
|
73
|
+
const typeField = applicationTypeField(await resolveProfile(platform, applicationId));
|
|
64
74
|
const audit = layout.audit;
|
|
65
75
|
const updatedAt = audit?.updatedAt ?? audit?.createdAt;
|
|
66
76
|
const views = (layout.views ?? []);
|
|
67
77
|
if (mode === 'full')
|
|
68
|
-
return { updatedAt, views };
|
|
78
|
+
return { updatedAt, ...typeField, views };
|
|
69
79
|
if (mode === 'subtree') {
|
|
70
80
|
if (!componentId)
|
|
71
81
|
throw new PlatformApiError("mode='subtree' için componentId zorunludur.");
|
|
72
82
|
const subtree = findNode(views, componentId);
|
|
73
83
|
if (!subtree)
|
|
74
84
|
throw new PlatformApiError(`Layout'ta '${componentId}' id'li bir komponent yok; layout_schema_get'i summary kipinde çağırıp hedefi doğrulayın.`);
|
|
75
|
-
return { updatedAt, views: subtree };
|
|
85
|
+
return { updatedAt, ...typeField, views: subtree };
|
|
76
86
|
}
|
|
77
|
-
return { updatedAt, views: views.map(node => summarize(node)) };
|
|
87
|
+
return { updatedAt, ...typeField, views: views.map(node => summarize(node)) };
|
|
78
88
|
}));
|
|
79
89
|
server.registerTool('layout_create', {
|
|
80
90
|
title: 'Layout oluştur',
|
|
@@ -90,19 +100,28 @@ export function registerLayoutTools(server, platform) {
|
|
|
90
100
|
},
|
|
91
101
|
annotations: writes
|
|
92
102
|
}, handle(config, async ({ project, environment, applicationId, name, views, events, parameters }) => {
|
|
93
|
-
|
|
103
|
+
const resolved = await resolveProfile(platform, applicationId);
|
|
104
|
+
assertScreenWriteGuards('layout', { schema: views, events }, resolved.profile.platform);
|
|
94
105
|
const fixed = normalizeComponentDefaults(views);
|
|
95
|
-
const catalogNotes = await
|
|
96
|
-
const gaps = [
|
|
106
|
+
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, views, 'layout_create');
|
|
107
|
+
const gaps = [
|
|
108
|
+
...(resolved.profile.layout.blocksMeaningful ? verticalGapWarnings(views ?? [], 'LAY-003 (uyarı)') : []),
|
|
109
|
+
...flexSizeWarnings(views ?? [], 'LAY-007 (uyarı)', 'LAY-008 (uyarı)'),
|
|
110
|
+
...spacingLayerWarnings(views ?? [], 'LAY-010 (uyarı)', 'LAY-011 (uyarı)'),
|
|
111
|
+
...await screenProfileWarnings(platform, resolved, project, environment, applicationId, { kind: 'layout', nodes: views ?? [] })
|
|
112
|
+
];
|
|
97
113
|
const response = await platform.tenant('POST', project, `/layouts/${applicationId}`, {
|
|
98
114
|
environment,
|
|
99
115
|
body: { name, views: views ?? [], events: events ?? [], parameters: parameters ?? null }
|
|
100
116
|
});
|
|
101
117
|
const drops = writeDiff({ name, views: views ?? [], events: events ?? [] }, response);
|
|
102
118
|
const normalized = withWriteDiff(withNormalization(response, [...componentDefaultsNote(fixed), ...catalogNotes, ...slotWarning(views)]), drops);
|
|
103
|
-
|
|
119
|
+
const typeField = applicationTypeField(resolved);
|
|
120
|
+
if (!normalized || typeof normalized !== 'object')
|
|
104
121
|
return normalized;
|
|
105
|
-
|
|
122
|
+
if (gaps.length === 0)
|
|
123
|
+
return Object.keys(typeField).length === 0 ? normalized : { ...normalized, ...typeField };
|
|
124
|
+
return { ...normalized, ...typeField, layoutWarnings: gaps };
|
|
106
125
|
}));
|
|
107
126
|
server.registerTool('layout_update', {
|
|
108
127
|
title: 'Layout güncelle',
|
|
@@ -120,13 +139,21 @@ export function registerLayoutTools(server, platform) {
|
|
|
120
139
|
annotations: updates
|
|
121
140
|
}, handle(config, async ({ project, environment, applicationId, id, ...changes }) => {
|
|
122
141
|
const overrides = Object.fromEntries(Object.entries(changes).filter(([, value]) => value !== undefined));
|
|
123
|
-
|
|
142
|
+
const resolved = overrides.views === undefined ? undefined : await resolveProfile(platform, applicationId);
|
|
143
|
+
assertScreenWriteGuards('layout', { schema: overrides.views, events: overrides.events }, resolved?.profile.platform);
|
|
124
144
|
const current = await fetchHost(platform, 'layout', project, environment, applicationId, id);
|
|
125
145
|
const fixed = normalizeComponentDefaults(overrides.views);
|
|
126
|
-
const catalogNotes = await
|
|
146
|
+
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, overrides.views, 'layout_update');
|
|
127
147
|
const body = layoutUpdateBody({ ...current, applicationId }, overrides);
|
|
128
148
|
await platform.tenant('PUT', project, `/layouts/${applicationId}/${id}`, { environment, body });
|
|
129
|
-
const gaps = overrides.views === undefined
|
|
149
|
+
const gaps = overrides.views === undefined || !resolved
|
|
150
|
+
? []
|
|
151
|
+
: [
|
|
152
|
+
...(resolved.profile.layout.blocksMeaningful ? verticalGapWarnings(body.views, 'LAY-003 (uyarı)') : []),
|
|
153
|
+
...flexSizeWarnings(body.views, 'LAY-007 (uyarı)', 'LAY-008 (uyarı)'),
|
|
154
|
+
...spacingLayerWarnings(body.views, 'LAY-010 (uyarı)', 'LAY-011 (uyarı)'),
|
|
155
|
+
...await screenProfileWarnings(platform, resolved, project, environment, applicationId, { kind: 'layout', nodes: body.views })
|
|
156
|
+
];
|
|
130
157
|
const summary = { id, changed: Object.keys(overrides), preserved: { viewNodes: body.views.length } };
|
|
131
158
|
if (gaps.length > 0)
|
|
132
159
|
summary.layoutWarnings = gaps;
|
|
@@ -180,9 +207,10 @@ export function registerLayoutTools(server, platform) {
|
|
|
180
207
|
const overrides = Object.fromEntries(['name', 'views', 'events', 'parameters']
|
|
181
208
|
.filter(key => patched[key] !== undefined)
|
|
182
209
|
.map(key => [key, patched[key]]));
|
|
183
|
-
|
|
210
|
+
const profile = await resolveProfile(platform, applicationId);
|
|
211
|
+
assertScreenWriteGuards('layout', { schema: overrides.views, events: overrides.events }, profile.profile.platform);
|
|
184
212
|
const fixed = normalizeComponentDefaults(overrides.views);
|
|
185
|
-
const catalogNotes = await
|
|
213
|
+
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, overrides.views, 'layout_patch');
|
|
186
214
|
const body = layoutUpdateBody({ ...current, applicationId }, overrides);
|
|
187
215
|
// Gövde değil FARK gönderilir: gateway normalizasyonları (komponent varsayılanları, katalog
|
|
188
216
|
// kuralları, value'suz olayların elenmesi) son hâle işlendikten sonra net diff hesaplanır.
|
|
@@ -193,7 +221,12 @@ export function registerLayoutTools(server, platform) {
|
|
|
193
221
|
body: { baseVersion: baseVersionOf(document, 'layout_get'), ops: netOps }
|
|
194
222
|
});
|
|
195
223
|
const written = patchResult(saved, finalDocument);
|
|
196
|
-
const gaps = [
|
|
224
|
+
const gaps = [
|
|
225
|
+
...(profile.profile.layout.blocksMeaningful ? verticalGapWarnings(body.views, 'LAY-003 (uyarı)') : []),
|
|
226
|
+
...flexSizeWarnings(body.views, 'LAY-007 (uyarı)', 'LAY-008 (uyarı)'),
|
|
227
|
+
...spacingLayerWarnings(body.views, 'LAY-010 (uyarı)', 'LAY-011 (uyarı)'),
|
|
228
|
+
...await screenProfileWarnings(platform, profile, project, environment, applicationId, { kind: 'layout', nodes: body.views })
|
|
229
|
+
];
|
|
197
230
|
const summary = {
|
|
198
231
|
id,
|
|
199
232
|
applied: patchOps.length,
|
package/dist/tools/merges.js
CHANGED
|
@@ -37,7 +37,7 @@ export function registerMergeTools(server, platform) {
|
|
|
37
37
|
const config = platform.config;
|
|
38
38
|
server.registerTool('merge_plan', {
|
|
39
39
|
title: 'Merge planı oluştur',
|
|
40
|
-
description: "Bir dalı ebeveynine (development) merge etmek için üç yönlü diff planı ister. Hedef her zaman dalın ebeveynidir — production'a merge eden bir yol YOKTUR. title ZORUNLUDUR: isteğin adıdır ve geçmişte o adla durur. Asenkron: yanıt 202 döner, plan hemen dolu değildir. Projede açık bir plan varsa 400 döner; önce onu uygulayın ya da merge_discard ile bırakın.",
|
|
40
|
+
description: "Bir dalı ebeveynine (development) merge etmek için üç yönlü diff planı ister. Hedef her zaman dalın ebeveynidir — production'a merge eden bir yol YOKTUR. title ZORUNLUDUR: isteğin adıdır ve geçmişte o adla durur. Asenkron: yanıt 202 döner, plan hemen dolu değildir. Projede açık bir plan varsa 400 döner; önce onu uygulayın ya da merge_discard ile bırakın. Süreç tanımları ve iş takvimleri planda modül olarak görünür (fark versions[…].model.nodes[<düğüm id>] yolunda); örnekler, görevler, defter ve uyarlamalar merge edilmez.",
|
|
41
41
|
inputSchema: { projectId: guid, sourceEnvironmentId: guid, title: mergeTitle, description: mergeDescription },
|
|
42
42
|
annotations: writes
|
|
43
43
|
}, handle(config, async ({ projectId, sourceEnvironmentId, title, description }) => {
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
import { guid, appRef, withResolved, projectParam, environmentParam, definitionParam, languageParam, pagingParams, readOnly, writes, updates, destructive, microOps } from './common.js';
|
|
1
|
+
import { guid, appRef, withResolved, projectParam, environmentParam, definitionParam, languageParam, pagingParams, asUserIdParam, readOnly, writes, updates, destructive, microOps } from './common.js';
|
|
2
2
|
import { languageHeader } from '../knowledge/languageCodes.js';
|
|
3
3
|
import { hydrateMicroserviceRefs } from '../knowledge/hydrate.js';
|
|
4
4
|
import { RefResolver } from '../platform/refs.js';
|
|
5
5
|
import { normalizeMicroserviceDefinition, normalizeMicroservicePatchOps, withNormalization } from '../knowledge/normalize.js';
|
|
6
6
|
import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
|
|
7
7
|
import { microserviceOutline, workflowOutline, resolvePart, resolvePatchOperations } from '../knowledge/outlines.js';
|
|
8
|
+
import { unresolvedParameterAliases, parameterAliasWarning } from '../knowledge/microserviceParameters.js';
|
|
8
9
|
import { patchResult, baseVersionOf } from '../platform/patch.js';
|
|
9
|
-
import { policyRules } from '../knowledge/rules.js';
|
|
10
|
+
import { filterOperatorError, policyRules } from '../knowledge/rules.js';
|
|
10
11
|
import { writeDiff, withWriteDiff } from '../platform/writeDiff.js';
|
|
11
|
-
import { identityHeaders } from '../platform/tokenVault.js';
|
|
12
|
+
import { identityHeaders, resolveIdentity } from '../platform/tokenVault.js';
|
|
13
|
+
import { impersonationHeaders } from '../platform/impersonation.js';
|
|
14
|
+
import { accessDecisionOf, legacyRoleListFindings, projectAccessContext } from '../knowledge/access.js';
|
|
12
15
|
import { PlatformApiError } from '../platform/errors.js';
|
|
13
16
|
import { existingMatch, ifExistsParam, listAll, platformRename, withOutcome, withRename } from '../platform/ifExists.js';
|
|
14
17
|
import { outlineWrite, recordWriteViewParam } from '../platform/writeView.js';
|
|
15
18
|
import { handle } from '../platform/responses.js';
|
|
19
|
+
import { headersForMode } from '../platform/http.js';
|
|
16
20
|
import fastJsonPatch from 'fast-json-patch';
|
|
21
|
+
import { jsonArray } from '../platform/jsonArray.js';
|
|
17
22
|
import { z } from 'zod';
|
|
18
23
|
import { constraintSummary } from '../knowledge/backendConstraints.js';
|
|
19
24
|
import { unmappedMembers, introducedUnmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
|
|
@@ -66,9 +71,9 @@ async function queryScopeFindings(platform, project, environment, definition) {
|
|
|
66
71
|
}]
|
|
67
72
|
: [];
|
|
68
73
|
}
|
|
69
|
-
const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
|
|
74
|
+
const patchOperationsParam = jsonArray(z.array(z.record(z.unknown())).min(1))
|
|
70
75
|
.describe("RFC 6902 JSON Patch işlemleri; path'leri view:'outline'/'part' ile keşfedin. Dizi öğelerinde indeks yerine seçici kullanılabilir: '/sourceParameters/joins[alias=customers]/path' — seçici gövde platforma gitmeden indekse çevrilir, çözülemezse istek hiç gönderilmez.");
|
|
71
|
-
const asUserParam = z.string().min(1).optional().describe("Uygulama üyesinin kimliği: istek gateway'in servis jetonu yerine bu kimlikle gider. Jeton HEM Authorization başlığında HEM NG_AccessToken çerezinde taşınır, böylece jetonu ÇEREZDEN okuyan middleware de geçer — uca middleware bağlandığı anda bu alan olmadan çağrı 401 döner (09-05 koşusu S-21).
|
|
76
|
+
const asUserParam = z.string().min(1).optional().describe("Uygulama üyesinin kimliği: istek gateway'in servis jetonu yerine bu kimlikle gider. Jeton HEM Authorization başlığında HEM NG_AccessToken çerezinde taşınır, böylece jetonu ÇEREZDEN okuyan middleware de geçer — uca middleware bağlandığı anda bu alan olmadan çağrı 401 döner (09-05 koşusu S-21). KOMPLEKS PROJEDE referans access_session_create'ten gelir: jeton Bearer olarak gider, platform Bearer'lı isteğe CSRF sormaz (ZY_App_ çerezi kurulmaz — çerezle gelen durum değiştiren istek X-ZY-CSRF ister); microservice_preview bir Studio ucudur ve uygulama jetonuyla sınanamaz, uygulama kullanıcısı olarak microservice_execute / microservice_debug kullanın. ÜÇ ŞEKİL kabul edilir: (1) TERCİH EDİLEN `test:<ad>` — gateway kök .env'deki MCP_TEST_USER_<AD> satırıyla giriş ucunu kendisi çağırır, jetonu kasadan yeniden kullanır (satırı insan yazar), (2) `tok_…` referansı (giriş ucunu çağırdığınızda yanıtın tokenRefs alanında döner; ömür MCP_TOKEN_TTL_MINUTES, MCP_STATE_DIR varsa gateway yeniden başlayınca da çözülür), (3) ham JWT. anonymous ile birlikte verilemez.");
|
|
72
77
|
const cookiesParam = z.record(z.string()).optional().describe("İsteğe eklenecek çerezler (ad → değer): uygulamanın KENDİ oturum çerezi buraya verilir (ör. { CORE_Token: '<jwt>' }). asUser verildiğinde gateway NG_AccessToken çerezini zaten kendisi kurar; bu alan yalnız uygulama başka bir çerez adı okuyorsa gerekir. anonymous ile birlikte verilemez.");
|
|
73
78
|
const executeInput = {
|
|
74
79
|
project: projectParam,
|
|
@@ -85,6 +90,7 @@ const executeInput = {
|
|
|
85
90
|
headers: z.record(z.string()).optional().describe("İsteğe eklenecek header'lar. 'Authorization' verirseniz gateway KENDİ token'ını KOYMAZ — istek tamamen sizin kimliğinizle gider (middleware'li uçları üye token'ıyla test etmenin yolu budur)"),
|
|
86
91
|
anonymous: z.boolean().optional().describe("true: istek HİÇBİR Authorization header'ı olmadan gider — 'korumalı uç tokensız ne döner?' sorusunun cevabı budur (korumalı uçtan 401, anonim uçtan 200 beklenir). Gateway normalde her çağrıya kendi token'ını koyduğu için bu bayrak olmadan anonim erişim testi yapılamaz."),
|
|
87
92
|
asUser: asUserParam,
|
|
93
|
+
asUserId: asUserIdParam,
|
|
88
94
|
cookies: cookiesParam,
|
|
89
95
|
language: languageParam,
|
|
90
96
|
expectFailure: z.boolean().optional().describe("true: bu çağrıda bir hata dönmesi BEKLENİYOR (kasıtlı negatif test — yanlış parola, yetkisiz erişim, geçersiz gövde). Yanıt yine httpStatus'u/hatayı taşır, ama ölçüm aracı bu satırı plansız hata saymaz (page_screenshot'taki expectFailure deseniyle aynı).")
|
|
@@ -99,6 +105,9 @@ function runIdentity(anonymous, asUser, cookies, headers) {
|
|
|
99
105
|
}
|
|
100
106
|
return identityHeaders(asUser, cookies, headers);
|
|
101
107
|
}
|
|
108
|
+
function hasAuthorization(headers) {
|
|
109
|
+
return Object.keys(headers ?? {}).some(name => name.toLowerCase() === 'authorization');
|
|
110
|
+
}
|
|
102
111
|
/**
|
|
103
112
|
* Debug çıktısındaki `executionItems` ucun kendi adımlarıdır; middleware AYRI bir workflow olarak
|
|
104
113
|
* ucun ÖNÜNDE koşar ve ağaçta hiç görünmez — 09-04 koşusunda sessizce açık kalan şirket kapısı
|
|
@@ -189,17 +198,27 @@ function unboundQueryParameters(value, into = []) {
|
|
|
189
198
|
unboundQueryParameters(entry, into);
|
|
190
199
|
return into;
|
|
191
200
|
}
|
|
201
|
+
/** Çağrının dinamik filtresi (`filters`, sorguda ya da gövdede) bilinen işleçlerle mi — değilse istek gitmez (g-03). */
|
|
202
|
+
function assertFilterOperators(tool, bound) {
|
|
203
|
+
const bodyFilters = bound.body && !Array.isArray(bound.body) ? bound.body.filters : undefined;
|
|
204
|
+
const error = filterOperatorError(tool, bound.query?.filters) ?? filterOperatorError(tool, bodyFilters);
|
|
205
|
+
if (error)
|
|
206
|
+
throw new PlatformApiError(error, 400);
|
|
207
|
+
}
|
|
192
208
|
function executePath(prefix, application, microservice, routeParams) {
|
|
193
209
|
const routeSuffix = routeParams && routeParams.length > 0
|
|
194
210
|
? `/${routeParams.map(encodeURIComponent).join('/')}`
|
|
195
211
|
: '';
|
|
196
212
|
return `/${prefix}/${application}/${microservice}${routeSuffix}`;
|
|
197
213
|
}
|
|
198
|
-
/**
|
|
214
|
+
/**
|
|
215
|
+
* Slug application_update ile değişebildiği için önbellek kısa ömürlüdür (yalnız aynı turdaki tekrar okumaları ucuzlatır);
|
|
216
|
+
* runtime yolu 404 dönen çağıran `fresh: true` ile önbelleği atlar. Org API'nin 404 dışı hatası (yetki, ağ) çağırana gider.
|
|
217
|
+
*/
|
|
199
218
|
const APPLICATION_SLUG_TTL_MS = 60_000;
|
|
200
219
|
const applicationSlugCache = new Map();
|
|
201
|
-
async function applicationSlug(platform, applicationId) {
|
|
202
|
-
const cached = applicationSlugCache.get(applicationId);
|
|
220
|
+
export async function applicationSlug(platform, applicationId, options = {}) {
|
|
221
|
+
const cached = options.fresh ? undefined : applicationSlugCache.get(applicationId);
|
|
203
222
|
if (cached && cached.expiresAt > Date.now())
|
|
204
223
|
return cached.slug;
|
|
205
224
|
try {
|
|
@@ -210,8 +229,10 @@ async function applicationSlug(platform, applicationId) {
|
|
|
210
229
|
applicationSlugCache.set(applicationId, { slug, expiresAt: Date.now() + APPLICATION_SLUG_TTL_MS });
|
|
211
230
|
return slug;
|
|
212
231
|
}
|
|
213
|
-
catch {
|
|
214
|
-
|
|
232
|
+
catch (error) {
|
|
233
|
+
if (error instanceof PlatformApiError && error.status === 404)
|
|
234
|
+
return undefined;
|
|
235
|
+
throw error;
|
|
215
236
|
}
|
|
216
237
|
}
|
|
217
238
|
/**
|
|
@@ -241,6 +262,12 @@ async function resolveRuntimeUrl(platform, project, environment, applicationId,
|
|
|
241
262
|
}
|
|
242
263
|
export function registerMicroserviceTools(server, platform) {
|
|
243
264
|
const config = platform.config;
|
|
265
|
+
server.registerTool('microservice_system_operation_list', {
|
|
266
|
+
title: 'Sistem operasyonlarını listele',
|
|
267
|
+
description: "Bir microservice'in systemOperation alanına konabilecek hazır platform operasyonlarının kataloğunu döner (GET /{project}/microservices/system-operations): operasyon adı, karar motorunun soracağı izin, kaynak tipi, beklediği parametreler ve açıklaması. Sistem operasyonlu uç kendi adımlarını yazmaz — platformun hazır davranışını (ör. satır sahibini değiştirme, maskeli alan açma, uygulama girişi) uygulamanın kendi ucu gibi yayınlar. Her satırın 'guard' alanı korumayı söyler: 'permission' → oturum + buradaki permission karara bağlanır; permission BOŞ olan 'permission' satırında izni işlemin çağırdığı servis verir (ADR-0004): süreç çalışma zamanı işlemleri (process.* — görev kutusu ve eylemleri, process.task.sign dahil; örnek, vekalet, devir, bildirim, tercih, rapor) kişiye ve kayda göre karar verir, REST bpm/* ucuyla aynı görünürlüğü ve aynı alan adlarını döner; yalnız process.override.* process.manage ister; 'session' → operasyon izin sormaz, yalnız oturum ister (ör. access.session.get: oturumdaki kullanıcı; uç anonim değilse microservice.execute kararı yine uygulanır); 'anonymous' → oturum da izin de sorulmaz (access.session.create: giriş; girdi yalnız gövdeden okunur, çerezler yalnız application/json istekte yazılır, gövdede jeton dönmez) ve uç isAnonymous:true olmak zorundadır, önizlemede çalışmaz. Süreç ekranı process.* işlemleriyle kurulur, Page.bpm ile değil (BPM-022); kod adımından platform ucuna ham fetch yerine bu uçlar kullanılır (FLOW-028). Katalog sabittir, projeye göre değişmez.",
|
|
268
|
+
inputSchema: { project: projectParam, environment: environmentParam },
|
|
269
|
+
annotations: readOnly
|
|
270
|
+
}, handle(config, ({ project, environment }) => platform.tenant('GET', project, '/microservices/system-operations', { environment })));
|
|
244
271
|
server.registerTool('microservice_list', {
|
|
245
272
|
title: 'Microservice listele',
|
|
246
273
|
description: 'Application altındaki microservice\'leri listeler.',
|
|
@@ -264,7 +291,7 @@ export function registerMicroserviceTools(server, platform) {
|
|
|
264
291
|
}));
|
|
265
292
|
server.registerTool('microservice_get', {
|
|
266
293
|
title: 'Microservice getir',
|
|
267
|
-
description: "Microservice tanımını getirir. Büyük tanımda önce view:'outline' (kaynak/alan özeti), sonra view:'part' ile tek parça çekin.",
|
|
294
|
+
description: "Microservice tanımını getirir. Büyük tanımda önce view:'outline' (kaynak/alan özeti), sonra view:'part' ile tek parça çekin. parameterScheme[].name ÇAĞRI PARAMETRESİNİN adıdır ve tablo kaynaklı uçta kök filtre için nitelenmemiş alan slug'ıdır ('id'); nitelikli bir ad ('kredi.id') yalnız JOIN alias'ıyla meşrudur — join değilse o filtre runtime'da hiç çözülmez ve yanıt MS-023 uyarısını taşır (TB-119).",
|
|
268
295
|
inputSchema: {
|
|
269
296
|
project: projectParam,
|
|
270
297
|
environment: environmentParam,
|
|
@@ -285,9 +312,16 @@ export function registerMicroserviceTools(server, platform) {
|
|
|
285
312
|
return withResolved({ part, value: resolvePart(definition, part) }, resolver.resolved);
|
|
286
313
|
}
|
|
287
314
|
const resolvedUrl = await resolveRuntimeUrl(platform, project, environment, resolvedApplicationId, definition);
|
|
315
|
+
// MS-023 — entity slug'ı YALNIZ kusur varken okunur: sağlam uçta fazladan istek atılmaz.
|
|
316
|
+
const unresolved = unresolvedParameterAliases(definition);
|
|
317
|
+
const entitySlug = unresolved.length === 0 || typeof definition.entityId !== 'string'
|
|
318
|
+
? undefined
|
|
319
|
+
: await resolver.entity(definition.entityId).then(entity => entity.slug).catch(() => undefined);
|
|
320
|
+
const warning = parameterAliasWarning(unresolved, entitySlug);
|
|
321
|
+
const parameterWarnings = warning === undefined ? {} : { parameterWarnings: [warning] };
|
|
288
322
|
if (view === 'outline')
|
|
289
|
-
return withResolved({ ...microserviceOutline(definition), resolvedUrl }, resolver.resolved);
|
|
290
|
-
return withResolved({ ...payload, resolvedUrl }, resolver.resolved);
|
|
323
|
+
return withResolved({ ...microserviceOutline(definition), resolvedUrl, ...parameterWarnings }, resolver.resolved);
|
|
324
|
+
return withResolved({ ...payload, resolvedUrl, ...parameterWarnings }, resolver.resolved);
|
|
291
325
|
}));
|
|
292
326
|
server.registerTool('microservice_create', {
|
|
293
327
|
title: 'Microservice oluştur',
|
|
@@ -321,7 +355,8 @@ export function registerMicroserviceTools(server, platform) {
|
|
|
321
355
|
...(existing === undefined
|
|
322
356
|
? createFindings
|
|
323
357
|
: enforcePolicy(evaluatePolicy(config, policyRules, 'microservice', definition, { operation: 'update' }, policyOverride))),
|
|
324
|
-
...scopeFindings
|
|
358
|
+
...scopeFindings,
|
|
359
|
+
...await legacyRoleListFindings(platform, project, environment, definition, 'microservice', policyOverride)
|
|
325
360
|
];
|
|
326
361
|
const drift = unmappedMembers(existing === undefined ? 'CreateMicroserviceCommand' : 'UpdateMicroserviceCommand', definition);
|
|
327
362
|
const payload = existing === undefined
|
|
@@ -343,7 +378,8 @@ export function registerMicroserviceTools(server, platform) {
|
|
|
343
378
|
const normalized = normalizeMicroserviceDefinition(definition);
|
|
344
379
|
const findings = [
|
|
345
380
|
...enforcePolicy(evaluatePolicy(config, policyRules, 'microservice', definition, { operation: 'update' }, policyOverride)),
|
|
346
|
-
...await queryScopeFindings(platform, project, environment, definition)
|
|
381
|
+
...await queryScopeFindings(platform, project, environment, definition),
|
|
382
|
+
...await legacyRoleListFindings(platform, project, environment, definition, 'microservice', policyOverride)
|
|
347
383
|
];
|
|
348
384
|
const drift = unmappedMembers('UpdateMicroserviceCommand', definition);
|
|
349
385
|
const payload = await platform.tenant('PUT', project, `/microservices/${resolvedApplicationId}/${id}`, { environment, body: definition });
|
|
@@ -406,26 +442,41 @@ export function registerMicroserviceTools(server, platform) {
|
|
|
406
442
|
}, handle(config, ({ project, environment, id }) => platform.tenant('POST', project, `/microservices/${id}/clone`, { environment })));
|
|
407
443
|
server.registerTool('microservice_execute', {
|
|
408
444
|
title: 'Microservice çalıştır',
|
|
409
|
-
description: "Kayıtlı microservice'i gerçek runtime yolundan çalıştırır (POST /{project}/m/{application}/{microservice SLUG'ı}). Dönen httpStatus microservice'in kendi sonucudur (hata da geçerli çıktıdır); beklenmedik sonuçta microservice_debug ile adım adım inceleyin. Anonim erişim testi için anonymous: true. Yanıt 'headers'
|
|
410
|
-
inputSchema:
|
|
445
|
+
description: "Kayıtlı microservice'i gerçek runtime yolundan çalıştırır (POST /{project}/m/{application}/{microservice SLUG'ı}). Dönen httpStatus microservice'in kendi sonucudur (hata da geçerli çıktıdır); beklenmedik sonuçta microservice_debug ile adım adım inceleyin. Anonim erişim testi için anonymous: true. KOMPLEKS PROJEDE gateway kimliği uygulama öznesi değildir (enforce'ta 401 AppSessionRequired): kullanıcı gözüyle çalıştırmak için asUserId (parolasız, users satır id'si; yalnız development/dal — production'da istek gönderilmez) ya da oturum açılmış üye için asUser. Yanıt 'headers' alanı VARSAYILAN OLARAK yalnız iş başlıklarını taşır (küçük harf): content-type, content-length, content-disposition, location, total-count (sayfalı tablo akışlarının okuduğu sözleşme), x-request-id, traceparent. Ucun response adımında kendi yazdığı başlıkları ya da sunucu başlıklarını görmek için includeHeaders:'all'; hiç başlık istemiyorsanız 'none'. set-cookie/authorization her kipte elenir.",
|
|
446
|
+
inputSchema: {
|
|
447
|
+
...executeInput,
|
|
448
|
+
includeHeaders: z.enum(['none', 'essential', 'all']).optional().describe("Yanıttaki 'headers' alanı. essential (varsayılan): content-type, content-length, content-disposition, location, total-count, x-request-id, traceparent. all: platformun döndüğü bütün başlıklar (gizliler hariç) — ucun kendi yazdığı başlığı doğrulamak için. none: başlık yok")
|
|
449
|
+
},
|
|
411
450
|
annotations: writes
|
|
412
|
-
}, handle(config, async ({ project, environment, application, microservice, method, routeParams, query, body, parameters, headers, anonymous, asUser, cookies, language }) => {
|
|
451
|
+
}, handle(config, async ({ project, environment, application, microservice, method, routeParams, query, body, parameters, headers, anonymous, asUser, asUserId, cookies, language, includeHeaders }) => {
|
|
413
452
|
const notes = [];
|
|
414
|
-
const
|
|
453
|
+
const eye = await impersonationHeaders(platform, 'microservice_execute', project, environment, { asUserId, asUser, anonymous, ownAuthorization: hasAuthorization(headers) }, { runtime: true });
|
|
454
|
+
const member = anonymous === true ? asUser : await resolveIdentity(asUser, platform, project, environment);
|
|
455
|
+
const requestHeaders = { ...runIdentity(anonymous, member, cookies, headers), ...eye, ...languageHeader(language, notes) };
|
|
415
456
|
const bound = bindCallParameters(method, parameters, query, body, notes);
|
|
416
|
-
|
|
457
|
+
assertFilterOperators('microservice_execute', bound);
|
|
458
|
+
const raw = await platform.tenantRaw(method, project, executePath('m', application, microservice, routeParams), { environment, query: bound.query, body: bound.body, headers: requestHeaders, anonymous, mirrorAuthorizationCookie: true });
|
|
459
|
+
return withNormalization({ ...raw, headers: headersForMode(raw.headers, includeHeaders ?? 'essential') }, notes);
|
|
417
460
|
}));
|
|
418
461
|
server.registerTool('microservice_debug', {
|
|
419
462
|
title: 'Microservice debug',
|
|
420
|
-
description: "Microservice'i debug modunda çalıştırır; yanıtta adım adım executionItems ağacı döner (her adımın girdi/çıktısı). executionItems YALNIZ ucun kendi adımlarını kapsar — ucun ÖNÜNDE koşan middleware'ler ayrıca 'middlewares' alanında adım özetiyle listelenir (09-04 Y-04). Değeri NULL bağlanan query parametreleri 'unboundParameters' alanında adıyla listelenir (ağaçta bu satırların value anahtarı görünmez). Preview semantiğiyle koşar: tek transaction + sonunda rollback, kalıcı satır yazmaz. httpStatus akışın kendi sonucudur (4xx/5xx'te runtimeErrors eklenir); ağaç düğümlerinde hata bayrağı YOKTUR — patlayan adımın output'u boştur, hata gövdesi hata dalındaki response adımının çıktısındadır. Zamanlanmış (schedule-job) uçlar da slug yoluyla debug edilir (method: 'POST', parametresiz): job geçmişi hatayı yalnız mesaj olarak yazar, adım adım girdi/çıktı burada görülür (platform_guide('microservice') §Zamanlanmış işin gerçek sonucunu görmek).",
|
|
463
|
+
description: "Microservice'i debug modunda çalıştırır; yanıtta adım adım executionItems ağacı döner (her adımın girdi/çıktısı). executionItems YALNIZ ucun kendi adımlarını kapsar — ucun ÖNÜNDE koşan middleware'ler ayrıca 'middlewares' alanında adım özetiyle listelenir (09-04 Y-04). Değeri NULL bağlanan query parametreleri 'unboundParameters' alanında adıyla listelenir (ağaçta bu satırların value anahtarı görünmez). Preview semantiğiyle koşar: tek transaction + sonunda rollback, kalıcı satır yazmaz. httpStatus akışın kendi sonucudur (4xx/5xx'te runtimeErrors eklenir); ağaç düğümlerinde hata bayrağı YOKTUR — patlayan adımın output'u boştur, hata gövdesi hata dalındaki response adımının çıktısındadır. Zamanlanmış (schedule-job) uçlar da slug yoluyla debug edilir (method: 'POST', parametresiz): job geçmişi hatayı yalnız mesaj olarak yazar, adım adım girdi/çıktı burada görülür (platform_guide('microservice') §Zamanlanmış işin gerçek sonucunu görmek). Kompleks projede kullanıcı gözü asUserId (parolasız) ya da asUser ile verilir ve yanıta 'accessDecision' eklenir: { decision: allow | deny | not-enforced | unknown, mode, code?, permission?, reason, next } — 401/403'ün erişim kararından mı geldiğini ve sıradaki adımı söyler.",
|
|
421
464
|
inputSchema: executeInput,
|
|
422
465
|
annotations: writes
|
|
423
|
-
}, handle(config, async ({ project, environment, application, microservice, method, routeParams, query, body, parameters, headers, anonymous, asUser, cookies, language }) => {
|
|
466
|
+
}, handle(config, async ({ project, environment, application, microservice, method, routeParams, query, body, parameters, headers, anonymous, asUser, asUserId, cookies, language }) => {
|
|
424
467
|
const notes = [];
|
|
425
|
-
const
|
|
468
|
+
const eye = await impersonationHeaders(platform, 'microservice_debug', project, environment, { asUserId, asUser, anonymous, ownAuthorization: hasAuthorization(headers) }, { runtime: true });
|
|
469
|
+
const member = anonymous === true ? asUser : await resolveIdentity(asUser, platform, project, environment);
|
|
470
|
+
const requestHeaders = { ...runIdentity(anonymous, member, cookies, headers), ...eye, ...languageHeader(language, notes) };
|
|
426
471
|
const bound = bindCallParameters(method, parameters, query, body, notes);
|
|
472
|
+
assertFilterOperators('microservice_debug', bound);
|
|
427
473
|
const payload = await platform.tenantRaw(method, project, executePath('debug', application, microservice, routeParams), { environment, query: bound.query, body: bound.body, headers: requestHeaders, anonymous, mirrorAuthorizationCookie: true });
|
|
428
474
|
const unbound = unboundQueryParameters(payload.body);
|
|
475
|
+
const chain = await middlewareChain(platform, project, environment, application, microservice, payload.httpStatus);
|
|
476
|
+
// Karar yanıtta ayrı alan olarak gelmez: kompleks projede hata kodundan ve ortamın modundan türetilir
|
|
477
|
+
// (g-31). Proje okuması zincirden SONRA yapılır; basit projede alan hiç eklenmez.
|
|
478
|
+
const errorBody = (payload.body && typeof payload.body === 'object' ? payload.body : {});
|
|
479
|
+
const decision = accessDecisionOf(await projectAccessContext(platform, project, environment), payload.httpStatus, errorBody.code, errorBody.message);
|
|
429
480
|
return withNormalization({
|
|
430
481
|
...payload,
|
|
431
482
|
...(unbound.length > 0
|
|
@@ -434,7 +485,8 @@ export function registerMicroserviceTools(server, platform) {
|
|
|
434
485
|
unboundParametersNote: "Bu query parametreleri NULL bağlandı: çağrıda yoklar ya da değerleri boş string'di (platform boş string'i NULL'a çevirir). Parametreyi 'parameters' (ya da GET'te 'query', POST/PUT'ta 'body') ile verin; ad sorgunun parametre adıyla birebir aynı olmalı."
|
|
435
486
|
}
|
|
436
487
|
: {}),
|
|
437
|
-
...
|
|
488
|
+
...chain,
|
|
489
|
+
...(decision ? { accessDecision: decision } : {})
|
|
438
490
|
}, notes);
|
|
439
491
|
}));
|
|
440
492
|
server.registerTool('microservice_preview', {
|
|
@@ -474,7 +526,7 @@ export function registerMicroserviceTools(server, platform) {
|
|
|
474
526
|
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'microservice', definition, { operation: 'preview' }, policyOverride));
|
|
475
527
|
// Önizleme de ucun middleware'lerini koşturur: kimlik verilmezse korumalı uç 401 döner ve kuru
|
|
476
528
|
// koşu aracı tam gerektiği anda kullanılamaz hâle gelir (09-05 koşusu S-21).
|
|
477
|
-
const payload = await platform.tenantRaw('POST', project, `/microservices/${resolvedApplicationId}/preview`, { environment, body: definition, headers: { ...identityHeaders(asUser, cookies, undefined), ...languageHeader(language, normalized) }, mirrorAuthorizationCookie: true });
|
|
529
|
+
const payload = await platform.tenantRaw('POST', project, `/microservices/${resolvedApplicationId}/preview`, { environment, body: definition, headers: { ...identityHeaders(await resolveIdentity(asUser, platform, project, environment), cookies, undefined), ...languageHeader(language, normalized) }, mirrorAuthorizationCookie: true });
|
|
478
530
|
return attachFindings(withResolved(withNormalization(payload, normalized), [...resolver.resolved, ...hydrated]), findings);
|
|
479
531
|
}));
|
|
480
532
|
server.registerTool('microservice_job_history', {
|