@appaflytech/zeyrek-ai-mcp 0.0.36 → 0.0.40
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 +524 -53
- package/dist/knowledge/componentEvents.js +132 -7
- package/dist/knowledge/connectDataBind.js +851 -0
- package/dist/knowledge/connectDataDefinition.js +344 -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 +60 -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 +876 -0
- package/dist/knowledge/mobileComponentEvents.js +259 -0
- package/dist/knowledge/mobileStore.js +396 -0
- package/dist/knowledge/normalize.js +240 -72
- 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 +485 -22
- package/dist/knowledge/schemaGuard.js +11 -0
- package/dist/knowledge/styleResolve.js +64 -10
- package/dist/knowledge/styleResolveNative.js +529 -0
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/observability/trace.js +13 -5
- package/dist/platform/argumentAliases.js +128 -0
- package/dist/platform/bodyFile.js +103 -0
- package/dist/platform/capture/actions.js +398 -0
- package/dist/platform/capture/browser.js +1 -0
- package/dist/platform/capture/capture.js +683 -0
- 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 +163 -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 +68 -2
- 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/middleware-authenticate.json +1 -1
- package/dist/resources/examples/mobile-app-shell-drawer.json +244 -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 +703 -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 +810 -0
- package/dist/resources/guides/bpm.md +691 -0
- package/dist/resources/guides/case.md +153 -0
- package/dist/resources/guides/component.md +92 -5
- 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/merge.md +42 -7
- package/dist/resources/guides/microservice.md +88 -3
- package/dist/resources/guides/middleware.md +69 -5
- package/dist/resources/guides/mobile-layout.md +193 -0
- package/dist/resources/guides/mobile-publish.md +148 -0
- package/dist/resources/guides/mobile.md +565 -0
- package/dist/resources/guides/page.md +469 -82
- 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 +146 -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 +24 -0
- package/dist/resources/schemas/MicroserviceDto.json +15 -3
- package/dist/resources/schemas/OrganizationProjectDto.json +343 -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 +25 -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/StartMobileBuildCommand.json +54 -0
- package/dist/resources/schemas/StepDto.json +25 -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 +146 -1
- package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +333 -0
- package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
- package/dist/server.js +31 -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 +63 -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 +19 -6
- package/dist/tools/components.js +118 -14
- package/dist/tools/connectData.js +450 -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 +38 -3
- package/dist/tools/designSchemaPatch.js +34 -9
- package/dist/tools/dtos.js +36 -5
- package/dist/tools/entities.js +79 -12
- package/dist/tools/environments.js +1 -1
- package/dist/tools/externalComponents.js +26 -5
- package/dist/tools/flows.js +119 -13
- 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 +2 -2
- package/dist/tools/microservices.js +77 -25
- package/dist/tools/mobile.js +280 -0
- package/dist/tools/mobileStore.js +572 -0
- package/dist/tools/modules.js +48 -0
- package/dist/tools/organizationStructure.js +137 -0
- package/dist/tools/pages.js +467 -100
- package/dist/tools/platformInfo.js +28 -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 +36 -7
- 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/platform/screenshot.js +0 -1162
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 { fillComponentNames, componentNameNote, 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ı: her düğümde elementId, name (= elementId), type, blocks zorunlu — blocks: [{ breakpoint: 1024, size: { w, h }, position: { x, y } }], gateway doldurmaz (PAGE-037). 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,20 +100,29 @@ export function registerLayoutTools(server, platform) {
|
|
|
90
100
|
},
|
|
91
101
|
annotations: writes
|
|
92
102
|
}, handle(config, async ({ project, environment, applicationId, name, views, events, parameters }) => {
|
|
103
|
+
const resolved = await resolveProfile(platform, applicationId);
|
|
93
104
|
const named = fillComponentNames(views);
|
|
94
|
-
assertScreenWriteGuards('layout', { schema: views, events });
|
|
105
|
+
assertScreenWriteGuards('layout', { schema: views, events }, resolved.profile.platform);
|
|
95
106
|
const fixed = normalizeComponentDefaults(views);
|
|
96
|
-
const catalogNotes = await
|
|
97
|
-
const gaps = [
|
|
107
|
+
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, views, 'layout_create');
|
|
108
|
+
const gaps = [
|
|
109
|
+
...(resolved.profile.layout.blocksMeaningful ? verticalGapWarnings(views ?? [], 'LAY-003 (uyarı)') : []),
|
|
110
|
+
...flexSizeWarnings(views ?? [], 'LAY-007 (uyarı)', 'LAY-008 (uyarı)'),
|
|
111
|
+
...spacingLayerWarnings(views ?? [], 'LAY-010 (uyarı)', 'LAY-011 (uyarı)'),
|
|
112
|
+
...await screenProfileWarnings(platform, resolved, project, environment, applicationId, { kind: 'layout', nodes: views ?? [] })
|
|
113
|
+
];
|
|
98
114
|
const response = await platform.tenant('POST', project, `/layouts/${applicationId}`, {
|
|
99
115
|
environment,
|
|
100
116
|
body: { name, views: views ?? [], events: events ?? [], parameters: parameters ?? null }
|
|
101
117
|
});
|
|
102
118
|
const drops = writeDiff({ name, views: views ?? [], events: events ?? [] }, response);
|
|
103
119
|
const normalized = withWriteDiff(withNormalization(response, [...componentNameNote(named), ...componentDefaultsNote(fixed), ...catalogNotes, ...slotWarning(views)]), drops);
|
|
104
|
-
|
|
120
|
+
const typeField = applicationTypeField(resolved);
|
|
121
|
+
if (!normalized || typeof normalized !== 'object')
|
|
105
122
|
return normalized;
|
|
106
|
-
|
|
123
|
+
if (gaps.length === 0)
|
|
124
|
+
return Object.keys(typeField).length === 0 ? normalized : { ...normalized, ...typeField };
|
|
125
|
+
return { ...normalized, ...typeField, layoutWarnings: gaps };
|
|
107
126
|
}));
|
|
108
127
|
server.registerTool('layout_update', {
|
|
109
128
|
title: 'Layout güncelle',
|
|
@@ -121,14 +140,22 @@ export function registerLayoutTools(server, platform) {
|
|
|
121
140
|
annotations: updates
|
|
122
141
|
}, handle(config, async ({ project, environment, applicationId, id, ...changes }) => {
|
|
123
142
|
const overrides = Object.fromEntries(Object.entries(changes).filter(([, value]) => value !== undefined));
|
|
143
|
+
const resolved = overrides.views === undefined ? undefined : await resolveProfile(platform, applicationId);
|
|
124
144
|
const named = fillComponentNames(overrides.views);
|
|
125
|
-
assertScreenWriteGuards('layout', { schema: overrides.views, events: overrides.events });
|
|
145
|
+
assertScreenWriteGuards('layout', { schema: overrides.views, events: overrides.events }, resolved?.profile.platform);
|
|
126
146
|
const current = await fetchHost(platform, 'layout', project, environment, applicationId, id);
|
|
127
147
|
const fixed = normalizeComponentDefaults(overrides.views);
|
|
128
|
-
const catalogNotes = await
|
|
148
|
+
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, overrides.views, 'layout_update');
|
|
129
149
|
const body = layoutUpdateBody({ ...current, applicationId }, overrides);
|
|
130
150
|
await platform.tenant('PUT', project, `/layouts/${applicationId}/${id}`, { environment, body });
|
|
131
|
-
const gaps = overrides.views === undefined
|
|
151
|
+
const gaps = overrides.views === undefined || !resolved
|
|
152
|
+
? []
|
|
153
|
+
: [
|
|
154
|
+
...(resolved.profile.layout.blocksMeaningful ? verticalGapWarnings(body.views, 'LAY-003 (uyarı)') : []),
|
|
155
|
+
...flexSizeWarnings(body.views, 'LAY-007 (uyarı)', 'LAY-008 (uyarı)'),
|
|
156
|
+
...spacingLayerWarnings(body.views, 'LAY-010 (uyarı)', 'LAY-011 (uyarı)'),
|
|
157
|
+
...await screenProfileWarnings(platform, resolved, project, environment, applicationId, { kind: 'layout', nodes: body.views })
|
|
158
|
+
];
|
|
132
159
|
const summary = { id, changed: Object.keys(overrides), preserved: { viewNodes: body.views.length } };
|
|
133
160
|
if (gaps.length > 0)
|
|
134
161
|
summary.layoutWarnings = gaps;
|
|
@@ -182,10 +209,11 @@ export function registerLayoutTools(server, platform) {
|
|
|
182
209
|
const overrides = Object.fromEntries(['name', 'views', 'events', 'parameters']
|
|
183
210
|
.filter(key => patched[key] !== undefined)
|
|
184
211
|
.map(key => [key, patched[key]]));
|
|
212
|
+
const profile = await resolveProfile(platform, applicationId);
|
|
185
213
|
const named = fillComponentNames(overrides.views);
|
|
186
|
-
assertScreenWriteGuards('layout', { schema: overrides.views, events: overrides.events });
|
|
214
|
+
assertScreenWriteGuards('layout', { schema: overrides.views, events: overrides.events }, profile.profile.platform);
|
|
187
215
|
const fixed = normalizeComponentDefaults(overrides.views);
|
|
188
|
-
const catalogNotes = await
|
|
216
|
+
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, overrides.views, 'layout_patch');
|
|
189
217
|
const body = layoutUpdateBody({ ...current, applicationId }, overrides);
|
|
190
218
|
// Gövde değil FARK gönderilir: gateway normalizasyonları (komponent varsayılanları, katalog
|
|
191
219
|
// kuralları, value'suz olayların elenmesi) son hâle işlendikten sonra net diff hesaplanır.
|
|
@@ -196,7 +224,12 @@ export function registerLayoutTools(server, platform) {
|
|
|
196
224
|
body: { baseVersion: baseVersionOf(document, 'layout_get'), ops: netOps }
|
|
197
225
|
});
|
|
198
226
|
const written = patchResult(saved, finalDocument);
|
|
199
|
-
const gaps = [
|
|
227
|
+
const gaps = [
|
|
228
|
+
...(profile.profile.layout.blocksMeaningful ? verticalGapWarnings(body.views, 'LAY-003 (uyarı)') : []),
|
|
229
|
+
...flexSizeWarnings(body.views, 'LAY-007 (uyarı)', 'LAY-008 (uyarı)'),
|
|
230
|
+
...spacingLayerWarnings(body.views, 'LAY-010 (uyarı)', 'LAY-011 (uyarı)'),
|
|
231
|
+
...await screenProfileWarnings(platform, profile, project, environment, applicationId, { kind: 'layout', nodes: body.views })
|
|
232
|
+
];
|
|
200
233
|
const summary = {
|
|
201
234
|
id,
|
|
202
235
|
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 }) => {
|
|
@@ -55,7 +55,7 @@ export function registerMergeTools(server, platform) {
|
|
|
55
55
|
}, handle(config, ({ projectId, ...query }) => platform.org('GET', `/merges/${projectId}`, { query })));
|
|
56
56
|
server.registerTool('merge_get', {
|
|
57
57
|
title: 'Merge planını oku',
|
|
58
|
-
description: "Bir merge planını döner. items[] yalnız DEĞİŞEN kayıtları taşır; her kayıtta kind (add|update|delete|conflict) ve elements[] vardır. Çakışan elemanlarda base/source/target üç değeri birden gelir. dataRisk: true olan kalemde SEBEP dataRiskReasons[] içindedir: 'field-removed' (alan siliniyor), 'field-narrowed' (tip/nullable/unique daraltılıyor), 'not-null-without-default-on-populated-table' (hedefte satır varken varsayılansız NOT NULL alan ekleniyor — bu apply'ı DDL aşamasında düşürür, alanı nullable yapın ya da varsayılan verin). dataRisk bir UYARIDIR, apply'ı bloklamaz. derivedFromKey dolu olan kalem OTOMATİK ÜRETİLMİŞ bir kayıttır (varsayılan DTO); kaynağını (entity ya da query) çözdüğünüzde aynı yoldaki çakışması aynı tarafa KENDİLİĞİNDEN çözülür — ayrı ayrı ve zıt çözülemez. Uygulanmış planlarda title, description, createdBy ve appliedBy da gelir. kind=revert ise bu bir geri alma planıdır: revertsPlanId geri aldığı planı verir ve elements'te source merge ÖNCESİ, target ŞİMDİKİ değerdir. isStale: true ise plan alındığından beri DAL ya da development değişmiştir: items o değişikliği taşimaz ve merge_apply 409 döner — merge_refresh ile planı tazeleyin. elements[].isNoise: true olan eleman GÖSTERİM gürültüsüdür — kanvasın kendi durumu (workflow schema), DTO'dan türetilen şema (microservice schema.parameterScheme/returnScheme), sunucu yönetimli anahtar; merge gövdesinde KALIR ve uygulanır, yalnız okurken atlanır. Çakışan eleman asla işaretlenmez. items[].references[] o kalemin gövdesindeki guid'lerin karşılığıdır ({ id, name, module }): bir table step'in rule.entityId'si hangi tabloya, bir branch'in nextStepId'si hangi adıma, bir filtrenin fieldId'si hangi alana işaret ediyor — plan dışına çıkmadan okunur. items[].parentKey dolu olan kayıt başka bir kaydın çocuğudur (DTO çocukları, iç içe klasörler); ebeveyniyle birlikte okunur. items[].recordType kaydın modül içindeki türüdür — bir workflow kaydı 'workflow', 'automation' ya da 'middleware' olabilir ve modül üçüne de workflow der. items[].hiddenFields o kaydın GÖVDESİNDE okunmayacak anahtarlardır (aynı politika; eklenen/silinen kayıt tek eleman olarak geldiği için yolun değil anahtarın sorusudur).",
|
|
58
|
+
description: "Bir merge planını döner. items[] yalnız DEĞİŞEN kayıtları taşır; her kayıtta kind (add|update|delete|conflict) ve elements[] vardır. Çakışan elemanlarda base/source/target üç değeri birden gelir. dataRisk: true olan kalemde SEBEP dataRiskReasons[] içindedir: 'field-removed' (alan siliniyor), 'field-narrowed' (tip/nullable/unique daraltılıyor), 'not-null-without-default-on-populated-table' (hedefte satır varken varsayılansız NOT NULL alan ekleniyor — bu apply'ı DDL aşamasında düşürür, alanı nullable yapın ya da varsayılan verin), 'table-removed' (hedefte satırı olan tablo siliniyor). dataRisk bir UYARIDIR, apply'ı bloklamaz. items[].dependents[] ({ id, name, module }) dolu olan kalem, DALIN SİLDİĞİ ama development'ın dal açıldıktan sonra kullanmaya başladığı kayıttır: silme ÇAKIŞMAYA döner; hedef lehine çözüm kaydı ve bağımlısını korur, kaynak lehine çözüm siler (bağımlı FK ile düşebilir). Sorgunun çıktı DTO'su ve alanları aynı çakışma grubuna girer. Süreç kenarlarında (edges) iki taraf AYNI geçidin çıkışlarına dokunduysa yol 'versions[id=…].model.edges{from=<düğüm>}' olan TEK çakışma gelir; farklı geçitler kendiliğinden birleşir. Merge çevirileri (translation, adı 'key') ve microfunction'ları da taşır; microfunction hedefte TASLAK kalır, yayını kullanıcı yapar. derivedFromKey dolu olan kalem OTOMATİK ÜRETİLMİŞ bir kayıttır (varsayılan DTO); kaynağını (entity ya da query) çözdüğünüzde aynı yoldaki çakışması aynı tarafa KENDİLİĞİNDEN çözülür — ayrı ayrı ve zıt çözülemez. Uygulanmış planlarda title, description, createdBy ve appliedBy da gelir. kind=revert ise bu bir geri alma planıdır: revertsPlanId geri aldığı planı verir ve elements'te source merge ÖNCESİ, target ŞİMDİKİ değerdir. isStale: true ise plan alındığından beri DAL ya da development değişmiştir: items o değişikliği taşimaz ve merge_apply 409 döner — merge_refresh ile planı tazeleyin. elements[].isNoise: true olan eleman GÖSTERİM gürültüsüdür — kanvasın kendi durumu (workflow schema), DTO'dan türetilen şema (microservice schema.parameterScheme/returnScheme), sunucu yönetimli anahtar; merge gövdesinde KALIR ve uygulanır, yalnız okurken atlanır. Çakışan eleman asla işaretlenmez. items[].references[] o kalemin gövdesindeki guid'lerin karşılığıdır ({ id, name, module }): bir table step'in rule.entityId'si hangi tabloya, bir branch'in nextStepId'si hangi adıma, bir filtrenin fieldId'si hangi alana işaret ediyor — plan dışına çıkmadan okunur. items[].parentKey dolu olan kayıt başka bir kaydın çocuğudur (DTO çocukları, iç içe klasörler); ebeveyniyle birlikte okunur. items[].recordType kaydın modül içindeki türüdür — bir workflow kaydı 'workflow', 'automation' ya da 'middleware' olabilir ve modül üçüne de workflow der. items[].hiddenFields o kaydın GÖVDESİNDE okunmayacak anahtarlardır (aynı politika; eklenen/silinen kayıt tek eleman olarak geldiği için yolun değil anahtarın sorusudur).",
|
|
59
59
|
inputSchema: { projectId: guid, planId: guid, view: mergeView },
|
|
60
60
|
annotations: readOnly
|
|
61
61
|
}, handle(config, ({ projectId, planId, view }) => platform.org('GET', `/merges/${projectId}/${planId}?view=${view ?? 'conflicts'}`)));
|
|
@@ -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ı · access.session.delete: çıkış; refresh ailesini iptal eder ve üç oturum çerezini yanıtla siler, erişim jetonu dolmuşsa 401 AppSessionRequired döner ve runtime yenileyip tekrarlar — akışın cookie/storage adımları bu HttpOnly çerezlere ulaşmaz, FLOW-037, uç isAnonymous:true kalır; 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', {
|