@appaflytech/zeyrek-ai-mcp 0.0.7 → 0.0.9
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 +27 -21
- package/dist/config.js +2 -0
- package/dist/knowledge/backendConstraints.js +3 -0
- package/dist/knowledge/componentCatalog.js +172 -33
- package/dist/knowledge/componentEvents.js +35 -4
- package/dist/knowledge/errorPath.js +1 -1
- package/dist/knowledge/normalize.js +474 -23
- package/dist/knowledge/propTypes.js +5 -4
- package/dist/knowledge/rules.js +113 -6
- package/dist/knowledge/styleResolve.js +52 -5
- package/dist/knowledge/themeResolve.js +936 -0
- package/dist/knowledge/themeRules.js +221 -0
- package/dist/knowledge/themeSchema.js +335 -0
- package/dist/platform/domSummary.js +144 -0
- package/dist/platform/http.js +10 -2
- package/dist/platform/screenshot.js +492 -29
- package/dist/platform/screenshotMemory.js +55 -0
- package/dist/platform/strictArguments.js +32 -0
- package/dist/platform/writeDiff.js +6 -3
- package/dist/resources/examples/layout-app-shell.json +1 -1
- package/dist/resources/examples/page-sign-in.json +1 -1
- package/dist/resources/examples/theme-brand.json +162 -0
- package/dist/resources/guides/component.md +8 -2
- package/dist/resources/guides/expressions.md +6 -0
- package/dist/resources/guides/getting-started.md +6 -0
- package/dist/resources/guides/layout.md +36 -26
- package/dist/resources/guides/microservice.md +160 -6
- package/dist/resources/guides/page.md +165 -59
- package/dist/resources/guides/theme.md +210 -0
- package/dist/resources/guides/translation.md +13 -10
- package/dist/resources/guides/workflow.md +141 -7
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/CreateMicroserviceCommand.json +4 -1
- package/dist/resources/schemas/CreateWorkflowCommand.json +4 -1
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +4 -1
- package/dist/resources/schemas/PreviewWorkflowCommand.json +4 -1
- package/dist/resources/schemas/StepDto.json +4 -1
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +4 -1
- package/dist/resources/schemas/UpdateWorkflowCommand.json +4 -1
- package/dist/server.js +52 -42
- package/dist/tools/components.js +8 -0
- package/dist/tools/designSchemaPatch.js +152 -0
- package/dist/tools/flows.js +24 -21
- package/dist/tools/layouts.js +8 -8
- package/dist/tools/microservices.js +74 -10
- package/dist/tools/pages.js +275 -332
- package/dist/tools/projects.js +66 -9
- package/dist/tools/queries.js +72 -6
- package/dist/tools/schemaOps.js +280 -0
- package/dist/tools/screenWrite.js +2 -1
- package/dist/tools/screens.js +0 -7
- package/dist/tools/themes.js +163 -0
- package/dist/tools/workflows.js +10 -6
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/** Alan sırasından bağımsız anahtar: aynı istek her çağrıda aynı sha256'yı üretmeli. */
|
|
3
|
+
function stable(value) {
|
|
4
|
+
if (Array.isArray(value))
|
|
5
|
+
return value.map(stable);
|
|
6
|
+
if (value && typeof value === 'object') {
|
|
7
|
+
const source = value;
|
|
8
|
+
return Object.keys(source).sort().reduce((target, key) => {
|
|
9
|
+
if (source[key] !== undefined)
|
|
10
|
+
target[key] = stable(source[key]);
|
|
11
|
+
return target;
|
|
12
|
+
}, {});
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
export function captureKey(parts) {
|
|
17
|
+
return createHash('sha256').update(JSON.stringify(stable(parts))).digest('hex');
|
|
18
|
+
}
|
|
19
|
+
export function imageHash(image) {
|
|
20
|
+
return createHash('sha256').update(image).digest('hex');
|
|
21
|
+
}
|
|
22
|
+
export class CaptureMemory {
|
|
23
|
+
limit;
|
|
24
|
+
entries = new Map();
|
|
25
|
+
constructor(limit = 50) {
|
|
26
|
+
this.limit = limit;
|
|
27
|
+
}
|
|
28
|
+
recall(key) {
|
|
29
|
+
return this.entries.get(key);
|
|
30
|
+
}
|
|
31
|
+
remember(key, entry) {
|
|
32
|
+
// Yeniden yazılan anahtar halkanın SONUNA gider: sık çekilen sayfa düşmesin.
|
|
33
|
+
this.entries.delete(key);
|
|
34
|
+
this.entries.set(key, entry);
|
|
35
|
+
while (this.entries.size > this.limit) {
|
|
36
|
+
const oldest = this.entries.keys().next().value;
|
|
37
|
+
if (oldest === undefined)
|
|
38
|
+
break;
|
|
39
|
+
this.entries.delete(oldest);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
get size() {
|
|
43
|
+
return this.entries.size;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* SÜREÇ düzeyinde tek bellek.
|
|
48
|
+
*
|
|
49
|
+
* HTTP taşıması her POST için YENİ bir gateway sunucusu kuruyor (`index.ts` `app.post('/mcp')`
|
|
50
|
+
* → `createGatewayServer`), yani `registerPageTools` istek başına koşuyor. Bellek o fonksiyonun
|
|
51
|
+
* içinde yaratıldığında her çağrı boş bir halkayla başlıyor ve `diff` her seferinde "ilk kare"
|
|
52
|
+
* diyordu — ölçüldü 2026-09-16, dört ardışık çağrının dördü de `baselineAt` yok. Stdio
|
|
53
|
+
* taşımasında sunucu oturum boyu yaşadığı için kusur orada görünmüyordu.
|
|
54
|
+
*/
|
|
55
|
+
export const sharedCaptureMemory = new CaptureMemory();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
function isRawShape(value) {
|
|
3
|
+
if (!value || typeof value !== 'object' || '_def' in value)
|
|
4
|
+
return false;
|
|
5
|
+
return Object.values(value).every(entry => entry instanceof z.ZodType);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* GW-005 — tanınmayan üst düzey argüman REDDEDİLİR.
|
|
9
|
+
*
|
|
10
|
+
* SDK ham şekli `z.object(shape)` ile sarar ve zod'un varsayılanı bilinmeyen anahtarı hata vermeden
|
|
11
|
+
* ATMAKTIR: şemada olmayan bir alan doğrulamadan geçer, handler'a hiç ulaşmaz ve çağrı başarıyla
|
|
12
|
+
* biter. 2026-09-15 G-13'te `microservice_execute`/`microservice_debug`/`query_preview`'a verilen
|
|
13
|
+
* `parameters` böyle kayboldu — dört farklı filtre aynı gövdeyi döndü ve ölçüm aracı çağıranı
|
|
14
|
+
* olmayan bir sorgu kusuruna yönlendirdi. Tek tek tool'lara alan eklemek sınıfı kapatmaz; sessizlik
|
|
15
|
+
* burada, SDK'ya şema verilmeden önce kaldırılır.
|
|
16
|
+
*/
|
|
17
|
+
export function rejectUnknownArguments(server) {
|
|
18
|
+
const registerTool = server.registerTool.bind(server);
|
|
19
|
+
server.registerTool = ((name, config, callback) => {
|
|
20
|
+
if (!isRawShape(config.inputSchema))
|
|
21
|
+
return registerTool(name, config, callback);
|
|
22
|
+
const shape = config.inputSchema;
|
|
23
|
+
const accepted = Object.keys(shape).join(', ');
|
|
24
|
+
const inputSchema = z.object(shape, {
|
|
25
|
+
errorMap: (issue, context) => issue.code === 'unrecognized_keys'
|
|
26
|
+
? { message: `${name} şu üst düzey argümanları tanımıyor: ${issue.keys.map(key => `'${key}'`).join(', ')}. Tanınmayan alan sessizce yok sayılmaz — çağrı hiç gönderilmedi. Bu tool'un okuduğu alanlar: ${accepted}.` }
|
|
27
|
+
: { message: context.defaultError }
|
|
28
|
+
}).strict();
|
|
29
|
+
return registerTool(name, { ...config, inputSchema }, callback);
|
|
30
|
+
});
|
|
31
|
+
return server;
|
|
32
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PROP_VALUE_TYPES } from '../knowledge/normalize.js';
|
|
1
2
|
import { logStep } from '../observability/trace.js';
|
|
2
3
|
const maxDrops = 20;
|
|
3
4
|
const maxDepth = 12;
|
|
@@ -214,9 +215,11 @@ export function unwrapProps(value) {
|
|
|
214
215
|
const record = value;
|
|
215
216
|
const isProp = typeof record.type === 'string' && (Object.hasOwn(record, 'data') || Object.hasOwn(record, 'ref'));
|
|
216
217
|
if (isProp) {
|
|
217
|
-
// `
|
|
218
|
-
//
|
|
219
|
-
|
|
218
|
+
// Platform `static` dışındaki her tipte değeri `ref`'e yazar (Prop ctor'u,
|
|
219
|
+
// DesignComponentManagementSchema.cs:666); `data` ya boştur ya türetilmiştir (file URL'i, page
|
|
220
|
+
// slug'ı, translation tasarım yedeği). `data`'yı taşıyıcı saymak bağlı akışı her yazmada
|
|
221
|
+
// "kaydedilen null" gösteriyordu (S-7).
|
|
222
|
+
const carrier = record.type !== 'static' && PROP_VALUE_TYPES.has(record.type)
|
|
220
223
|
? (Object.hasOwn(record, 'ref') ? record.ref : record.data)
|
|
221
224
|
: (Object.hasOwn(record, 'data') ? record.data : record.ref);
|
|
222
225
|
return unwrapProps(carrier);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"sourceRef": "platform_guide('layout') Kural 5a/5b; zeyrek-frontend apps/studio/src/features/layout/layout.functions.ts (getDefaultLayout), packages/ng-apps-screen-builder/src/flex-layout.ts (getFlexChildStyle), packages/ng-apps-ui/src/shared/render/render.functions.ts"
|
|
7
7
|
},
|
|
8
8
|
"_rules": {
|
|
9
|
-
"viewsNotSchema": "Layout'ta şema alanının adı 'views'tir
|
|
9
|
+
"viewsNotSchema": "Layout'ta şema alanının adı 'views'tir (LAY-001). Kurulu layout'ta hedefli değişiklik layout_schema_patch micro-op'larıyla yazılır; tam ağaç layout_update ile.",
|
|
10
10
|
"singleSlot": "TEK slot. Sayfa şeması HER slot'a ayrı ayrı kopyalanır — iki slot sayfayı iki kez çizer ve elementId'leri tekrarlar (LAY-002 / LAY-006).",
|
|
11
11
|
"propValueField": "Statik prop'un değeri 'data' alanındadır ({ type:'static', ref:null, data }); 'ref' referans tipleri (flow/file) içindir. Ham değer yazarsanız gateway sarmalar ve normalizasyon notu döner.",
|
|
12
12
|
"slotRowIsOpenEnded": "Slot'un grid satırı açık uçludur (runtime 'y / auto' yazar): sayfa uzadıkça slot uzar. Slot'a sabit yükseklik vermeye çalışma.",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"rawRedirect": "redirect isRaw:true iken path ÇOK SATIRLI JS bloğudur ve son ifadenin değeri hedef adrestir. 'Korunan sayfaya gitmek isterken login'e düşen kullanıcıyı geri gönderme' deseni budur; yoksa sabit bir sayfaya gidilir (pageId + path).",
|
|
14
14
|
"objectProp": "Prop değeri nesne olabilir: icon → { type:'static', ref:{ name:'progress_activity' } }.",
|
|
15
15
|
"pageIsPublic": "Giriş sayfasına middlewareIds BAĞLANMAZ (guard'lı olsaydı kullanıcı giriş yapamazdı). Buna karşılık diğer sayfalar ve korunan uçlar middlewareIds ile bağlanır.",
|
|
16
|
-
"notificationIsHidden": "notification'ın şemasında isHidden 2026-08-26'dan beri VARDIR: props.isHidden'ı doğrudan bildirime yazabilirsin. Bu örnekteki box_message sarmalayıcısı o dönemin kalıntısıdır (crm koşumu B-10) ve tek bir bildirim için ARTIK GEREKMEZ — burada duruyor çünkü şeridi bir kaba sarıp birden çok parçayı birlikte gösterip gizliyor. appearance
|
|
16
|
+
"notificationIsHidden": "notification'ın şemasında isHidden 2026-08-26'dan beri VARDIR: props.isHidden'ı doğrudan bildirime yazabilirsin. Bu örnekteki box_message sarmalayıcısı o dönemin kalıntısıdır (crm koşumu B-10) ve tek bir bildirim için ARTIK GEREKMEZ — burada duruyor çünkü şeridi bir kaba sarıp birden çok parçayı birlikte gösterip gizliyor. appearance'ta ise isHidden alanı YOKTUR (2026-09-15'te kaldırıldı) — görünürlük yalnız props.isHidden'dır.",
|
|
17
17
|
"validationShape": "Validation gövdesi DÖRT alan taşır: { type, message, value, isActive }. 'name' anahtarı JsonIgnore'dur — {name, value, message} yazarsan tip enum varsayılanına düşer ve alan sessizce REGEX doğrulamasına döner. Tip adları TİRELİDİR (max-length / min-length / max-value / min-value); 'maxLength' backend'e yazılır ama runtime doğrulayıcı onu tanımaz ve doğrulama hiç koşmaz. Gateway düzeltebildiğini düzeltir, kalanını PAGE-016 ile reddeder."
|
|
18
18
|
},
|
|
19
19
|
"pageCreateArgs": {
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta": {
|
|
3
|
+
"synthetic": true,
|
|
4
|
+
"note": "Studio tema panelinin ürettiği kayıtla aynı şekil. Yalnız SAPAN değerler yazılır: typeScale/radiusScale/spacingScale/actions dokunulmayan kademeleri taşımaz, böylece platform varsayılanı değişince onları izlemeye devam ederler. Preset gövdeleri sabit hex değil var(--ng-*) kullanır — preset de temayı izlesin.",
|
|
5
|
+
"usage": "theme_update({ theme: <themeUpdateArgs.theme> }) — kısmi yazma; tamamını kurmak için replace: true. componentPresets tipleri doğrulansın istiyorsanız applicationId verin (THEME-011)."
|
|
6
|
+
},
|
|
7
|
+
"_rules": [
|
|
8
|
+
"shadow.color altı haneli hex OLMALI; başka yazım üç gölgeyi birden görünmez yapar (THEME-004).",
|
|
9
|
+
"Oranlar 0 < r <= 20; aralık dışı değer runtime'da sessizce yok sayılır (THEME-007).",
|
|
10
|
+
"mode:'dark' yazılacaksa paletteDark da yazılır — karanlıkta runtime palette'e BAKMAZ (THEME-009).",
|
|
11
|
+
"componentPresets bir kaskad değil BAŞLANGIÇ değeridir: mevcut düğümlere dokunmaz; bir tip en fazla 5 versiyon taşır ve defaultVersion versiyonlar arasında olmalıdır (THEME-002).",
|
|
12
|
+
"componentStyles EMEKLİ: panel ilk kayıtta onu componentPresets'e taşır ve canlı kaskad kopar (THEME-003). Bu örnek onu hiç taşımaz."
|
|
13
|
+
],
|
|
14
|
+
"themeUpdateArgs": {
|
|
15
|
+
"theme": {
|
|
16
|
+
"mode": "light",
|
|
17
|
+
"palette": {
|
|
18
|
+
"accent": {
|
|
19
|
+
"primary": "#4F46E5",
|
|
20
|
+
"hover": "#4338CA",
|
|
21
|
+
"muted": "#EEF2FF",
|
|
22
|
+
"subtle": "#F5F7FF"
|
|
23
|
+
},
|
|
24
|
+
"background": {
|
|
25
|
+
"canvas": "#F8FAFC",
|
|
26
|
+
"surface": "#FFFFFF",
|
|
27
|
+
"surfaceAlt": "#F1F5F9"
|
|
28
|
+
},
|
|
29
|
+
"border": {
|
|
30
|
+
"primary": "#E2E8F0",
|
|
31
|
+
"secondary": "#94A3B8"
|
|
32
|
+
},
|
|
33
|
+
"text": {
|
|
34
|
+
"primary": "#0F172A",
|
|
35
|
+
"secondary": "#475569",
|
|
36
|
+
"disabled": "#94A3B8"
|
|
37
|
+
},
|
|
38
|
+
"status": {
|
|
39
|
+
"success": "#15803D",
|
|
40
|
+
"warning": "#B45309",
|
|
41
|
+
"error": "#B91C1C",
|
|
42
|
+
"info": "#F1F5F9"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"paletteDark": {
|
|
46
|
+
"accent": {
|
|
47
|
+
"primary": "#818CF8",
|
|
48
|
+
"hover": "#A5B4FC",
|
|
49
|
+
"muted": "#1E1B4B",
|
|
50
|
+
"subtle": "#151338"
|
|
51
|
+
},
|
|
52
|
+
"background": {
|
|
53
|
+
"canvas": "#0B1120",
|
|
54
|
+
"surface": "#111827",
|
|
55
|
+
"surfaceAlt": "#0F172A"
|
|
56
|
+
},
|
|
57
|
+
"border": {
|
|
58
|
+
"primary": "#1F2937",
|
|
59
|
+
"secondary": "#475569"
|
|
60
|
+
},
|
|
61
|
+
"text": {
|
|
62
|
+
"primary": "#E2E8F0",
|
|
63
|
+
"secondary": "#94A3B8",
|
|
64
|
+
"disabled": "#475569"
|
|
65
|
+
},
|
|
66
|
+
"status": {
|
|
67
|
+
"success": "#34D399",
|
|
68
|
+
"warning": "#FBBF24",
|
|
69
|
+
"error": "#F87171",
|
|
70
|
+
"info": "#1F2937"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"fontFamily": "Inter Tight",
|
|
74
|
+
"headingFontFamily": "Sora",
|
|
75
|
+
"fontSize": "15px",
|
|
76
|
+
"fontWeight": "400",
|
|
77
|
+
"typeScale": {
|
|
78
|
+
"h1": 2.5,
|
|
79
|
+
"small": 0.8
|
|
80
|
+
},
|
|
81
|
+
"spacing": "12px",
|
|
82
|
+
"spacingScale": {
|
|
83
|
+
"xl": 5
|
|
84
|
+
},
|
|
85
|
+
"borderRadius": "8px",
|
|
86
|
+
"radiusScale": {
|
|
87
|
+
"lg": 2
|
|
88
|
+
},
|
|
89
|
+
"shadow": {
|
|
90
|
+
"offsetX": 0,
|
|
91
|
+
"offsetY": 6,
|
|
92
|
+
"blur": 12,
|
|
93
|
+
"spread": -2,
|
|
94
|
+
"color": "#1E1B4B",
|
|
95
|
+
"opacity": 18
|
|
96
|
+
},
|
|
97
|
+
"defaultInputSize": "md",
|
|
98
|
+
"actions": {
|
|
99
|
+
"blue": "#4F46E5",
|
|
100
|
+
"red": "#E11D48"
|
|
101
|
+
},
|
|
102
|
+
"presets": {
|
|
103
|
+
"kart": {
|
|
104
|
+
"padding": "16px",
|
|
105
|
+
"borderRadius": "var(--ng-radius-lg)",
|
|
106
|
+
"background": "var(--ng-background-surface)",
|
|
107
|
+
"border": "1px solid var(--ng-border-primary)",
|
|
108
|
+
"boxShadow": "var(--ng-shadow-sm)",
|
|
109
|
+
"transition": "border-color 140ms ease, box-shadow 140ms ease",
|
|
110
|
+
"&:hover": {
|
|
111
|
+
"borderColor": "var(--ng-accent-primary)",
|
|
112
|
+
"boxShadow": "var(--ng-shadow-md)"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"sessizMetin": {
|
|
116
|
+
"color": "var(--ng-text-secondary)",
|
|
117
|
+
"fontSize": "var(--ng-font-size-small)"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"componentPresets": {
|
|
121
|
+
"button": {
|
|
122
|
+
"defaultVersion": "V1",
|
|
123
|
+
"versions": {
|
|
124
|
+
"V1": {
|
|
125
|
+
"props": {
|
|
126
|
+
"size": "lg"
|
|
127
|
+
},
|
|
128
|
+
"appearance": {
|
|
129
|
+
"marginType": "custom",
|
|
130
|
+
"marginValues": {
|
|
131
|
+
"top": 0,
|
|
132
|
+
"right": 0,
|
|
133
|
+
"bottom": 12,
|
|
134
|
+
"left": 0
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"V2": {
|
|
139
|
+
"props": {
|
|
140
|
+
"size": "sm",
|
|
141
|
+
"type": "secondary"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"container": {
|
|
147
|
+
"defaultVersion": "V1",
|
|
148
|
+
"versions": {
|
|
149
|
+
"V1": {
|
|
150
|
+
"props": {
|
|
151
|
+
"layout": "flex",
|
|
152
|
+
"direction": "row",
|
|
153
|
+
"gap": "medium",
|
|
154
|
+
"wrap": true
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -60,7 +60,10 @@ Doğrulama mesajını çeviriye bağlamak ayrı bir sözleşmedir (`t:` öneki,
|
|
|
60
60
|
(`eventcalendar` · `importwizard` · `kanban` · `signature` · `stepper`) dolar — `kanban` ve
|
|
61
61
|
`eventcalendar` yükü `self`'e HİÇ yazmaz, yalnız `event.data` ile okunur (ayrım
|
|
62
62
|
`component_get` sözleşme notlarında).
|
|
63
|
-
- Akış bağlama: `flow_create` → `
|
|
63
|
+
- Akış bağlama: `flow_create` → `set_event` (sayfada `page_schema_patch`, layout'ta
|
|
64
|
+
`layout_schema_patch`, widget'ta `component_schema_patch`). Akış isteği barındırıcının şemasını
|
|
65
|
+
yazmaz; bağ yalnız bu yamayla kurulur, silmede de önce `remove_event` sonra `flow_delete`.
|
|
66
|
+
İstisna: `html` komponentinin
|
|
64
67
|
aksiyonları kendi `flow` prop'uyla bağlanır (`platform_guide('html')`).
|
|
65
68
|
|
|
66
69
|
## Stil
|
|
@@ -87,6 +90,9 @@ Widget, kendi komponent ağacını taşıyan yeniden kullanılabilir pakettir (`
|
|
|
87
90
|
`elementId`'leri kullanır; Studio düzenleyicisinin gösterdiği `__widget__` yer tutucusu
|
|
88
91
|
yalnız editör katmanıdır (kayıt anında gerçek id'ye çevrilir) — API'den yazarken yer
|
|
89
92
|
tutucu KULLANMA.
|
|
93
|
+
4. **Ağacı değiştirmek:** `component_schema_patch` (widget kaydının `id`'si) sayfa ile aynı
|
|
94
|
+
micro-op'ları `PATCH /components/{app}/{id}/schema`'ya yazar; `component_update` ise slug alan
|
|
95
|
+
tam gövde PUT'tur. Widget'ın düzey olayı yoktur, `remove_event` yalnız komponent hedefler.
|
|
90
96
|
|
|
91
97
|
## `states` ve `appearance` sözlükleri
|
|
92
98
|
|
|
@@ -117,7 +123,7 @@ Her şema düğümünde iki sözlük vardır; ikisi de ortak render katmanında
|
|
|
117
123
|
| `widthType` | `cover` · `contain` · `auto` · `fixed` · `fill` | İlk ikisi görsel/medya sığdırma. Kalanı **flex (ve eski cssgrid) kabın çocuğunun genişlik modu** (2026-09-01): `auto` içerik kadar, `fixed` `widthString`'den, `fill` kabın tüm genişliği (satırda `flex:1 1 100%`, sütunda `align-self:stretch`). **Yazılmazsa eski 12 kolon `blocks.size.w` payı geçerlidir** — öncelik: `fill` > `fixed` > `auto` > span |
|
|
118
124
|
| `widthString` / `heightString` | CSS uzunluğu | Sabit ölçü; **yalnız ilgili `*Type: 'fixed'` iken okunur** (aksi PAGE-017 uyarısı). Kabul: çıplak sayı (px sayılır) · `px % vw vh vmin vmax rem em ch` birimli değer · `calc(...)`. Negatif/`pt`/`fr`/`auto` GEÇMEZ — platform kaydeder ama panel ve runtime sessizce düşürür (PAGE-018). Eski `widthPx` alanı 2026-09-01'de kaldırıldı |
|
|
119
125
|
| `marginType` / `marginValue` | `normal` · `none` · `custom` + px | Dış boşluk: **yazılmazsa `normal` sayılır** = her kenara 4px (`spacing.ts` `CANVAS_NORMAL_MARGIN`); custom=`marginValue`. Bileşenleri dip dibe dizmek için `none` ŞART — `gap:'none'` olsa bile normal margin komşular arasında 8px bırakır (sıkı dizilim tarifi: `platform_guide('page')` Kural 1f-2) |
|
|
120
|
-
| `paddingType` / `paddingValue` | `normal` · `none` · `custom` + px |
|
|
126
|
+
| `paddingType` / `paddingValue` | `normal` · `none` · `custom` + px | İç boşluk: normal=10px. **Yalnız droppable kaplarda ve tipli stil modelindeki yapraklarda (box · text · container · statcard · icon · form) çizilir**; `slot`, kabuk kökleri (`layout`/`layout-shell`) ve `modal`/`drawer`/`auth-layout` hiç almaz — platform 200 döner, ekran değişmez (PAGE-029). Değerler piksel SAYISIDIR: `24`, `"24px"` değil (PAGE-030) |
|
|
121
127
|
| `alignType` | `left` · `center` · `right` | İçerik hizalama (destekleyen komponentlerde) |
|
|
122
128
|
| `aspectRatio` | sayı | En-boy oranı kilidi (medya komponentleri) |
|
|
123
129
|
|
|
@@ -103,6 +103,7 @@ dalından devam eder.
|
|
|
103
103
|
| `event` | `{name, data, source: {id, props}}` |
|
|
104
104
|
| `cookie` | `cookie.get(name)` / `cookie.set(name, value, {expiresInHours, path})` / `cookie.remove(name)` — tarayıcı cookie'si |
|
|
105
105
|
| `setComponentProperty(name, key, value)` / `getComponentProperty(name, key)` | fonksiyon alternatifi |
|
|
106
|
+
| `resetForm(name)` | Formu sıfırlar: alanlar başlangıç değerine döner, form "gönderilmemiş" olur, doğrulama mesajları silinir. Kayıt sonrası "yeni kayıt" için alanları tek tek `null`'a çekme — gönderilmiş formda her biri "zorunlu alan" mesajı çıkarır. Ad ya da komponent değişkeni alır: `resetForm('risk_form')` / `resetForm(risk_form)`. **Yalnız UI flow kodunda** |
|
|
106
107
|
| `LocalStorage` · `Widget` · `params` | yerel veri · widget bağlamı · olay parametreleri |
|
|
107
108
|
| `t(key)` | Çeviri anahtarını çözer: aktif dil → projenin varsayılan dili → anahtarın kendisi. Boş string de "eksik" sayılır. Sözlük `machine.context.state.translations`'tan gelir; dil `language-selector` ile değişince bir sonraki çağrı yeni dili görür. **Yalnız UI flow kodunda vardır** — backend ifadelerinde karşılığı `Loc()`'tur (`platform_guide('workflow')`) | `t('home.welcome')` |
|
|
108
109
|
| `log(...)` | console (proxy'leri temizler) |
|
|
@@ -130,6 +131,11 @@ prop `type: 'code'` olur, **ifade `ref` alanına `{{ }}` içinde** yazılır, `d
|
|
|
130
131
|
değerini taşır:
|
|
131
132
|
`"text": { "type": "code", "data": "Button text", "ref": "{{ state.page.MyTest.isActive ? 'Test' : 'FalseTest' }}" }`
|
|
132
133
|
|
|
134
|
+
> **Prop'ta parantezsiz ifade METİNDİR (PAGE-032).** Akış adımındaki `value.type: 'code'`
|
|
135
|
+
> ifadeyi doğrudan koşturur; prop'taki `code` ise bir şablondur ve yalnız `{{ }}` içini
|
|
136
|
+
> çalıştırır. `"ref": "new Date().getFullYear()"` prop'a harfi harfine o metni yazar, hata
|
|
137
|
+
> üretmez — `page_schema_patch` bu yüzden parantezsiz prop ifadesini reddeder.
|
|
138
|
+
|
|
133
139
|
## 3. Adım argümanlarında `value.type` çözümlemesi
|
|
134
140
|
|
|
135
141
|
`microservice`/`setter` adımlarının `parameters[]`/`iteratees[]` değerlerinde:
|
|
@@ -140,7 +140,13 @@ koda baktığını gizlemek yerine raporlamak.
|
|
|
140
140
|
- create/update → ilgili `*_get` ile geri oku
|
|
141
141
|
- microservice → `microservice_execute`, beklenmedik sonuçta `microservice_debug`
|
|
142
142
|
- workflow → `workflow_preview`; automation → `automation_trigger` + `automation_histories`
|
|
143
|
+
- zamanlanmış iş (`schedule-job`) → ÖNCE `workflow_preview` / `microservice_debug` (rollback'li adım
|
|
144
|
+
izi), SONRA `microservice_schedule_control` `trigger` + `microservice_job_history`. Geçmiş
|
|
145
|
+
`failed` satırında patlayan adımı ve sebebini yazar ama adım izini vermez
|
|
146
|
+
(`platform_guide('microservice')` §Zamanlanmış işin gerçek sonucunu görmek)
|
|
143
147
|
- "API 200 döndü" tek başına bitti saymaz; politika bulgularını (`policyFindings`) oku ve gereğini yap
|
|
148
|
+
- Tool'un şemasında olmayan üst düzey argüman **reddedilir** ve hata okunan alanları listeler
|
|
149
|
+
(GW-005). Bir argüman kabul edildiyse gateway onu okuyor demektir.
|
|
144
150
|
|
|
145
151
|
|
|
146
152
|
## Yazdıktan sonra `silentlyDropped` alanına bak
|
|
@@ -12,22 +12,29 @@ kutusu layout modülünde süzülmez — tüm katalog kullanılabilir.
|
|
|
12
12
|
|
|
13
13
|
**2. Şema alanının adı `schema` değil `views`.** (LAY-001)
|
|
14
14
|
|
|
15
|
-
**3.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
`views` göndermezsen mevcut ağaç korunur.
|
|
30
|
-
|
|
15
|
+
**3. Ağaç değişikliği `layout_schema_patch` ile (2026-09-14).** Platform
|
|
16
|
+
`PATCH /layouts/{app}/{id}/schema` ucunu verir ve sayfa ile **aynı** micro-op sözlüğünü konuşur:
|
|
17
|
+
`add_component`, `remove_component`, `move_component`, `replace_prop`, `set_event`, `remove_event`,
|
|
18
|
+
`resize_component`, `set_prop_type`, `reorder` ve diğerleri `page_schema_patch`'teki gibi yazılır.
|
|
19
|
+
Dokunulan düğümler tam doğrulanır, geri kalan ağaç yapısal; istek atomiktir. Sayfadan farkları:
|
|
20
|
+
|
|
21
|
+
- Kök ekleme `parent: 'root'`'a gider — layout'ta `page_container` yoktur.
|
|
22
|
+
- `remove_event` `target: 'page'` layout düzeyi olayları hedefler.
|
|
23
|
+
- `baseVersion` yoktur: son yazan kazanır. Hedefleri yazmadan hemen önce `layout_schema_get` ile oku.
|
|
24
|
+
- Slot'u silen ya da ikinci slot ekleyen yama yazılır ama LAY-002 / LAY-006 uyarısı döner (Kural 4).
|
|
25
|
+
- Bağı kalmayan akışı platform kalıcı siler; gateway böyle bir yamayı `allowFlowDeletion: true`
|
|
26
|
+
olmadan göndermez (G-21, sayfadakiyle aynı).
|
|
27
|
+
|
|
28
|
+
Okumak için `layout_schema_get` (summary kipi hedef bulmak için yeterlidir); tam ağacı kendin
|
|
29
|
+
yazacaksan `layout_update` (`views` göndermezsen mevcut ağaç korunur).
|
|
30
|
+
|
|
31
|
+
**3a. `layout_patch` düz JSON Patch içindir.** Ad, `parameters`, `events` gibi ağaç dışı alanlar ya
|
|
32
|
+
da yol gerektiren bir değişiklik için: layout'u okur, JSON Patch'i ve kendi normalizasyonlarını
|
|
33
|
+
uygular ve **farkı** `PATCH /layouts/{app}/{id}`'ye `{ baseVersion, ops }` olarak yazar (09-04 koşusu
|
|
34
|
+
Y-25). Yol İNDEKS yerine SEÇİCİ alır: `/views/0/children[elementId=baslik]/props/content/data`.
|
|
35
|
+
Okunan kaydın `version`'ı `baseVersion` olarak gider; araya başka bir yazma girdiyse **409** döner
|
|
36
|
+
ve hiçbir op uygulanmaz — doğru tepki `layout_schema_get` ile yeniden okuyup patch'i güncel hâle
|
|
37
|
+
göre kurmaktır. `version` bir **string**tir (mikrosaniye zaman damgası) — sayıya çevirme.
|
|
31
38
|
|
|
32
39
|
**4. TEK slot.** Sayfa şeması **her** slot'a ayrı ayrı kopyalanır — iki slot, sayfayı iki
|
|
33
40
|
kez çizer ve `elementId`'leri tekrarlar. (LAY-002 / LAY-006)
|
|
@@ -92,6 +99,12 @@ container isWrapper:true heightType:'fill' layout:'flex' direction:'row' gap:
|
|
|
92
99
|
uçludur (`y / auto`), yani sayfa uzadıkça slot uzar.
|
|
93
100
|
- **Kaydırma:** `fill` + `states.isScrollable:true` verilen düğüm büyümek yerine İÇİNDE
|
|
94
101
|
kaydırır — uzun içerikte kabuğu sabit tutmanın yolu budur.
|
|
102
|
+
- **Slot'un kenar boşluğu margin'dir, padding değil.** Slot droppable değildir; ona yazılan
|
|
103
|
+
`paddingType`/`paddingValue` hiçbir kutuya çizilmez (LAY-010). Her sayfanın kenardan uzak
|
|
104
|
+
durmasını tek yerden istiyorsan slot'a `appearance.marginType: 'custom'` + `marginValue: 24`
|
|
105
|
+
yaz — margin slot'un sarmalayıcısına iç boşluk olarak iner ve slot'un zemini olmadığı için
|
|
106
|
+
sonuç padding'le aynıdır. Studio iskeleti slot'a zaten 8px custom margin verir. Değer SAYIDIR
|
|
107
|
+
(`24`, `"24px"` değil — LAY-011). Her sayfaya sarmalayıcı container eklemek gerekmez.
|
|
95
108
|
- **MOBİL UYARISI:** bu ağaç `flex` olduğu için telefonda YIĞILMAZ (Kural 7) — 375px'te yan
|
|
96
109
|
menü ince bir şerite iner. Telefonda alt alta düşmesi gereken bir kabuk için kökü
|
|
97
110
|
`layout:'grid'` kur; o zaman `fill`'in flex anlamı (`flex:1 1 auto`) devreye girmez,
|
|
@@ -135,7 +148,8 @@ bağlantı nesnesi ya da tam yol).
|
|
|
135
148
|
## Çeviri: header/sidebar etiketini anahtara bağlamak
|
|
136
149
|
|
|
137
150
|
Layout'un `views` ağacındaki bir etiketi çeviriye bağlamak için **bütün ağacı yeniden yazma**.
|
|
138
|
-
`
|
|
151
|
+
`layout_schema_patch`'in `set_prop_type` op'u prop'un tipini yerinde değiştirir (`layout_patch` de
|
|
152
|
+
aynı op'u tanır ve JSON Patch ile karışık kabul eder):
|
|
139
153
|
|
|
140
154
|
```jsonc
|
|
141
155
|
{ "op": "set_prop_type", "target": "app_header_title", "prop": "content",
|
|
@@ -145,15 +159,11 @@ Layout'un `views` ağacındaki bir etiketi çeviriye bağlamak için **bütün a
|
|
|
145
159
|
- Anahtar **`ref`'te** yaşar, `data`'da değil — runtime `data`'yı her turda çözümlenmiş değerle
|
|
146
160
|
ezer. `ref` boşsa gateway isteği göndermeden reddeder.
|
|
147
161
|
- Mevcut statik metin `data`'da yedek olarak KALIR, böylece Studio canvas'ında boş kutu görünmez.
|
|
148
|
-
- `set_prop_type` ile JSON Patch aynı `ops` listesinde karışık verilebilir;
|
|
149
|
-
uygulanır, sonra patch yolları çözülür.
|
|
150
|
-
- Aynı op sayfa tarafında `page_schema_patch` ile çalışır —
|
|
151
|
-
`translation_list` ile bulun; fallback zinciri ve `t:`
|
|
152
|
-
`platform_guide('translation')`'da.
|
|
153
|
-
|
|
154
|
-
> Layout'un diğer micro-op'ları YOKTUR: `add_component`, `remove_component`, `replace_prop` ve
|
|
155
|
-
> arkadaşları yalnız sayfa hattındadır. Layout'ta düğüm eklemek/silmek için JSON Patch ya da
|
|
156
|
-
> `layout_update` kullanılır.
|
|
162
|
+
- `layout_patch`'te `set_prop_type` ile JSON Patch aynı `ops` listesinde karışık verilebilir;
|
|
163
|
+
micro-op'lar önce uygulanır, sonra patch yolları çözülür.
|
|
164
|
+
- Aynı op sayfa tarafında `page_schema_patch`, widget'ta `component_schema_patch` ile çalışır —
|
|
165
|
+
sözleşme birebir aynıdır. Anahtarları `translation_list` ile bulun; fallback zinciri ve `t:`
|
|
166
|
+
doğrulama mesajı sözleşmesi `platform_guide('translation')`'da.
|
|
157
167
|
|
|
158
168
|
## Sayfayı layout'a bağlama
|
|
159
169
|
|