@appaflytech/zeyrek-ai-mcp 0.0.18 → 0.0.20
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/README.md +13 -14
- package/dist/config.js +2 -0
- package/dist/knowledge/componentCatalog.js +204 -836
- package/dist/knowledge/componentEvents.js +75 -368
- package/dist/knowledge/mobileComponentCatalog.js +331 -0
- package/dist/knowledge/mobileComponentEvents.js +50 -0
- package/dist/knowledge/normalize.js +63 -66
- package/dist/knowledge/platform/lint.js +205 -0
- package/dist/knowledge/platform/mobile.js +78 -0
- package/dist/knowledge/platform/mobileRules.js +121 -0
- package/dist/knowledge/platform/mobileTabs.js +108 -0
- package/dist/knowledge/platform/profile.js +20 -0
- package/dist/knowledge/platform/resolve.js +122 -0
- package/dist/knowledge/platform/web.js +38 -0
- package/dist/knowledge/rules.js +6 -29
- package/dist/knowledge/styleResolve.js +1 -1
- package/dist/knowledge/styleResolveNative.js +410 -0
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/platform/capture/actions.js +333 -0
- package/dist/platform/capture/browser.js +1 -0
- package/dist/platform/{screenshot.js → capture/capture.js} +23 -509
- package/dist/platform/capture/index.js +10 -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/domSummary.js +1 -1
- package/dist/platform/responses.js +1 -2
- package/dist/platform/strictArguments.js +2 -22
- package/dist/platform/writeDiff.js +31 -58
- package/dist/resources/examples/mobile-app-shell-drawer.json +209 -0
- package/dist/resources/examples/mobile-app-shell-stack.json +123 -0
- package/dist/resources/examples/mobile-app-shell-tab.json +174 -0
- package/dist/resources/examples/mobile-list-detail-form.json +656 -0
- package/dist/resources/guides/component.md +6 -9
- package/dist/resources/guides/functions.md +3 -32
- package/dist/resources/guides/getting-started.md +0 -35
- package/dist/resources/guides/layout.md +11 -7
- package/dist/resources/guides/mobile.md +215 -0
- package/dist/resources/guides/page.md +71 -49
- package/dist/resources/guides/translation.md +6 -5
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +0 -18
- package/dist/server.js +2 -0
- package/dist/tools/applications.js +60 -3
- package/dist/tools/components.js +50 -10
- package/dist/tools/designSchemaPatch.js +18 -13
- package/dist/tools/externalComponents.js +25 -4
- package/dist/tools/flows.js +51 -38
- package/dist/tools/functions.js +10 -20
- package/dist/tools/layouts.js +41 -9
- package/dist/tools/microservices.js +11 -39
- package/dist/tools/mobile.js +203 -0
- package/dist/tools/pages.js +127 -95
- package/dist/tools/platformInfo.js +2 -1
- package/dist/tools/profileWrite.js +45 -0
- package/dist/tools/schemaOps.js +2 -2
- package/dist/tools/screenWrite.js +2 -2
- package/dist/tools/screens.js +9 -3
- package/dist/tools/workflows.js +12 -39
- package/package.json +2 -7
- package/dist/platform/diagnostics.js +0 -85
- package/dist/platform/ifExists.js +0 -129
- package/dist/platform/writeView.js +0 -17
|
@@ -175,10 +175,11 @@ motor olmasıdır (tarayıcı JS'i ve Jint).
|
|
|
175
175
|
verilmişse sekme başlığı çeviri sözlüğünden çözülür; anahtar boşsa `browserTitle` olduğu gibi
|
|
176
176
|
kullanılır. İkisi de boşsa sayfa adı yazılır.
|
|
177
177
|
|
|
178
|
-
> **Sekme başlığı canlı dil değişimini
|
|
179
|
-
>
|
|
180
|
-
>
|
|
181
|
-
>
|
|
178
|
+
> **Sekme başlığı SAYFA YÜKLENİRKEN çözülür, canlı dil değişimini İZLEMEZ.** Ölçüldü 2026-09-08
|
|
179
|
+
> (yerel runtime): `language-selector` ile dil değiştirildiğinde sayfa içeriği ve layout başlığı
|
|
180
|
+
> anında yeni dile geçiyor, sekme başlığı ise açılıştaki dilde kalıyor; aynı dille sayfa yeniden
|
|
181
|
+
> yüklendiğinde başlık doğru geliyor. Sebep `Runtime.svelte`'te dilin bir `const` olarak bir kez
|
|
182
|
+
> çözülmesi. Sekme başlığının dilini doğrulayacaksan **yeniden yükleyerek** doğrula.
|
|
182
183
|
|
|
183
184
|
## Doğrulama mesajları: `t:` öneki
|
|
184
185
|
|
|
@@ -208,7 +209,7 @@ gerekmez — `schema.ts`'e dokunulmaz, katalog yeniden yüklenmez.
|
|
|
208
209
|
`translation_update` artık uygulamanın bütün sayfalarının önbellek satırlarını düşürüyor
|
|
209
210
|
(`RefreshPageCacheWhenTranslationChangedCommand`), okuma yolu cache-aside olduğu için bir
|
|
210
211
|
sonraki `page_runtime_get` taze değeri kurar. Yazmadan hemen sonra okuyabilirsin.
|
|
211
|
-
- Mobil runtime (
|
|
212
|
+
- Mobil uygulama runtime'ı (`@ng-apps/ui-native`) web ile aynı akış motorunu ve dil seçimini kullanır; cihazda ölçülene kadar kanıtlı olan web'dir.
|
|
212
213
|
|
|
213
214
|
## Backend doğrulama sınırları (TR-001)
|
|
214
215
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
3
|
-
"generatedAt": "2026-09-
|
|
2
|
+
"hash": "05c7864d58e308973805f7becee1578ce9eddad196abcdf7eebb43b1e7677549",
|
|
3
|
+
"generatedAt": "2026-09-19T20:19:15.052Z",
|
|
4
4
|
"types": 186,
|
|
5
5
|
"files": 108,
|
|
6
6
|
"note": "Şemaları üreten backend kaynaklarının parmak izi. Elle düzenlemeyin: 'npm run generate-schemas' yazar, 'npm run schema:check' denetler.",
|
|
@@ -95,20 +95,6 @@
|
|
|
95
95
|
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
|
|
96
96
|
},
|
|
97
97
|
"nullable": true
|
|
98
|
-
},
|
|
99
|
-
"bindings": {
|
|
100
|
-
"type": "array",
|
|
101
|
-
"items": {
|
|
102
|
-
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
|
|
103
|
-
},
|
|
104
|
-
"nullable": true
|
|
105
|
-
},
|
|
106
|
-
"functions": {
|
|
107
|
-
"type": "array",
|
|
108
|
-
"items": {
|
|
109
|
-
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
|
|
110
|
-
},
|
|
111
|
-
"nullable": true
|
|
112
98
|
}
|
|
113
99
|
},
|
|
114
100
|
"additionalProperties": false
|
|
@@ -203,10 +189,6 @@
|
|
|
203
189
|
},
|
|
204
190
|
"stepKind": {
|
|
205
191
|
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Studio.Flows.StepKind"
|
|
206
|
-
},
|
|
207
|
-
"propertyName": {
|
|
208
|
-
"type": "string",
|
|
209
|
-
"nullable": true
|
|
210
192
|
}
|
|
211
193
|
},
|
|
212
194
|
"additionalProperties": false
|
package/dist/server.js
CHANGED
|
@@ -39,6 +39,7 @@ import { registerMergeTools } from "./tools/merges.js";
|
|
|
39
39
|
import { registerRevisionTools } from "./tools/revisions.js";
|
|
40
40
|
import { registerActivityTools } from "./tools/activities.js";
|
|
41
41
|
import { registerDtoTools } from "./tools/dtos.js";
|
|
42
|
+
import { registerMobileTools } from "./tools/mobile.js";
|
|
42
43
|
const moduleRegistrations = {
|
|
43
44
|
platform: registerPlatformTools,
|
|
44
45
|
project: registerProjectTools,
|
|
@@ -80,6 +81,7 @@ const moduleRegistrations = {
|
|
|
80
81
|
merge: registerMergeTools,
|
|
81
82
|
activity: registerActivityTools,
|
|
82
83
|
revision: registerRevisionTools,
|
|
84
|
+
mobile: registerMobileTools,
|
|
83
85
|
};
|
|
84
86
|
export function createGatewayServer(platform) {
|
|
85
87
|
const server = rejectUnknownArguments(instrumentServer(new McpServer({ name: "ngapps", version: "0.1.0" }), platform.config));
|
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
import { guid, pagingParams, readOnly, writes, updates, destructive } from './common.js';
|
|
2
2
|
import { handle } from '../platform/responses.js';
|
|
3
|
+
import { forgetApplication, readApplicationPlatform, resolveApplication } from '../knowledge/platform/resolve.js';
|
|
4
|
+
import { mobileTabsProblems, readMobileTabs } from '../knowledge/platform/mobileTabs.js';
|
|
5
|
+
import { findingLine } from '../knowledge/platform/profile.js';
|
|
3
6
|
import { z } from 'zod';
|
|
7
|
+
/**
|
|
8
|
+
* MOB-007 (sekme ayarı) — `properties.mobile.tabs` yazan mobil uygulama çağrısının denetimi. Yazım
|
|
9
|
+
* platforma YİNE gider (D3; backend `properties`'i doğrulamaz): bulgu `platformWarnings`'e düşer.
|
|
10
|
+
* Sayfa ve widget listesi okunamazsa o denetimler atlanır, biçim denetimi yine koşar.
|
|
11
|
+
*/
|
|
12
|
+
export async function mobileTabsWarnings(platform, applicationId, projectSlug, homepageId, properties) {
|
|
13
|
+
const tabs = readMobileTabs(properties);
|
|
14
|
+
if (tabs === undefined)
|
|
15
|
+
return [];
|
|
16
|
+
const pages = applicationId && projectSlug
|
|
17
|
+
? await platform.tenant('GET', projectSlug, `/pages/${applicationId}`, { query: { pageIndex: 0, pageLength: 200 } })
|
|
18
|
+
.then(response => (response?.data ?? []).map(page => ({ id: String(page.id ?? '') })))
|
|
19
|
+
.catch(() => undefined)
|
|
20
|
+
: undefined;
|
|
21
|
+
const widgetIds = applicationId && projectSlug
|
|
22
|
+
? await platform.tenant('GET', projectSlug, `/components/${applicationId}`, { query: { pageIndex: 0, pageLength: 999 } })
|
|
23
|
+
.then(response => new Set((response?.data ?? []).filter(entry => entry.kind === 'widget').map(entry => String(entry.id ?? ''))))
|
|
24
|
+
.catch(() => undefined)
|
|
25
|
+
: undefined;
|
|
26
|
+
return mobileTabsProblems(tabs, {
|
|
27
|
+
...(pages ? { pages } : {}),
|
|
28
|
+
...(homepageId ? { homepageId } : {}),
|
|
29
|
+
...(widgetIds ? { widgetIds } : {})
|
|
30
|
+
}).map(message => findingLine({
|
|
31
|
+
code: 'MOB-007',
|
|
32
|
+
severity: 'warn',
|
|
33
|
+
message,
|
|
34
|
+
guide: "platform_guide('mobile') §Gezinme"
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
function withPlatformWarnings(response, warnings) {
|
|
38
|
+
if (warnings.length === 0 || !response || typeof response !== 'object' || Array.isArray(response))
|
|
39
|
+
return response;
|
|
40
|
+
return { ...response, platformWarnings: warnings };
|
|
41
|
+
}
|
|
4
42
|
export function registerApplicationTools(server, platform) {
|
|
5
43
|
const config = platform.config;
|
|
6
44
|
server.registerTool('application_list', {
|
|
@@ -34,7 +72,14 @@ export function registerApplicationTools(server, platform) {
|
|
|
34
72
|
notFoundPageId: guid.optional()
|
|
35
73
|
},
|
|
36
74
|
annotations: writes
|
|
37
|
-
}, handle(config, ({ projectId, ...body }) =>
|
|
75
|
+
}, handle(config, async ({ projectId, ...body }) => {
|
|
76
|
+
const warnings = readApplicationPlatform(body.type) === 'mobile'
|
|
77
|
+
? await mobileTabsWarnings(platform, undefined, undefined, undefined, body.properties)
|
|
78
|
+
: [];
|
|
79
|
+
const response = await platform.org('POST', `/applications/${projectId}`, { body });
|
|
80
|
+
forgetApplication(platform);
|
|
81
|
+
return withPlatformWarnings(response, warnings);
|
|
82
|
+
}));
|
|
38
83
|
server.registerTool('application_update', {
|
|
39
84
|
title: 'Application güncelle',
|
|
40
85
|
description: 'Application bilgilerini günceller; homepageId zorunludur (mevcut değeri application_get ile alın).',
|
|
@@ -49,11 +94,23 @@ export function registerApplicationTools(server, platform) {
|
|
|
49
94
|
notFoundPageId: guid.optional()
|
|
50
95
|
},
|
|
51
96
|
annotations: updates
|
|
52
|
-
}, handle(config, ({ id, ...body }) =>
|
|
97
|
+
}, handle(config, async ({ id, ...body }) => {
|
|
98
|
+
const current = await resolveApplication(platform, id);
|
|
99
|
+
const warnings = current?.platform === 'mobile'
|
|
100
|
+
? await mobileTabsWarnings(platform, id, current.projectSlug, body.homepageId, body.properties)
|
|
101
|
+
: [];
|
|
102
|
+
const response = await platform.org('PUT', `/applications/${id}`, { body });
|
|
103
|
+
forgetApplication(platform, id);
|
|
104
|
+
return withPlatformWarnings(response, warnings);
|
|
105
|
+
}));
|
|
53
106
|
server.registerTool('application_delete', {
|
|
54
107
|
title: 'Application sil',
|
|
55
108
|
description: 'Application\'ı kalıcı olarak siler.',
|
|
56
109
|
inputSchema: { id: guid },
|
|
57
110
|
annotations: destructive
|
|
58
|
-
}, handle(config, args =>
|
|
111
|
+
}, handle(config, async (args) => {
|
|
112
|
+
const response = await platform.org('DELETE', `/applications/${args.id}`);
|
|
113
|
+
forgetApplication(platform, args.id);
|
|
114
|
+
return response;
|
|
115
|
+
}));
|
|
59
116
|
}
|
package/dist/tools/components.js
CHANGED
|
@@ -1,25 +1,40 @@
|
|
|
1
1
|
import { guid, projectParam, environmentParam, readOnly, writes, updates, destructive } from './common.js';
|
|
2
|
-
import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, withNormalization } from '../knowledge/normalize.js';
|
|
2
|
+
import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, normalizeDroppableStates, withNormalization } from '../knowledge/normalize.js';
|
|
3
3
|
import { eventContractsFor, eventPayloadNote } from '../knowledge/componentEvents.js';
|
|
4
4
|
import { componentPresetDefaults, readProjectTheme } from '../knowledge/themeSchema.js';
|
|
5
5
|
import { knowledgeFor, knowledgeNote, APPEARANCE_TOKEN_SETS, STATE_FLAG_NOTES, INTERNAL_ROLES_BY_TYPE } from '../knowledge/componentCatalog.js';
|
|
6
|
+
import { MOBILE_STATE_FLAG_NOTES, mobileComponentKnowledge } from '../knowledge/mobileComponentCatalog.js';
|
|
7
|
+
import { mobileComponentEventContracts } from '../knowledge/mobileComponentEvents.js';
|
|
6
8
|
import { componentUpdateBody, fetchHost, schemaParam, unwrap } from './screens.js';
|
|
7
9
|
import { PlatformApiError } from '../platform/errors.js';
|
|
8
10
|
import { handle } from '../platform/responses.js';
|
|
11
|
+
import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
|
|
12
|
+
import { mobileComponentNotes } from '../knowledge/platform/mobileRules.js';
|
|
9
13
|
import { z } from 'zod';
|
|
10
|
-
const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform;
|
|
14
|
+
const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform (ComponentType); verilmezse uygulamanın tipi — mobil uygulamada mobile');
|
|
11
15
|
const kindParam = z.enum(['component', 'widget']).optional()
|
|
12
16
|
.describe("component: sayfaya konan tekil eleman. widget: kendi şeması olan kapsayıcı (container/modal/drawer)");
|
|
13
17
|
const widgetTypeParam = z.enum(['container', 'modal', 'drawer']).optional()
|
|
14
18
|
.describe("kind:'widget' iken zorunlu");
|
|
19
|
+
/**
|
|
20
|
+
* Uç `type` verilmezse WEB kataloğunu döner (`GetComponentsQuery` `Type ?? Web`); mobil uygulamanın
|
|
21
|
+
* paleti, doğrulayıcısı ve widget'ları `type=mobile` satırlarıdır. Profil mobil derse sorgu tipi
|
|
22
|
+
* taşır; web'de sorgu profil öncesiyle aynıdır (G1 kilidi).
|
|
23
|
+
*/
|
|
15
24
|
async function listComponents(platform, project, environment, applicationId, scope) {
|
|
16
25
|
const path = scope === 'all' ? `/components/${applicationId}/all` : `/components/${applicationId}`;
|
|
26
|
+
const catalogType = scope === 'all' ? 'web' : (await resolveProfile(platform, applicationId)).profile.catalogType;
|
|
17
27
|
const response = await platform.tenant('GET', project, path, {
|
|
18
28
|
environment,
|
|
19
|
-
query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999 }
|
|
29
|
+
query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999, ...(catalogType === 'mobile' ? { type: 'mobile' } : {}) }
|
|
20
30
|
});
|
|
21
31
|
return response?.data ?? [];
|
|
22
32
|
}
|
|
33
|
+
/** Uygulamanın kayıtlı bileşen slug'ları (mobil profilin MOB-003 denetimi). */
|
|
34
|
+
export async function fetchCatalogSlugs(platform, project, environment, applicationId) {
|
|
35
|
+
const components = await listComponents(platform, project, environment, applicationId);
|
|
36
|
+
return new Set(components.map(component => String(component.slug ?? '')).filter(slug => slug.length > 0));
|
|
37
|
+
}
|
|
23
38
|
/**
|
|
24
39
|
* Yerleşim normalizasyonlarının ikisi de aynı katalog listesinden beslenir; tek okumada
|
|
25
40
|
* çıkarılır ki yazma yolları fazladan istek atmasın. Uygulamanın kendi sözlüğü okunur
|
|
@@ -38,12 +53,17 @@ export async function fetchComponentLayoutRules(platform, project, environment,
|
|
|
38
53
|
export function componentLayoutRules(components) {
|
|
39
54
|
const maxSizes = new Map();
|
|
40
55
|
const autoHeights = new Map();
|
|
56
|
+
const droppable = new Map();
|
|
41
57
|
for (const component of components) {
|
|
42
58
|
const slug = typeof component.slug === 'string' ? component.slug : undefined;
|
|
43
59
|
if (!slug)
|
|
44
60
|
continue;
|
|
45
61
|
if (typeof component.isDefaultAutoHeight === 'boolean')
|
|
46
62
|
autoHeights.set(slug, component.isDefaultAutoHeight);
|
|
63
|
+
// Kap bilgisi sözlükten gelir; düğümün `states.isDroppable`ı onu izler (Studio paleti de
|
|
64
|
+
// aynı alanı katalogdan yazar). `true` gören tip kap sayılır.
|
|
65
|
+
if (typeof component.isDroppable === 'boolean')
|
|
66
|
+
droppable.set(slug, component.isDroppable);
|
|
47
67
|
const blocks = (component.definition ?? {}).blocks;
|
|
48
68
|
if (!Array.isArray(blocks))
|
|
49
69
|
continue;
|
|
@@ -58,7 +78,7 @@ export function componentLayoutRules(components) {
|
|
|
58
78
|
});
|
|
59
79
|
}
|
|
60
80
|
}
|
|
61
|
-
return { maxSizes, autoHeights };
|
|
81
|
+
return { maxSizes, autoHeights, droppable };
|
|
62
82
|
}
|
|
63
83
|
/**
|
|
64
84
|
* Katalog okuması başarısız olsa da yazma isteği gitmeli, ama iki normalizasyonun düşüş davranışı
|
|
@@ -69,14 +89,21 @@ export function componentLayoutRules(components) {
|
|
|
69
89
|
* varsayılanını (`fixed`, `DesignComponentManagementSchema.cs:24`) kabul etmek demektir; en fazla
|
|
70
90
|
* sekiz tipte (auth-layout/html/image/layout/qrcode/table/text-editor/video) fazladan yükseklik
|
|
71
91
|
* üretir, atlamak ise her tipte içerik kırpar.
|
|
92
|
+
* - `states.isDroppable` atlanır — katalog okunamadığında hangi tipin kap olduğu bilinmez ve
|
|
93
|
+
* uydurulmaz; düğüm bugünkü hâliyle yazılır.
|
|
72
94
|
*/
|
|
73
95
|
export async function applyCatalogLayoutRules(platform, project, environment, applicationId, nodes) {
|
|
74
96
|
try {
|
|
75
97
|
const rules = await fetchComponentLayoutRules(platform, project, environment, applicationId);
|
|
76
|
-
return {
|
|
98
|
+
return {
|
|
99
|
+
clamped: clampBlockSizes(nodes, rules.maxSizes),
|
|
100
|
+
heights: normalizeHeightTypes(nodes, rules.autoHeights),
|
|
101
|
+
sizes: normalizeSizeStrings(nodes),
|
|
102
|
+
states: normalizeDroppableStates(nodes, rules.droppable)
|
|
103
|
+
};
|
|
77
104
|
}
|
|
78
105
|
catch {
|
|
79
|
-
return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes) };
|
|
106
|
+
return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes), states: [] };
|
|
80
107
|
}
|
|
81
108
|
}
|
|
82
109
|
/**
|
|
@@ -116,6 +143,7 @@ export function registerComponentTools(server, platform) {
|
|
|
116
143
|
}, handle(config, async ({ project, environment, applicationId, scope, includeHidden }) => {
|
|
117
144
|
const components = await listComponents(platform, project, environment, applicationId, scope);
|
|
118
145
|
return {
|
|
146
|
+
...applicationTypeField(await resolveProfile(platform, applicationId)),
|
|
119
147
|
components: components
|
|
120
148
|
.filter(component => includeHidden === true || component.isHide !== true)
|
|
121
149
|
.map(component => ({
|
|
@@ -161,6 +189,15 @@ export function registerComponentTools(server, platform) {
|
|
|
161
189
|
: [];
|
|
162
190
|
const componentSlug = typeof component.slug === 'string' ? component.slug : undefined;
|
|
163
191
|
const knowledge = knowledgeFor(componentSlug);
|
|
192
|
+
// Mobil uygulamada kayıt mobil kataloğun satırıdır (`listComponents` type=mobile); davranış
|
|
193
|
+
// notları web runtime'ından gelir (`knowledge` — mobil şema web sınıfını genişletir), bileşenin
|
|
194
|
+
// mobil farkları `mobileKnowledge`'ta, bütün mobil bileşenlere geçen notlar `mobileNotes`'ta (G4).
|
|
195
|
+
// Web ikizi olmayan bileşende (`app-bar`, `tooltip`…) bilgi yalnız `mobileKnowledge`'tadır; olay
|
|
196
|
+
// yükleri de önce mobil sözlükten okunur (`mobileComponentEvents.ts`).
|
|
197
|
+
const mobile = (await resolveProfile(platform, applicationId)).profile.platform === 'mobile';
|
|
198
|
+
const mobileKnowledge = mobile && componentSlug !== undefined && Object.hasOwn(mobileComponentKnowledge, componentSlug)
|
|
199
|
+
? mobileComponentKnowledge[componentSlug]
|
|
200
|
+
: undefined;
|
|
164
201
|
// S-3 — `defaults` HAM katalogdur; Studio'da bırakılan düğüm ise temanın bileşen preseti
|
|
165
202
|
// kaplanmış katalogdan kurulur (`withThemeComponentDefaults`). Tema okunamazsa (uç düşer,
|
|
166
203
|
// yetki yoksa) alan yanıta HİÇ girmez: uydurulmuş bir varsayılan yanlış bilgidir.
|
|
@@ -177,7 +214,7 @@ export function registerComponentTools(server, platform) {
|
|
|
177
214
|
isDroppable: component.isDroppable,
|
|
178
215
|
props: definition.props,
|
|
179
216
|
defaults: definition.defaults,
|
|
180
|
-
events: eventContractsFor(componentSlug, eventNames),
|
|
217
|
+
events: eventContractsFor(componentSlug, eventNames, mobile ? mobileComponentEventContracts : undefined),
|
|
181
218
|
eventPayloadNote,
|
|
182
219
|
...(knowledge
|
|
183
220
|
? {
|
|
@@ -188,7 +225,7 @@ export function registerComponentTools(server, platform) {
|
|
|
188
225
|
},
|
|
189
226
|
...(knowledge.guide ? { guide: knowledge.guide } : {})
|
|
190
227
|
}
|
|
191
|
-
: { knowledgeNote }),
|
|
228
|
+
: mobileKnowledge ? {} : { knowledgeNote }),
|
|
192
229
|
...(componentSlug && INTERNAL_ROLES_BY_TYPE[componentSlug]
|
|
193
230
|
? {
|
|
194
231
|
internalRoles: INTERNAL_ROLES_BY_TYPE[componentSlug],
|
|
@@ -196,8 +233,9 @@ export function registerComponentTools(server, platform) {
|
|
|
196
233
|
}
|
|
197
234
|
: {}),
|
|
198
235
|
...(themeDefaults ? { themeDefaults } : {}),
|
|
236
|
+
...(mobile ? { platform: 'mobile', ...(mobileKnowledge ? { mobileKnowledge } : {}), mobileNotes: mobileComponentNotes(componentSlug) } : {}),
|
|
199
237
|
appearanceValues: APPEARANCE_TOKEN_SETS,
|
|
200
|
-
stateFlags: STATE_FLAG_NOTES,
|
|
238
|
+
stateFlags: mobile ? { ...STATE_FLAG_NOTES, ...MOBILE_STATE_FLAG_NOTES } : STATE_FLAG_NOTES,
|
|
201
239
|
validations: definition.validations,
|
|
202
240
|
sizes: definition.blocks
|
|
203
241
|
};
|
|
@@ -234,11 +272,13 @@ export function registerComponentTools(server, platform) {
|
|
|
234
272
|
const catalog = (body.schema ?? []).length > 0
|
|
235
273
|
? await applyCatalogLayoutRules(platform, project, environment, applicationId, body.schema)
|
|
236
274
|
: { clamped: [], heights: [], sizes: [] };
|
|
275
|
+
// Mobil uygulamanın widget'ı mobil katalog satırıdır; tip verilmezse uygulamanın tipi.
|
|
276
|
+
const defaultType = body.type ?? (await resolveProfile(platform, applicationId)).profile.catalogType;
|
|
237
277
|
return platform.tenant('POST', project, `/components/${applicationId}`, {
|
|
238
278
|
environment,
|
|
239
279
|
body: {
|
|
240
280
|
kind: 'component',
|
|
241
|
-
type:
|
|
281
|
+
type: defaultType,
|
|
242
282
|
categories: [],
|
|
243
283
|
definition: {},
|
|
244
284
|
schema: [],
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { orphanedFlowWarnings, orphanedFlowPlan, orphanedFlowMessage,
|
|
1
|
+
import { orphanedFlowWarnings, orphanedFlowPlan, orphanedFlowMessage, staleSetterWarnings, normalizeSchemaOps, validationNote, componentDefaultsNote, replacePropNote, flexSizeWarnings, nestedRepeaterNodes, nestedRepeaterMessage, stringStyleNodes, stringStyleWarning, inertFlexPropNodes, inertFlexPropWarning, verticalGapWarnings, withNormalization, FLEX_LAYOUT_PROP_NAMES } from '../knowledge/normalize.js';
|
|
2
2
|
import { opsParam, writeViewParam, outlineWriteResponse, unknownEventOps, collectTypes, simulateLayoutOps, removeNodeFromTree, planEventRemovals, planResizes, planPropTypes, assertOpBodies } from './schemaOps.js';
|
|
3
3
|
import { guid, projectParam, environmentParam, updates, microOps } from './common.js';
|
|
4
4
|
import { fetchHost, hostPath } from './screens.js';
|
|
5
5
|
import { assertScreenWriteGuards, screenCatalogNotes } from './screenWrite.js';
|
|
6
|
-
import {
|
|
6
|
+
import { schemaOpDrops, withWriteDiff } from '../platform/writeDiff.js';
|
|
7
7
|
import { fetchComponentEventNames } from './components.js';
|
|
8
8
|
import { PlatformApiError } from '../platform/errors.js';
|
|
9
9
|
import { handle } from '../platform/responses.js';
|
|
10
10
|
import { slotWarning } from './layouts.js';
|
|
11
|
+
import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
|
|
12
|
+
import { boundFlowSteps, screenProfileWarnings } from './profileWrite.js';
|
|
11
13
|
import { z } from 'zod';
|
|
12
14
|
const HOSTS = {
|
|
13
15
|
layout: {
|
|
@@ -68,10 +70,7 @@ export function registerDesignSchemaPatchTool(server, platform, host) {
|
|
|
68
70
|
}
|
|
69
71
|
const nodes = (record[spec.tree] ?? []);
|
|
70
72
|
const events = host === 'layout' ? record.events : undefined;
|
|
71
|
-
if (opRecords.some(entry => entry.op === 'set_event'
|
|
72
|
-
const bound = boundEventOps(nodes, opRecords);
|
|
73
|
-
if (bound.length > 0)
|
|
74
|
-
throw new PlatformApiError(`PAGE-034 — dolu olaya set_event (istek gönderilmedi): ${bound.join(' · ')}`, 400);
|
|
73
|
+
if (opRecords.some(entry => entry.op === 'set_event')) {
|
|
75
74
|
const typesByElementId = new Map();
|
|
76
75
|
collectTypes(nodes, typesByElementId);
|
|
77
76
|
collectTypes(opRecords.map(entry => entry.component).filter(Boolean), typesByElementId);
|
|
@@ -80,7 +79,6 @@ export function registerDesignSchemaPatchTool(server, platform, host) {
|
|
|
80
79
|
if (unknown.length > 0)
|
|
81
80
|
throw new PlatformApiError(`PAGE-008 — geçersiz olay adı (istek gönderilmedi): ${unknown.join(' · ')}`, 400);
|
|
82
81
|
}
|
|
83
|
-
stripGatewayEventFields(opRecords);
|
|
84
82
|
const deletedFlows = orphanedFlowPlan(nodes, events, [...opRecords, ...removeEventOps]);
|
|
85
83
|
if (deletedFlows.length > 0 && allowFlowDeletion !== true)
|
|
86
84
|
throw new PlatformApiError(orphanedFlowMessage(deletedFlows), 400);
|
|
@@ -101,12 +99,18 @@ export function registerDesignSchemaPatchTool(server, platform, host) {
|
|
|
101
99
|
const nested = simulatable ? nestedRepeaterNodes(simulated) : [];
|
|
102
100
|
if (nested.length > 0)
|
|
103
101
|
throw new PlatformApiError(nestedRepeaterMessage(nested), 400);
|
|
102
|
+
const resolved = await resolveProfile(platform, applicationId);
|
|
104
103
|
const reshaped = simulatable || opRecords.some(entry => entry.op === 'remove_component');
|
|
104
|
+
const profileWarnings = await screenProfileWarnings(platform, resolved, project, environment, applicationId, {
|
|
105
|
+
kind: spec.kind,
|
|
106
|
+
ops: [...opRecords, ...propTypeOps],
|
|
107
|
+
steps: await boundFlowSteps(platform, resolved, project, environment, host, applicationId, id, opRecords)
|
|
108
|
+
});
|
|
105
109
|
const layoutWarnings = reshaped
|
|
106
110
|
? [
|
|
107
|
-
...verticalGapWarnings(simulated, spec.codes.gap, touched),
|
|
111
|
+
...(resolved.profile.layout.blocksMeaningful ? verticalGapWarnings(simulated, spec.codes.gap, touched) : []),
|
|
108
112
|
...stringStyleWarning(stringStyleNodes(simulated)),
|
|
109
|
-
...inertFlexPropWarning(inertFlexPropNodes(simulated)),
|
|
113
|
+
...(resolved.profile.layout.modes.has('grid') ? inertFlexPropWarning(inertFlexPropNodes(simulated)) : []),
|
|
110
114
|
...flexSizeWarnings(simulated, spec.codes.flexMismatch, spec.codes.flexInvalid),
|
|
111
115
|
...(host === 'layout' ? slotWarning(simulated) : [])
|
|
112
116
|
]
|
|
@@ -133,17 +137,18 @@ export function registerDesignSchemaPatchTool(server, platform, host) {
|
|
|
133
137
|
response.deletedFlows = deletedFlows;
|
|
134
138
|
if (flowWarnings.length > 0)
|
|
135
139
|
response.flowWarnings = flowWarnings;
|
|
136
|
-
if (layoutWarnings.length > 0)
|
|
137
|
-
response.layoutWarnings = layoutWarnings;
|
|
140
|
+
if (layoutWarnings.length > 0 || profileWarnings.length > 0)
|
|
141
|
+
response.layoutWarnings = [...layoutWarnings, ...profileWarnings];
|
|
142
|
+
Object.assign(response, applicationTypeField(resolved));
|
|
138
143
|
const contentOps = opRecords.filter(entry => entry.op === 'add_component' || entry.op === 'replace_prop');
|
|
139
|
-
let opDrops =
|
|
144
|
+
let opDrops = [];
|
|
140
145
|
if (contentOps.length > 0) {
|
|
141
146
|
try {
|
|
142
147
|
const saved = await fetchHost(platform, host, project, environment, applicationId, id);
|
|
143
148
|
opDrops = schemaOpDrops(saved[spec.tree], contentOps);
|
|
144
149
|
}
|
|
145
150
|
catch {
|
|
146
|
-
opDrops =
|
|
151
|
+
opDrops = [];
|
|
147
152
|
}
|
|
148
153
|
}
|
|
149
154
|
return withWriteDiff(withNormalization(response, [
|
|
@@ -7,6 +7,23 @@ import { z } from 'zod';
|
|
|
7
7
|
import { evaluatePolicy, enforcePolicy } from '../knowledge/policy.js';
|
|
8
8
|
import { policyRules } from '../knowledge/rules.js';
|
|
9
9
|
import { EXTERNAL_COMPONENT_PROTOCOL_VERSION } from '../knowledge/backendConstraints.js';
|
|
10
|
+
import { resolveProfile } from '../knowledge/platform/resolve.js';
|
|
11
|
+
import { findingLine } from '../knowledge/platform/profile.js';
|
|
12
|
+
/**
|
|
13
|
+
* MOB-006 — harici bileşen protokolü v1 tarayıcıda koşan `.mjs` custom element'tir; mobil
|
|
14
|
+
* uygulamanın native çizeri onu yükleyemez (mobil protokol v2 Faz 3). Profil kapalı derse çağrı
|
|
15
|
+
* platforma GİTMEZ: yüklenen paket hiçbir ekranda çizilmeyecekti.
|
|
16
|
+
*/
|
|
17
|
+
async function assertExternalComponentsAllowed(platform, applicationId, tool) {
|
|
18
|
+
const resolved = await resolveProfile(platform, applicationId);
|
|
19
|
+
if (resolved.profile.externalComponents)
|
|
20
|
+
return;
|
|
21
|
+
throw new PlatformApiError(`${tool}: ${findingLine({
|
|
22
|
+
code: 'MOB-006',
|
|
23
|
+
severity: 'warn',
|
|
24
|
+
message: "harici bileşen mobil uygulamada desteklenmiyor — protokol v1 tarayıcıda koşan .mjs custom element'tir, native çizer onu yükleyemez (mobil protokol v2 Faz 3). Çağrı platforma gönderilmedi; mobil ekranı katalog bileşenleriyle kurun (component_list)."
|
|
25
|
+
})}`, 400);
|
|
26
|
+
}
|
|
10
27
|
/** Platformun köprü protokolü; scaffold ve publish bu sürüme göre üretir/doğrular (backend ExternalComponentRules.CurrentProtocolVersion) */
|
|
11
28
|
const PROTOCOL_VERSION = EXTERNAL_COMPONENT_PROTOCOL_VERSION;
|
|
12
29
|
/** Backend `ExternalComponentRules.MaxBundleSizeBytes` ile aynı sınır */
|
|
@@ -199,6 +216,7 @@ export function registerExternalComponentTools(server, platform) {
|
|
|
199
216
|
},
|
|
200
217
|
annotations: writes
|
|
201
218
|
}, handle(config, async ({ project, environment, applicationId, bundlePath, manifestPath, version }) => {
|
|
219
|
+
await assertExternalComponentsAllowed(platform, applicationId, 'external_component_publish');
|
|
202
220
|
const manifestFile = resolve(manifestPath);
|
|
203
221
|
const bundleFile = resolve(bundlePath);
|
|
204
222
|
let manifest;
|
|
@@ -262,10 +280,13 @@ export function registerExternalComponentTools(server, platform) {
|
|
|
262
280
|
acknowledgeWarnings: z.boolean().optional().describe('Doğrulama uyarılarını okuyup kabul ettiğinizi bildirir; uyarısı olan sürümlerde zorunlu')
|
|
263
281
|
},
|
|
264
282
|
annotations: updates
|
|
265
|
-
}, handle(config, ({ project, environment, applicationId, slug, version, acknowledgeWarnings }) =>
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
283
|
+
}, handle(config, async ({ project, environment, applicationId, slug, version, acknowledgeWarnings }) => {
|
|
284
|
+
await assertExternalComponentsAllowed(platform, applicationId, 'external_component_activate');
|
|
285
|
+
return platform.tenant('POST', project, `/components/${applicationId}/external/${slug}/activate`, {
|
|
286
|
+
environment,
|
|
287
|
+
body: { version, acknowledgeWarnings: acknowledgeWarnings === true }
|
|
288
|
+
});
|
|
289
|
+
}));
|
|
269
290
|
server.registerTool('external_component_versions', {
|
|
270
291
|
title: 'Paket sürümlerini listele',
|
|
271
292
|
description: 'Bir harici komponentin yayınlanmış paket sürümlerini, hangisinin aktif olduğunu ve her sürümün doğrulama raporunu listeler. Geri alınacak sürümü buradan seçin.',
|