@appaflytech/zeyrek-ai-mcp 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/.env.example +21 -7
  2. package/.env.production.example +42 -0
  3. package/README.md +14 -7
  4. package/dist/config.js +113 -47
  5. package/dist/knowledge/componentCatalog.js +474 -31
  6. package/dist/knowledge/componentEvents.js +150 -12
  7. package/dist/knowledge/errorPath.js +64 -0
  8. package/dist/knowledge/normalize.js +12 -1
  9. package/dist/knowledge/outlines.js +6 -0
  10. package/dist/knowledge/rules.js +184 -3
  11. package/dist/knowledge/styleResolve.js +485 -0
  12. package/dist/observability/trace.js +4 -0
  13. package/dist/platform/http.js +3 -0
  14. package/dist/platform/responses.js +80 -4
  15. package/dist/platform/screenshot.js +106 -0
  16. package/dist/resources/examples/layout-app-shell.json +368 -0
  17. package/dist/resources/examples/microservice-table-list.json +1 -0
  18. package/dist/resources/examples/middleware-authenticate.json +243 -47
  19. package/dist/resources/examples/workflow-basic.json +24 -2
  20. package/dist/resources/guides/component.md +6 -3
  21. package/dist/resources/guides/external-component.md +129 -0
  22. package/dist/resources/guides/layout.md +147 -0
  23. package/dist/resources/guides/microservice.md +35 -0
  24. package/dist/resources/guides/middleware.md +10 -0
  25. package/dist/resources/guides/page.md +132 -14
  26. package/dist/resources/guides/workflow.md +127 -2
  27. package/dist/server.js +2 -0
  28. package/dist/tools/externalComponents.js +285 -0
  29. package/dist/tools/layouts.js +48 -6
  30. package/dist/tools/microservices.js +2 -2
  31. package/dist/tools/pages.js +98 -30
  32. package/dist/tools/platformInfo.js +2 -2
  33. package/dist/tools/screens.js +36 -0
  34. package/dist/tools/workflows.js +3 -3
  35. package/package.json +4 -1
@@ -7,6 +7,7 @@
7
7
  "definition": {
8
8
  "name": "Authenticate",
9
9
  "slug": "authenticate",
10
+ "description": "Korunan uçların önünde koşar: token doğrular ve user değişkenini kurar.",
10
11
  "type": "middleware",
11
12
  "steps": [
12
13
  {
@@ -14,39 +15,65 @@
14
15
  "name": "start",
15
16
  "type": "start",
16
17
  "branches": [
17
- { "id": "<GUID-2>", "name": "start", "type": "success", "nextStepId": "<GUID-3>" }
18
+ {
19
+ "id": "<GUID-2>",
20
+ "name": "start",
21
+ "type": "success",
22
+ "nextStepId": "<GUID-3>"
23
+ }
18
24
  ]
19
25
  },
20
26
  {
21
27
  "id": "<GUID-3>",
22
28
  "name": "token",
29
+ "description": "Çerezden/başlıktan ham token değerini çıkarır.",
23
30
  "type": "code",
24
31
  "rule": {
25
32
  "stepType": "code",
26
33
  "expression": "return system.validateToken(cookie.APP_Token)"
27
34
  },
28
35
  "branches": [
29
- { "id": "<GUID-4>", "name": "success", "type": "success", "nextStepId": "<GUID-5>" }
36
+ {
37
+ "id": "<GUID-4>",
38
+ "name": "success",
39
+ "type": "success",
40
+ "nextStepId": "<GUID-5>"
41
+ }
30
42
  ]
31
43
  },
32
44
  {
33
45
  "id": "<GUID-5>",
34
46
  "name": "token_check",
47
+ "description": "Token yoksa 401 dalına, varsa doğrulamaya yönlendirir.",
35
48
  "type": "condition",
36
49
  "rule": {
37
50
  "stepType": "condition",
38
51
  "items": [
39
- { "expression": "token.data.isValid && token.data.claims.userId", "branchId": "<GUID-6>" }
52
+ {
53
+ "expression": "token.data.isValid && token.data.claims.userId",
54
+ "branchId": "<GUID-6>"
55
+ }
40
56
  ]
41
57
  },
42
58
  "branches": [
43
- { "id": "<GUID-6>", "name": "<GUID-6>", "type": "success", "nextStepId": "<GUID-8>" },
44
- { "id": "<GUID-7>", "name": "else", "type": "success", "nextStepId": "<GUID-14>" }
59
+ {
60
+ "id": "<GUID-6>",
61
+ "name": "<GUID-6>",
62
+ "type": "success",
63
+ "nextStepId": "<GUID-8>"
64
+ },
65
+ {
66
+ "id": "<GUID-7>",
67
+ "name": "else",
68
+ "type": "success",
69
+ "nextStepId": "<GUID-14>"
70
+ }
45
71
  ]
46
72
  },
47
73
  {
48
74
  "id": "<GUID-8>",
49
75
  "name": "userTable",
76
+ "description": "Token sahibini users tablosundan rolleriyle birlikte okur.",
50
77
  "type": "table",
51
78
  "rule": {
52
79
  "stepType": "table",
@@ -55,24 +82,62 @@
55
82
  "operation": "get",
56
83
  "isSingle": true,
57
84
  "selectFields": [
58
- { "alias": "users", "fieldId": "<id alanı id>", "fieldSlug": "id" },
59
- { "alias": "users", "fieldId": "<email alanı id>", "fieldSlug": "email" },
60
- { "alias": "users", "fieldId": "<first_name alanı id>", "fieldSlug": "first_name" }
85
+ {
86
+ "alias": "users",
87
+ "fieldId": "<id alanı id>",
88
+ "fieldSlug": "id"
89
+ },
90
+ {
91
+ "alias": "users",
92
+ "fieldId": "<email alanı id>",
93
+ "fieldSlug": "email"
94
+ },
95
+ {
96
+ "alias": "users",
97
+ "fieldId": "<first_name alanı id>",
98
+ "fieldSlug": "first_name"
99
+ }
61
100
  ],
62
101
  "filters": [
63
- { "alias": "users", "fieldId": "<id alanı id>", "fieldSlug": "id", "operator": "eq", "source": "expression", "value": "token.data.claims.userId", "filterType": "single", "conditionType": "and", "isRequired": true, "children": [], "order": 0 }
102
+ {
103
+ "alias": "users",
104
+ "fieldId": "<id alanı id>",
105
+ "fieldSlug": "id",
106
+ "operator": "eq",
107
+ "source": "expression",
108
+ "value": "token.data.claims.userId",
109
+ "filterType": "single",
110
+ "conditionType": "and",
111
+ "isRequired": true,
112
+ "children": [],
113
+ "order": 0
114
+ }
64
115
  ],
65
116
  "joins": [],
66
- "sort": { "name": "sortField", "type": "sortType", "source": "query-string" },
67
- "limit": { "name": "limit", "offset": "offset", "source": "query-string" }
117
+ "sort": {
118
+ "name": "sortField",
119
+ "type": "sortType",
120
+ "source": "query-string"
121
+ },
122
+ "limit": {
123
+ "name": "limit",
124
+ "offset": "offset",
125
+ "source": "query-string"
126
+ }
68
127
  },
69
128
  "branches": [
70
- { "id": "<GUID-9>", "name": "success", "type": "success", "nextStepId": "<GUID-10>" }
129
+ {
130
+ "id": "<GUID-9>",
131
+ "name": "success",
132
+ "type": "success",
133
+ "nextStepId": "<GUID-10>"
134
+ }
71
135
  ]
72
136
  },
73
137
  {
74
138
  "id": "<GUID-10>",
75
139
  "name": "setUser",
140
+ "description": "Bulunan kullanıcıyı 'user' değişkenine yazar; sonraki uçlar bunu okur.",
76
141
  "type": "set-user",
77
142
  "rule": {
78
143
  "stepType": "set-user",
@@ -80,12 +145,18 @@
80
145
  "dataTransferObjectId": "<user DTO id — opsiyonel; verilirse workflow_middleware_variables şemayı listeler>"
81
146
  },
82
147
  "branches": [
83
- { "id": "<GUID-11>", "name": "success", "type": "success", "nextStepId": "<GUID-12>" }
148
+ {
149
+ "id": "<GUID-11>",
150
+ "name": "success",
151
+ "type": "success",
152
+ "nextStepId": "<GUID-12>"
153
+ }
84
154
  ]
85
155
  },
86
156
  {
87
157
  "id": "<GUID-12>",
88
158
  "name": "successResponse",
159
+ "description": "Kapıyı açar, istek asıl uca devam eder.",
89
160
  "type": "response",
90
161
  "rule": {
91
162
  "stepType": "response",
@@ -98,6 +169,7 @@
98
169
  {
99
170
  "id": "<GUID-14>",
100
171
  "name": "unauthorizedResponse",
172
+ "description": "Kimliksiz/geçersiz isteği 401 ile keser.",
101
173
  "type": "response",
102
174
  "rule": {
103
175
  "stepType": "response",
@@ -117,78 +189,202 @@
117
189
  "relationFieldTrap": "user_roles.role_id bir table adımında NESNE DEĞİL düz FK'dır (row_list her ilişki için join'i kendisi üretir, table adımı yalnız joins'te bildirileni çevirir). 'p.role_id.slug' undefined döner, roller sessizce boşalır ve Authorized her zaman false olur. Aşağıdaki ifade iki şekle de dayanır.",
118
190
  "steps": [
119
191
  {
120
- "id": "<GUID-R1>", "name": "rolesTable", "type": "table",
192
+ "id": "<GUID-R1>",
193
+ "name": "rolesTable",
194
+ "type": "table",
121
195
  "rule": {
122
- "stepType": "table", "datasourceId": "<datasource id>", "entityId": "<user_roles entity id>",
123
- "operation": "get", "alias": "user_roles", "isSingle": false,
196
+ "stepType": "table",
197
+ "datasourceId": "<datasource id>",
198
+ "entityId": "<user_roles entity id>",
199
+ "operation": "get",
200
+ "alias": "user_roles",
201
+ "isSingle": false,
124
202
  "selectFields": [
125
- { "alias": "user_roles", "fieldId": "<user_roles.id>", "fieldSlug": "id" },
126
- { "alias": "user_roles", "fieldId": "<user_roles.role_id>", "fieldSlug": "role_id" }
203
+ {
204
+ "alias": "user_roles",
205
+ "fieldId": "<user_roles.id>",
206
+ "fieldSlug": "id"
207
+ },
208
+ {
209
+ "alias": "user_roles",
210
+ "fieldId": "<user_roles.role_id>",
211
+ "fieldSlug": "role_id"
212
+ }
127
213
  ],
128
214
  "filters": [
129
- { "alias": "user_roles", "fieldId": "<user_roles.user_id>", "operator": "eq", "source": "expression",
130
- "value": "userTable.data.id", "filterType": "single", "conditionType": "and",
131
- "isRequired": true, "children": [], "order": 0 }
215
+ {
216
+ "alias": "user_roles",
217
+ "fieldId": "<user_roles.user_id>",
218
+ "operator": "eq",
219
+ "source": "expression",
220
+ "value": "userTable.data.id",
221
+ "filterType": "single",
222
+ "conditionType": "and",
223
+ "isRequired": true,
224
+ "children": [],
225
+ "order": 0
226
+ }
132
227
  ],
133
- "joins": [], "fields": [], "returnFields": [],
134
- "sort": { "name": "sortField", "type": "sortType", "source": "query-string" },
135
- "limit": { "name": "limit", "offset": "offset", "source": "query-string" }
228
+ "joins": [],
229
+ "fields": [],
230
+ "returnFields": [],
231
+ "sort": {
232
+ "name": "sortField",
233
+ "type": "sortType",
234
+ "source": "query-string"
235
+ },
236
+ "limit": {
237
+ "name": "limit",
238
+ "offset": "offset",
239
+ "source": "query-string"
240
+ }
136
241
  },
137
242
  "branches": [
138
- { "id": "<GUID-R2>", "name": "success", "type": "success", "nextStepId": "<GUID-R3>" },
139
- { "id": "<GUID-R2b>", "name": "fail", "type": "fail", "nextStepId": "<GUID-14>" }
243
+ {
244
+ "id": "<GUID-R2>",
245
+ "name": "success",
246
+ "type": "success",
247
+ "nextStepId": "<GUID-R3>"
248
+ },
249
+ {
250
+ "id": "<GUID-R2b>",
251
+ "name": "fail",
252
+ "type": "fail",
253
+ "nextStepId": "<GUID-14>"
254
+ }
140
255
  ]
141
256
  },
142
257
  {
143
- "id": "<GUID-R3>", "name": "allRoles", "type": "table",
258
+ "id": "<GUID-R3>",
259
+ "name": "allRoles",
260
+ "type": "table",
144
261
  "rule": {
145
- "stepType": "table", "datasourceId": "<datasource id>", "entityId": "<roles entity id>",
146
- "operation": "get", "alias": "roles", "isSingle": false,
262
+ "stepType": "table",
263
+ "datasourceId": "<datasource id>",
264
+ "entityId": "<roles entity id>",
265
+ "operation": "get",
266
+ "alias": "roles",
267
+ "isSingle": false,
147
268
  "selectFields": [
148
- { "alias": "roles", "fieldId": "<roles.id>", "fieldSlug": "id" },
149
- { "alias": "roles", "fieldId": "<roles.slug>", "fieldSlug": "slug" }
269
+ {
270
+ "alias": "roles",
271
+ "fieldId": "<roles.id>",
272
+ "fieldSlug": "id"
273
+ },
274
+ {
275
+ "alias": "roles",
276
+ "fieldId": "<roles.slug>",
277
+ "fieldSlug": "slug"
278
+ }
150
279
  ],
151
- "filters": [], "joins": [], "fields": [], "returnFields": [],
152
- "sort": { "name": "sortField", "type": "sortType", "source": "query-string" },
153
- "limit": { "name": "limit", "offset": "offset", "source": "query-string" }
280
+ "filters": [],
281
+ "joins": [],
282
+ "fields": [],
283
+ "returnFields": [],
284
+ "sort": {
285
+ "name": "sortField",
286
+ "type": "sortType",
287
+ "source": "query-string"
288
+ },
289
+ "limit": {
290
+ "name": "limit",
291
+ "offset": "offset",
292
+ "source": "query-string"
293
+ }
154
294
  },
155
295
  "branches": [
156
- { "id": "<GUID-R4>", "name": "success", "type": "success", "nextStepId": "<GUID-R5>" },
157
- { "id": "<GUID-R4b>", "name": "fail", "type": "fail", "nextStepId": "<GUID-14>" }
296
+ {
297
+ "id": "<GUID-R4>",
298
+ "name": "success",
299
+ "type": "success",
300
+ "nextStepId": "<GUID-R5>"
301
+ },
302
+ {
303
+ "id": "<GUID-R4b>",
304
+ "name": "fail",
305
+ "type": "fail",
306
+ "nextStepId": "<GUID-14>"
307
+ }
158
308
  ]
159
309
  },
160
310
  {
161
- "id": "<GUID-R5>", "name": "setUser", "type": "set-user",
311
+ "id": "<GUID-R5>",
312
+ "name": "setUser",
313
+ "description": "Bulunan kullanıcıyı 'user' değişkenine yazar; sonraki uçlar bunu okur.",
314
+ "type": "set-user",
162
315
  "rule": {
163
316
  "stepType": "set-user",
164
317
  "expression": "(function () {\n var link = rolesTable.data || [];\n var all = allRoles.data || [];\n var slugs = link.map(function (ur) {\n var rid = ur.role_id && ur.role_id.id ? ur.role_id.id : ur.role_id;\n var match = all.filter(function (r) { return r.id === rid; })[0];\n return match && match.slug;\n }).filter(function (s) { return !!s; });\n return Object.assign({}, userTable.data, { roles: slugs, roles_csv: ',' + slugs.join(',') + ',' });\n})()",
165
318
  "dataTransferObjectId": "<user DTO id — opsiyonel>"
166
319
  },
167
- "branches": [{ "id": "<GUID-R6>", "name": "success", "type": "success", "nextStepId": "<GUID-R7>" }]
320
+ "branches": [
321
+ {
322
+ "id": "<GUID-R6>",
323
+ "name": "success",
324
+ "type": "success",
325
+ "nextStepId": "<GUID-R7>"
326
+ }
327
+ ]
168
328
  },
169
329
  {
170
- "id": "<GUID-R7>", "name": "roleGate", "type": "condition",
171
- "rule": { "stepType": "condition", "items": [{ "expression": "Authorized(user.roles)", "branchId": "<GUID-R8>" }] },
330
+ "id": "<GUID-R7>",
331
+ "name": "roleGate",
332
+ "type": "condition",
333
+ "rule": {
334
+ "stepType": "condition",
335
+ "items": [
336
+ {
337
+ "expression": "Authorized(user.roles)",
338
+ "branchId": "<GUID-R8>"
339
+ }
340
+ ]
341
+ },
172
342
  "branches": [
173
- { "id": "<GUID-R8>", "name": "<GUID-R8>", "type": "success", "nextStepId": null },
174
- { "id": "<GUID-R9>", "name": "else", "type": "fail", "nextStepId": "<GUID-F>" }
343
+ {
344
+ "id": "<GUID-R8>",
345
+ "name": "<GUID-R8>",
346
+ "type": "success",
347
+ "nextStepId": null
348
+ },
349
+ {
350
+ "id": "<GUID-R9>",
351
+ "name": "else",
352
+ "type": "fail",
353
+ "nextStepId": "<GUID-F>"
354
+ }
175
355
  ]
176
356
  },
177
357
  {
178
- "id": "<GUID-F>", "name": "forbiddenResponse", "type": "response",
358
+ "id": "<GUID-F>",
359
+ "name": "forbiddenResponse",
360
+ "type": "response",
179
361
  "rule": {
180
362
  "stepType": "response",
181
363
  "bodyExpression": "{ success: false, message: 'Bu işlem için yetkiniz yok.' }",
182
- "httpStatusCode": 403, "headerExpression": "{ }"
364
+ "httpStatusCode": 403,
365
+ "headerExpression": "{ }"
183
366
  },
184
367
  "branches": []
185
368
  }
186
369
  ],
187
- "acceptance": "Dört testle kabul edilir: (1) rolü olan kullanıcı korumalı ucu çağırır → 200; (2) rolü olmayan kullanıcı → 403; (3) kimliksiz çağrı (microservice_execute anonymous:true) → 401; (4) roleIds boş bir uç aynı middleware'e bağlıyken kimliği doğrulanmış herkese açık kalır (Authorized boş rol listesinde true döner)."
370
+ "acceptance": "Dört testle kabul edilir: (1) rolü olan kullanıcı korumalı ucu çağırır → 200; (2) rolü olmayan kullanıcı → 403; (3) kimliksiz çağrı (microservice_execute anonymous:true) → 401; (4) roleIds boş bir uç aynı middleware'e bağlıyken kimliği doğrulanmış herkese açık kalır (Authorized boş rol listesinde true döner).",
371
+ "description": "Middleware çeşidi."
188
372
  },
189
373
  "consumptionExample": {
190
374
  "note": "Kimlik kapsaması: uca middleware'i bağla (definition.middlewareIds) + owner filtresi expression yap. qm kanıtı: sy-users-get-my-profile.",
191
- "middlewareIds": ["<authenticate workflow id>"],
192
- "filter": { "fieldId": "<owner alanı id>", "operator": "eq", "source": "expression", "value": "user.id", "filterType": "single", "conditionType": "and", "isRequired": false, "children": [], "order": 0 }
375
+ "middlewareIds": [
376
+ "<authenticate workflow id>"
377
+ ],
378
+ "filter": {
379
+ "fieldId": "<owner alanı id>",
380
+ "operator": "eq",
381
+ "source": "expression",
382
+ "value": "user.id",
383
+ "filterType": "single",
384
+ "conditionType": "and",
385
+ "isRequired": false,
386
+ "children": [],
387
+ "order": 0
388
+ }
193
389
  }
194
390
  }
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "_meta": {
3
3
  "synthetic": true,
4
- "note": "hr projesinde doğrulanmış şekil. Kurallar: step/branch id'leri GERÇEK GUID ve global benzersiz (RowAlreadyExists); DtoId verilen yerde Behavior zorunlu; table rule'da datasourceId + fieldId zorunlu; filtre value JavaScript ifadesi; preview girdisi previewPayload anahtarıyla."
4
+ "note": "hr projesinde doğrulanmış şekil. Kurallar: step/branch id'leri GERÇEK GUID ve global benzersiz (RowAlreadyExists); DtoId verilen yerde Behavior zorunlu; table rule'da datasourceId + fieldId zorunlu; filtre value JavaScript ifadesi; preview girdisi previewPayload anahtarıyla. bağlanmamış fail dalı hataya düşerse start'taki global-error dalına gider (IStep.cs:74-86)."
5
5
  },
6
6
  "definition": {
7
7
  "name": "Product Lookup",
8
8
  "slug": "product-lookup",
9
+ "description": "Ada göre tek ürün getirir; bulunamazsa hata yoluna düşer.",
9
10
  "type": "workflow",
10
11
  "parameterDtoId": "<girdi DTO id: { productName: string }>",
11
12
  "returnDtoId": "<çıktı DTO id: { name, price }>",
@@ -22,12 +23,20 @@
22
23
  "name": "start",
23
24
  "type": "success",
24
25
  "nextStepId": "<GUID-3>"
26
+ },
27
+ {
28
+ "id": "<GUID-7>",
29
+ "name": "global-error",
30
+ "type": "global-error",
31
+ "nextStepId": "<GUID-8>"
25
32
  }
26
33
  ]
27
34
  },
28
35
  {
29
36
  "id": "<GUID-3>",
30
37
  "name": "Load Product",
38
+ "description": "input.productName ile ürünü okur; tek kayıt bekler.",
39
+ "caution": "Ad benzersiz değil: aynı adda birden çok ürün varsa ilkini alır, hiç yoksa sessizce boş döner.",
31
40
  "type": "table",
32
41
  "rule": {
33
42
  "stepType": "table",
@@ -77,6 +86,7 @@
77
86
  {
78
87
  "id": "<GUID-6>",
79
88
  "name": "Response",
89
+ "description": "Bulunan ürünün adını 200 ile döner.",
80
90
  "type": "response",
81
91
  "rule": {
82
92
  "stepType": "response",
@@ -85,10 +95,22 @@
85
95
  "headerExpression": "{ }"
86
96
  },
87
97
  "branches": []
98
+ },
99
+ {
100
+ "id": "<GUID-8>",
101
+ "name": "onError",
102
+ "description": "Akış patlarsa hata kodunu ve mesajını 500 ile döner.",
103
+ "type": "response",
104
+ "rule": {
105
+ "stepType": "response",
106
+ "bodyExpression": "({ code: error.code, message: error.message })",
107
+ "httpStatusCode": 500
108
+ },
109
+ "branches": []
88
110
  }
89
111
  ]
90
112
  },
91
113
  "automationVariant": {
92
114
  "note": "Automation: returnDtoId/parameterDtoId YASAK (validator reddeder), returnBehavior 'object' verilebilir; state=unready NORMALDİR ve tetiklemeyi etkilemez. Tetikleme kapısı automation nesnesindeki entityId + operation + isQueue (false=anlık, true=kuyruk; null=asla tetiklenmez!). steps hem üst seviyede hem automation içinde (PLT-007); response yasak, hata yolu revert."
93
115
  }
94
- }
116
+ }
@@ -38,8 +38,11 @@ component_get → tek tipin TAM sözleşmesi, üç katman birleşik:
38
38
  - Yük `events[].payload`'dadır ama akışa **`event.data` ile GELMEZ**: motor yükü komponentin
39
39
  KENDİ prop'una yazar (`FlowMachine.onEmit` → `setNode`) ve akışı emit'in `params`'ıyla başlatır.
40
40
  Yani `payload` anahtarları prop adlarıdır ve `self.<anahtar>` ile okunur (ya da
41
- `value.type:'property'`); `reads` alanı yükte olmayan prop'ları söyler. `event.data` yalnız
42
- `html` komponentinin `fireEvent` aksiyonlarında dolar.
41
+ `value.type:'property'`); `reads` alanı yükte olmayan prop'ları söyler. `event.data`
42
+ `html`'in `fireEvent` aksiyonlarında ve `params` da gönderen 2026-08-27 kuşağında
43
+ (`eventcalendar` · `importwizard` · `kanban` · `signature` · `stepper`) dolar — `kanban` ve
44
+ `eventcalendar` yükü `self`'e HİÇ yazmaz, yalnız `event.data` ile okunur (ayrım
45
+ `component_get` sözleşme notlarında).
43
46
  - Akış bağlama: `flow_create` → `page_schema_patch set_event`. İstisna: `html` komponentinin
44
47
  aksiyonları kendi `flow` prop'uyla bağlanır (`platform_guide('html')`).
45
48
 
@@ -88,7 +91,7 @@ Her şema düğümünde iki sözlük vardır; ikisi de ortak render katmanında
88
91
 
89
92
  | `appearance` | Değerler | Anlamı |
90
93
  |---|---|---|
91
- | `heightType` | `auto` · `fixed` | `auto`: içerik kadar (önerilen — Kural 1d); `fixed`: `blocks.h × 10px` |
94
+ | `heightType` | `auto` · `fixed` · `fill` | `auto`: içerik kadar (önerilen — Kural 1d); `fixed`: `blocks.h × 10px`; `fill`: **kalanı doldur** — ebeveynin bıraktığı yer (ızgarada `height:100%`, flex sütununda `flex:1 1 auto`, flex satırında `align-self:stretch`). Tam ekran yerleşim kabuğu bununla kurulur, bkz. `platform_guide('layout')` |
92
95
  | `marginType` / `marginValue` | `normal` · `none` · `custom` + px | Dış boşluk: normal=5px, custom=`marginValue` |
93
96
  | `paddingType` / `paddingValue` | `normal` · `none` · `custom` + px | Droppable kapların iç boşluğu: normal=10px |
94
97
  | `alignType` | `left` · `center` · `right` | İçerik hizalama (destekleyen komponentlerde) |
@@ -0,0 +1,129 @@
1
+ # Kendi komponentinizi yazmak
2
+
3
+ Hazır katalog (`component_list`) ihtiyacınızı karşılamıyorsa üç seçeneğiniz var,
4
+ bu sırayla deneyin:
5
+
6
+ 1. **Hazır komponenti zorlayın.** `component_get` ile prop'lara bakın; çoğu
7
+ "yok" sanılan davranış bir prop ya da event kombinasyonuyla çıkar.
8
+ 2. **`html` kaçış kapısı.** Tek seferlik bir görsel için yeterli — bkz.
9
+ `platform_guide('html')`. Kalıcı, tekrar kullanılacak bir şey değilse burada
10
+ durun.
11
+ 3. **Kendi komponentinizi yayınlayın.** Aynı ihtiyaç birden fazla sayfada
12
+ tekrarlanıyorsa, prop/event sözleşmesi gerekiyorsa ya da `html` içinde
13
+ yönetilemeyecek kadar davranış varsa doğru yol budur. Bu rehberin konusu.
14
+
15
+ Yayınlanan komponent platformun kendi komponentlerinden ayırt edilmez:
16
+ sayfaya sürüklenir, prop'ları property panelinde düzenlenir, event'leri flow'a
17
+ bağlanır, tema değişkenlerini alır. Studio toolbox'ında **"Your Components"**
18
+ başlığı altında listelenir.
19
+
20
+ ## Akış
21
+
22
+ ```
23
+ external_component_scaffold → yerel iskelet (element.mjs + manifest.json)
24
+ ↓ (element.mjs'i yazın, manifest'i gerçek prop/event'lerinize göre düzenleyin)
25
+ external_component_publish → kayıt + paket yüklenir, doğrulama raporu döner
26
+ ↓ (rapor block içeriyorsa düzeltip tekrar publish — depolamaya yazılmadı)
27
+ ↓ taslak: Studio önizlemesinde görünür, yayınlanmış uygulamada görünmez
28
+ external_component_activate → yayına alır (yalnız metadata; kesinti yok)
29
+ ↓
30
+ page_schema_patch → add_component ile sayfaya koyun
31
+ ```
32
+
33
+ Aktivasyondan sonra komponent `component_list` / `component_get` çıktısında
34
+ normal katalog kaydı gibi döner; `add_component` micro-op'unda `type` olarak
35
+ slug'ı kullanın.
36
+
37
+ ## Sözleşme
38
+
39
+ Host element'e şema prop'larını **JS property** olarak yazar — attribute değil,
40
+ böylece dizi ve nesneler bozulmadan geçer. Yanına iki kanal koyar:
41
+
42
+ | Property | İçerik |
43
+ |---|---|
44
+ | şemadaki her prop | çözülmüş değer; yalnız değişen key'ler yeniden yazılır |
45
+ | `zxContext` | `{ elementId, appearance, states, isRequired, editorMode, language }` |
46
+ | `zxMachine` | platform yüzeyi (aşağıda) |
47
+
48
+ Element geriye **tek bir DOM olayıyla** konuşur: `zx-emit`, detail'i
49
+ `{ name, data?, setter?, flowId?, params? }`.
50
+
51
+ - `name` manifest'te bildirdiğiniz event adı olmalı; bildirilmemiş bir ad
52
+ flow'a bağlanamaz.
53
+ - `setter: true` verirseniz `data` içindeki değer aynı adlı prop'a geri yazılır —
54
+ `value` gibi iki yönlü davranan proplar için budur.
55
+
56
+ `zxMachine` sayılı bir yüzeydir; burada olmayan hiçbir şeye erişemezsiniz:
57
+ `getProps`, `getComponents`, `getComponentProps`, `getState`/`setState`,
58
+ `getVariable`/`setVariable`, `getStorage`/`setStorage`,
59
+ `getLanguage`/`setLanguage`, `t`, `checkAuthorization`, `user`, `pageParams`,
60
+ `emit`, `on`.
61
+
62
+ ## Yasaklar — yayınlamayı reddeder
63
+
64
+ Paket sunucuda AST taramasından geçer. Şunlardan biri varsa paket **depolamaya
65
+ hiç yazılmaz**:
66
+
67
+ `eval`, `new Function` / `Function(...)`, dinamik `import()`,
68
+ `document.cookie`, `window.machine`, `navigator.serviceWorker.register`,
69
+ `document.write`, `localStorage.clear()` / `sessionStorage.clear()`.
70
+
71
+ Tarama AST üzerinde çalışır: bir string sabitinin içindeki `eval` kelimesi bulgu
72
+ değildir, `eval(...)` çağrısı bulgudur.
73
+
74
+ ## Uyarılar — rapora yazılır, aktivasyonda onay ister
75
+
76
+ Dış ağ erişimi (`fetch`, `XMLHttpRequest`, `WebSocket`, `EventSource`),
77
+ doğrudan `localStorage`/`sessionStorage` erişimi, `window.X = ...` ataması,
78
+ `innerHTML`/`outerHTML` ataması, ve manifest'te bildirip element'te
79
+ karşılığını yazmadığınız proplar.
80
+
81
+ Uyarısı olan bir sürüm `acknowledgeWarnings: true` olmadan aktive edilemez.
82
+ Uyarıyı gördüğünüzde önce gerçekten gerekli mi diye bakın: veriyi flow ile
83
+ almak `fetch`'ten, `zxMachine.setStorage` doğrudan storage'dan iyidir.
84
+
85
+ ## Kurallar
86
+
87
+ - Slug `x-` ile başlamak zorunda (`^x-[a-z][a-z0-9-]*$`). Bu önek platform
88
+ slug'larıyla çakışmayı imkânsız kılar.
89
+ - Tek `export default`, `HTMLElement` türeten bir sınıf.
90
+ - Prop adları DOM'u bozacak adlar olamaz: `id`, `class`, `className`, `style`,
91
+ `slot`, `name`, `children`, `innerHTML`, `outerHTML`, `textContent`, `zx*`,
92
+ `on*`.
93
+ - `manifest.definition.blocks` boş olamaz — ızgara ayak izi olmayan komponent
94
+ ölçeklenemez.
95
+ - Prop tipleri platformun tanıdığı kümeden olmalı (`text`, `long-text`,
96
+ `number`, `switch`, `dropdown`, `array`, `object`, `flow`, `icon`, `color`,
97
+ `date`, …). Yeni bir prop tipi uyduramazsınız.
98
+ - Paket 2 MB'ı geçemez.
99
+ - Renk, boşluk, tipografi için `--ng-*` tema değişkenlerini kullanın; sabit renk
100
+ yazarsanız komponent kullanıcının temasına uymaz.
101
+
102
+ ## Sürümler ve geri alma
103
+
104
+ Paketler değişmezdir: aynı `(slug, version)` ikinci kez yayınlanamaz, düzeltme
105
+ yeni bir sürüm demektir. `external_component_versions` geçmişi ve her sürümün
106
+ doğrulama raporunu verir; `external_component_activate` ile eski bir sürümü
107
+ aktive etmek geri alma olarak çalışır. Aktivasyon yalnız metadata değiştirir —
108
+ platform yeniden başlamaz, açık oturumlar bozulmaz.
109
+
110
+ ## Editor modu
111
+
112
+ `zxContext.editorMode` true olduğunda element Studio kanvasında statik bir
113
+ önizleme olarak duruyor: zamanlayıcı kurmayın, ağ çağrısı yapmayın, tıklamayı
114
+ işlemeyin. Kanvasta etkileşim host tarafından zaten engellenir, ama gereksiz iş
115
+ yapmamak kanvası hızlı tutar.
116
+
117
+ ## Geliştirici kiti
118
+
119
+ Platform, npm paketi olmadan servis eder:
120
+
121
+ - `{studio}/component-kit/zeyrek-component.d.ts` — protokolün tip bildirimleri
122
+ - `{studio}/component-kit/harness.html` — platformsuz deneme sayfası
123
+ - `{studio}/component-kit/example-rating-stars.mjs` — çalışan örnek
124
+ - `GET {tenant}/{project}/components/external/manifest-schema` — manifest için
125
+ JSON Schema; izin verilen prop tipleri ve rezerve adlar sunucudaki kural
126
+ setinden **üretilir**, statik bir kopya olmadığı için sapmaz.
127
+
128
+ `external_component_scaffold` bu sözleşmeye uyan bir iskeleti yerel dizine
129
+ zaten yazar; kit, iskeleti elle düzenlerken referans olarak işinize yarar.