@appaflytech/zeyrek-ai-mcp 0.0.33 → 0.0.34

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 (169) hide show
  1. package/.env.example +0 -15
  2. package/dist/config.js +0 -11
  3. package/dist/index.js +0 -2
  4. package/dist/knowledge/boxSections.js +184 -0
  5. package/dist/knowledge/componentCatalog.js +248 -108
  6. package/dist/knowledge/componentEvents.js +22 -24
  7. package/dist/knowledge/layoutSummary.js +2 -140
  8. package/dist/knowledge/normalize.js +126 -117
  9. package/dist/knowledge/rules.js +19 -291
  10. package/dist/knowledge/styleResolve.js +38 -55
  11. package/dist/knowledge/themeResolve.js +3 -3
  12. package/dist/observability/trace.js +1 -1
  13. package/dist/platform/diagnostics.js +4 -10
  14. package/dist/platform/domSummary.js +1 -1
  15. package/dist/platform/http.js +7 -23
  16. package/dist/platform/responses.js +2 -6
  17. package/dist/platform/screenshot.js +1162 -0
  18. package/dist/platform/secrets.js +0 -9
  19. package/dist/platform/strictArguments.js +12 -68
  20. package/dist/platform/tokenVault.js +4 -187
  21. package/dist/resources/examples/layout-app-shell.json +707 -229
  22. package/dist/resources/examples/page-flex-sections.json +1 -1
  23. package/dist/resources/guides/component.md +5 -13
  24. package/dist/resources/guides/entity.md +5 -3
  25. package/dist/resources/guides/expressions.md +5 -14
  26. package/dist/resources/guides/functions.md +1 -1
  27. package/dist/resources/guides/layout.md +58 -55
  28. package/dist/resources/guides/microservice.md +2 -9
  29. package/dist/resources/guides/middleware.md +2 -34
  30. package/dist/resources/guides/page.md +171 -256
  31. package/dist/resources/guides/theme.md +2 -8
  32. package/dist/resources/guides/translation.md +1 -1
  33. package/dist/resources/guides/workflow.md +1 -7
  34. package/dist/resources/schema-fingerprint.json +4 -4
  35. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -3
  36. package/dist/resources/schemas/MicroserviceDto.json +2 -2
  37. package/dist/server.js +1 -7
  38. package/dist/tools/applications.js +3 -60
  39. package/dist/tools/components.js +16 -103
  40. package/dist/tools/datasources.js +1 -1
  41. package/dist/tools/designSchemaPatch.js +19 -23
  42. package/dist/tools/externalComponents.js +4 -25
  43. package/dist/tools/flows.js +6 -79
  44. package/dist/tools/layouts.js +20 -48
  45. package/dist/tools/microservices.js +10 -32
  46. package/dist/tools/pages.js +115 -396
  47. package/dist/tools/platformInfo.js +2 -7
  48. package/dist/tools/rows.js +1 -7
  49. package/dist/tools/schemaOps.js +4 -35
  50. package/dist/tools/screenWrite.js +37 -25
  51. package/dist/tools/screens.js +4 -91
  52. package/dist/tools/variables.js +5 -11
  53. package/package.json +2 -2
  54. package/dist/knowledge/access.js +0 -802
  55. package/dist/knowledge/case.js +0 -41
  56. package/dist/knowledge/connectDataBind.js +0 -819
  57. package/dist/knowledge/connectDataDefinition.js +0 -341
  58. package/dist/knowledge/connectDataExecute.js +0 -93
  59. package/dist/knowledge/connectDataRules.js +0 -128
  60. package/dist/knowledge/decision.js +0 -121
  61. package/dist/knowledge/expressionPrelude.js +0 -59
  62. package/dist/knowledge/microserviceParameters.js +0 -58
  63. package/dist/knowledge/mining.js +0 -94
  64. package/dist/knowledge/mobileComponentCatalog.js +0 -864
  65. package/dist/knowledge/mobileComponentEvents.js +0 -239
  66. package/dist/knowledge/mobileStore.js +0 -227
  67. package/dist/knowledge/platform/lint.js +0 -385
  68. package/dist/knowledge/platform/mobile.js +0 -142
  69. package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
  70. package/dist/knowledge/platform/mobileRules.js +0 -231
  71. package/dist/knowledge/platform/mobileSpacing.js +0 -82
  72. package/dist/knowledge/platform/mobileTabs.js +0 -108
  73. package/dist/knowledge/platform/nativeBoxModel.js +0 -44
  74. package/dist/knowledge/platform/profile.js +0 -25
  75. package/dist/knowledge/platform/resolve.js +0 -122
  76. package/dist/knowledge/platform/web.js +0 -39
  77. package/dist/knowledge/process.js +0 -510
  78. package/dist/knowledge/rowFilter.js +0 -43
  79. package/dist/knowledge/styleResolveNative.js +0 -527
  80. package/dist/platform/argumentAliases.js +0 -128
  81. package/dist/platform/bodyFile.js +0 -103
  82. package/dist/platform/capture/actions.js +0 -333
  83. package/dist/platform/capture/browser.js +0 -1
  84. package/dist/platform/capture/capture.js +0 -659
  85. package/dist/platform/capture/console-log.js +0 -122
  86. package/dist/platform/capture/index.js +0 -11
  87. package/dist/platform/capture/readiness.js +0 -103
  88. package/dist/platform/capture/summary.js +0 -77
  89. package/dist/platform/capture/target.js +0 -5
  90. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  91. package/dist/platform/capture/targets/studio-web.js +0 -5
  92. package/dist/platform/impersonation.js +0 -45
  93. package/dist/platform/jsonArray.js +0 -24
  94. package/dist/platform/schemaReadMemory.js +0 -60
  95. package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
  96. package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
  97. package/dist/resources/examples/bpm-satinalma.json +0 -376
  98. package/dist/resources/examples/connect-data-convert-verify.json +0 -107
  99. package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
  100. package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
  101. package/dist/resources/examples/connect-data-query-params.json +0 -50
  102. package/dist/resources/examples/connect-data-table-entity.json +0 -147
  103. package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
  104. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -244
  105. package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
  106. package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
  107. package/dist/resources/examples/mobile-form-screen.json +0 -365
  108. package/dist/resources/examples/mobile-list-detail-form.json +0 -703
  109. package/dist/resources/guides/access.md +0 -796
  110. package/dist/resources/guides/bpm.md +0 -686
  111. package/dist/resources/guides/case.md +0 -153
  112. package/dist/resources/guides/decision.md +0 -185
  113. package/dist/resources/guides/mobile-layout.md +0 -193
  114. package/dist/resources/guides/mobile.md +0 -578
  115. package/dist/resources/read.js +0 -41
  116. package/dist/resources/schemas/AccessExplanationDto.json +0 -144
  117. package/dist/resources/schemas/AccessMatrixDto.json +0 -170
  118. package/dist/resources/schemas/AccessPermissionDto.json +0 -57
  119. package/dist/resources/schemas/AccessPolicyDto.json +0 -223
  120. package/dist/resources/schemas/AccessResourceDto.json +0 -86
  121. package/dist/resources/schemas/AppSessionDto.json +0 -53
  122. package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
  123. package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
  124. package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
  125. package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
  126. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
  127. package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
  128. package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
  129. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
  130. package/dist/resources/schemas/DecisionDto.json +0 -302
  131. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
  132. package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
  133. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
  134. package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
  135. package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
  136. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
  137. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
  138. package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
  139. package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
  140. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
  141. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
  142. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
  143. package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
  144. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
  145. package/dist/resources/schemas/StartMobileBuildCommand.json +0 -54
  146. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
  147. package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
  148. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
  149. package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +0 -259
  150. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
  151. package/dist/tools/accessOperations.js +0 -135
  152. package/dist/tools/accessPolicies.js +0 -170
  153. package/dist/tools/accessRuntime.js +0 -203
  154. package/dist/tools/bpm.js +0 -343
  155. package/dist/tools/bpmGovernance.js +0 -266
  156. package/dist/tools/bpmOperations.js +0 -230
  157. package/dist/tools/bpmReporting.js +0 -154
  158. package/dist/tools/bpmRouting.js +0 -150
  159. package/dist/tools/bpmRuntime.js +0 -396
  160. package/dist/tools/case.js +0 -178
  161. package/dist/tools/caseRuntime.js +0 -89
  162. package/dist/tools/connectData.js +0 -449
  163. package/dist/tools/connectors.js +0 -193
  164. package/dist/tools/decisions.js +0 -206
  165. package/dist/tools/mobile.js +0 -221
  166. package/dist/tools/mobileStore.js +0 -268
  167. package/dist/tools/modules.js +0 -48
  168. package/dist/tools/organizationStructure.js +0 -137
  169. package/dist/tools/profileWrite.js +0 -92
@@ -1,8 +1,7 @@
1
1
  import { logStep } from '../observability/trace.js';
2
2
  import { PlatformApiError } from '../platform/errors.js';
3
3
  import { ensureWorkflowErrorPath } from './errorPath.js';
4
- import { DOCUMENT_STYLE_TYPES, TYPED_STYLE_COMPONENTS } from './styleResolve.js';
5
- import { STATE_STORAGE_KINDS, STEP_ALIASES } from './platform/profile.js';
4
+ import { TYPED_STYLE_COMPONENTS } from './styleResolve.js';
6
5
  const SORT_DEFAULT = { name: 'sortField', type: 'sortType', source: 'query-string' };
7
6
  const LIMIT_DEFAULT = { name: 'limit', offset: 'offset', source: 'query-string' };
8
7
  function asArray(value) {
@@ -270,11 +269,12 @@ export function normalizeWorkflowDefinition(definition) {
270
269
  */
271
270
  /**
272
271
  * Adım tipi sözlüğü backend'in, KOŞAN tipler barındırıcının: motor yedi tip register eder, web
273
- * `Runtime.svelte` altı, mobil `runtime-tasks.ts` yedi tip ekler ve aynı sayfa kaydı ikisinde de
272
+ * `Runtime.svelte` altı, mobil `ScreenRuntime.tsx` beş tip ekler ve aynı sayfa kaydı ikisinde de
274
273
  * koşar. Register edilmemiş bir tipe gelen akış sessizce ölür (`flow-engine.ts` `process()`
275
274
  * callback bulamazsa next/completed/stopped hiç çağrılmaz), üstelik `run()` promise'i
276
275
  * çözülmediği için `__ngAppsFlowActivity.running` sıfıra inmez. İki hâl tamamen türetilebilir
277
- * olduğu için lint değil NORMALİZASYON; `FLOW-023` kalan hâlleri uyarır.
276
+ * olduğu için lint değil NORMALİZASYON — kalanı (`confirm`/`download` mobilde yok) yalnız
277
+ * uygulama tarafında kapanabilir, `FLOW-023` onları uyarır.
278
278
  */
279
279
  function normalizeFlowHostGaps(steps, list) {
280
280
  const fixes = [];
@@ -288,15 +288,12 @@ function normalizeFlowHostGaps(steps, list) {
288
288
  .map(step => String(step.stepId ?? ''))
289
289
  .filter(id => id.length > 0));
290
290
  for (const step of list) {
291
- // navigate ile redirect'in argümanı AYNI ({ path, pageId, query, targetBlank, presentation })
292
- // ama navigate'i yalnız mobil register eder; redirect ise iki barındırıcıda da koşar (mobilde
293
- // aynı navigate uygulamasına eşlenir), yani redirect kesin üstün. `presentation`
294
- // (push | modal | replace) yalnız mobil barındırıcıda okunur; web yok sayar.
295
- const alias = STEP_ALIASES[String(step.type ?? '')];
296
- if (alias) {
297
- const original = String(step.type);
298
- step.type = alias;
299
- fixes.push(`'${label(step)}': type ${original} → ${alias} yazıldı — argüman şekli aynı ({ path, pageId, query, targetBlank, presentation }) ama ${original}'i web barındırıcısı register etmez, ${alias} ikisinde de koşar`);
291
+ // navigate ile redirect'in argümanı AYNI ({ path, pageId, query, targetBlank }) ama navigate'i
292
+ // yalnız mobil register eder; redirect ise iki barındırıcıda da koşar (mobilde aynı navigate
293
+ // uygulamasına eşlenir), yani redirect kesin üstün.
294
+ if (step.type === 'navigate') {
295
+ step.type = 'redirect';
296
+ fixes.push(`'${label(step)}': type navigate → redirect yazıldı — argüman şekli aynı ({ path, pageId, query, targetBlank }) ama navigate'i web barındırıcısı register etmez, redirect ikisinde de koşar`);
300
297
  }
301
298
  if (endStepIds.size === 0)
302
299
  continue;
@@ -459,7 +456,13 @@ const VALIDATION_TYPE_ALIASES = new Map([
459
456
  ...VALIDATION_CANONICAL_TYPES.map(type => [type.replace(/-/g, ''), type]),
460
457
  ['pattern', 'regex'],
461
458
  ['min', 'min-value'],
462
- ['max', 'max-value']
459
+ ['max', 'max-value'],
460
+ // OR-2 (2026-10-03): kayıt defteri checkboxgroup/multi-select/tag-input kuralını minItems/maxItems
461
+ // adıyla ilan eder (component_get.validations); backend ValidationType'ta bu ad yok, runtime da tanımaz.
462
+ // Studio paneli bu üçüne 'custom' şablonundan min-length/max-length yazar (ng-apps-types
463
+ // validation/constants.ts) ve Form uzunluk kuralı dizide SEÇİLİ ELEMAN sayısını ölçer.
464
+ ['minitems', 'min-length'],
465
+ ['maxitems', 'max-length']
463
466
  ]);
464
467
  const VALIDATION_VALUE_REQUIRED = new Set(['regex', 'max-length', 'min-length', 'max-value', 'min-value', 'value-options']);
465
468
  function canonicalValidationType(value) {
@@ -654,42 +657,32 @@ export function styleKeyNote(fixed) {
654
657
  + "Seçici anahtarlara ('&__body', ':hover', '--token') dokunulmadı."];
655
658
  }
656
659
  /**
657
- * Kabın `states.isDroppable`ı KATALOĞUN kararıdır. Gateway düğümü kurarken bu alanı
658
- * yazmıyordu (`DEFAULT_STATES` hepsini `false` bırakır) ve Studio kanvası düğümü kap saymıyordu:
659
- * imleç `scroll-view`un İÇİNDEYKEN bırakma planı sayfa kabına düşüyor, çizgi kabın üst kenarına
660
- * çiziliyordu (ölçüldü 2026-09-21, `test/mobile app` › `Satislar`). Aynı tipi paletten ekleyen
661
- * Studio katalog değerini yazdığı için tek şemada iki türlü davranan kap oluyordu.
662
- *
663
- * Değer uygulamanın KENDİ sözlüğünden gelir (`listComponents`; mobil uygulamada `type=mobile`
664
- * satırları), yani kural platformdan bağımsızdır ve kuruluşun kendi komponentlerini de kapsar.
665
- * Yalnız `true` yazılır: katalog bir tipi kap saymıyorsa düğüme dokunulmaz.
660
+ * Y-15 — adı eksik, null ya da boş/boşluk olan düğüm runtime'ın ifade ön sözünü bozar: `getNodeNames`
661
+ * null adı `"null"` anahtarına çevirir, `runCode` `const null = Components["null"]` satırını üretir
662
+ * (`ng-apps-flow/src/flow-execution.functions.ts`) ve sayfadaki BÜTÜN ifadeler SyntaxError'la düşer;
663
+ * hata yalnız akış adımının runtimeErrors'ında görünür (ölçüldü 2026-10-03, `y15-adsiz`). Backend adı
664
+ * hiç denetlemez (`PageSchemaValidator.cs`); Studio her düğüme `name = elementId` yazar
665
+ * (`ScreenBuilderDroppable.svelte`). Kural deterministik olduğu için reddetmek yerine dolduruyoruz.
666
+ * Doldurulan ad da PAGE-009'dan geçmek zorunda: çağıran bunu denetimden ÖNCE koşar. Dolu ada dokunulmaz.
666
667
  */
667
- export function normalizeDroppableStates(nodes, droppable) {
668
- const fixed = [];
669
- if (droppable.size === 0)
670
- return fixed;
668
+ export function fillComponentNames(nodes) {
669
+ const filled = [];
671
670
  for (const node of asObjects(nodes)) {
672
- const type = typeof node.type === 'string' ? node.type : '';
673
- if (droppable.get(type) === true) {
674
- // `states` normalde `normalizeComponentDefaults`tan geçmiş olur; gelmediyse burada da
675
- // eksiksiz kurulur — yarım `states` platformda NullReference üretir.
676
- if (!node.states || typeof node.states !== 'object' || Array.isArray(node.states)) {
677
- node.states = { ...DEFAULT_STATES };
678
- }
679
- const states = node.states;
680
- if (states.isDroppable !== true) {
681
- states.isDroppable = true;
682
- fixed.push(`'${String(node.elementId ?? node.name ?? type)}' (${type})`);
683
- }
671
+ const name = node.name;
672
+ const blank = name === undefined || name === null || (typeof name === 'string' && name.trim().length === 0);
673
+ if (blank && typeof node.elementId === 'string' && node.elementId.length > 0) {
674
+ node.name = node.elementId;
675
+ filled.push(node.elementId);
684
676
  }
685
- fixed.push(...normalizeDroppableStates(node.children, droppable));
677
+ filled.push(...fillComponentNames(node.children));
686
678
  }
687
- return fixed;
679
+ return filled;
688
680
  }
689
- export function droppableStatesNote(fixed) {
690
- return fixed.length === 0
691
- ? []
692
- : [`states.isDroppable katalogdan yazıldı (${fixed.join(' · ')}) — kataloğun kap saydığı düğüm Studio kanvasında da kap olmalı; alanı bilerek kapatmak için resize_component/set_states kullanın`];
681
+ export function componentNameNote(filled) {
682
+ if (filled.length === 0)
683
+ return [];
684
+ const access = filled.length === 1 ? filled[0] : "her düğümün kendi elementId'si";
685
+ return [`${filled.map(id => `'${id}'`).join(', ')}: name eksikti, elementId'den yazıldı — ifadelerde ${access} ile erişilir (adsız düğüm runtime'da sayfadaki bütün ifadeleri düşürür, Y-15)`];
693
686
  }
694
687
  export function normalizeComponentDefaults(nodes) {
695
688
  const fixed = [];
@@ -749,6 +742,65 @@ export function normalizeComponentDefaults(nodes) {
749
742
  }
750
743
  return fixed;
751
744
  }
745
+ export const COMPONENT_BODY_RULE = "Asgari gövde: { elementId, name (= elementId), type, props, blocks: [{ breakpoint: 1024, size: { w, h }, position: { x, y } }] }. "
746
+ + "Gateway blocks'u doldurmaz: blocks'u olmayan ya da null olan düğüm platformda kayıt sırasında 500 NullReferenceException verir. "
747
+ + "Boyutu component_get çıktısındaki sizes'tan al; flex kapta position yalnız sırayı belirtir (sırayı index ile de verebilirsin, blocks yine gövdede olur), "
748
+ + 'ızgara kapta x:0, y: kardeşlerin altı (en büyük y+h).';
749
+ /**
750
+ * Y-13 / PAGE-037 — `blocks` alanı hiç olmayan ya da `null` olan düğümleri (çocuklar dahil) toplar.
751
+ * `DesignComponentManagementSchema.Blocks`'un varsayılanı yoktur; `ToDomain` null listeyi
752
+ * `AddBlocks(null)` ile atlar, `_blocks` başlatılmaz ve `Blocks` getter'ı kayıtta patlar
753
+ * (`DesignComponent.cs:36-37,305`; yeni düğümde revizyon yakalama `ToObject:464`, var olan düğümde
754
+ * `DesignComponentRepository.UpsertRange` → `Override`). Ölçüldü 2026-10-04: son 7 günde eklenen
755
+ * düğümlerin ~%20'si blocks'suz geldi ve hepsi 500 aldı. Konum ebeveynin düzenine bağlı olduğu için
756
+ * doldurmuyoruz, reddediyoruz. `blocks: []` platformda kaydolur (ölçüldü 2026-10-04, `y13-blocks`) ve buraya girmez.
757
+ */
758
+ export function missingBlocksNodes(nodes) {
759
+ const missing = [];
760
+ for (const node of asObjects(nodes)) {
761
+ if (node.blocks === undefined || node.blocks === null) {
762
+ missing.push(`'${String(node.elementId ?? node.name ?? node.type ?? '?')}': blocks eksik — şunu ver: [{breakpoint:1024, size:{w,h}, position:{x,y}}]`);
763
+ }
764
+ missing.push(...missingBlocksNodes(node.children));
765
+ }
766
+ return missing;
767
+ }
768
+ /**
769
+ * PAGE-037 kimlik ayağı — platform elementId'siz add_component'i 'missing-id' ile reddeder
770
+ * (`PageSchemaMicroOpApplier.cs` add_component dalı) ama mesajı kimliğin hangi alan olduğunu
771
+ * söylemez. Ajanlar `name` verip elementId'yi atladı (Y-13 neden analizi N-B3, 5 düğüm).
772
+ */
773
+ export function addComponentIdErrors(ops) {
774
+ const errors = [];
775
+ for (const op of asObjects(ops)) {
776
+ if (op.op !== 'add_component')
777
+ continue;
778
+ const component = op.component && typeof op.component === 'object' ? op.component : {};
779
+ const elementId = component.elementId;
780
+ if (typeof elementId === 'string' && elementId.trim() !== '')
781
+ continue;
782
+ const name = typeof component.name === 'string' && component.name.trim() !== '' ? component.name : undefined;
783
+ errors.push(`add_component: component.elementId yok (platform 'missing-id' ile reddeder) — kimlik elementId'dir; name ifade adıdır, ikisini aynı yaz${name ? ` (elementId: '${name}', name: '${name}')` : ''}`);
784
+ }
785
+ return errors;
786
+ }
787
+ /**
788
+ * PAGE-037. Yalnız çağıranın verdiği ağaca bakar: page_create'in eklediği page_container
789
+ * blocks'la üretilir, okunan kayıttaki düğümler (layout_patch) platformdan blocks listesiyle gelir.
790
+ * Sayfa/layout yazma kapısı (`assertScreenWriteGuards`), `page_schema_validate` ve
791
+ * `component_update` çağırır; `page_schema_patch` aynı denetimi op başına toplar.
792
+ */
793
+ export function assertComponentBlocks(nodes) {
794
+ const missing = missingBlocksNodes(nodes);
795
+ if (missing.length === 0)
796
+ return;
797
+ throw new PlatformApiError(`PAGE-037 — komponent gövdesinde blocks yok (istek gönderilmedi): ${missing.join(' · ')}. ${COMPONENT_BODY_RULE}`, 400);
798
+ }
799
+ export function assertAddComponentIds(ops) {
800
+ const errors = addComponentIdErrors(ops);
801
+ if (errors.length > 0)
802
+ throw new PlatformApiError(`PAGE-037 — ${errors.join(' · ')} (istek gönderilmedi). ${COMPONENT_BODY_RULE}`, 400);
803
+ }
752
804
  /**
753
805
  * add_component micro-op'unun taşıdığı komponent ağacı da aynı ToDomain yolundan geçer.
754
806
  */
@@ -845,6 +897,7 @@ export function normalizeSchemaOps(ops) {
845
897
  const components = [];
846
898
  const props = [];
847
899
  const validations = [];
900
+ const names = [];
848
901
  for (const op of asObjects(ops)) {
849
902
  if (op.op === 'replace_prop') {
850
903
  if (isStylePropName(String(op.prop ?? ''))) {
@@ -866,9 +919,10 @@ export function normalizeSchemaOps(ops) {
866
919
  }
867
920
  if (op.op !== 'add_component' || !op.component)
868
921
  continue;
922
+ names.push(...fillComponentNames([op.component]));
869
923
  components.push(...normalizeComponentDefaults([op.component]));
870
924
  }
871
- return { components, props, validations };
925
+ return { components, props, validations, names };
872
926
  }
873
927
  export function validationNote(fixed) {
874
928
  return fixed.length === 0 ? [] : [`validation gövdeleri düzeltildi (${fixed.join(' · ')})`];
@@ -925,11 +979,11 @@ export function pageContainerNode() {
925
979
  * çekilirlerse sayfa içeriğinin akışına girer ve katman olarak açılmazlar.
926
980
  */
927
981
  const ROOT_LAYER_TYPES = new Set(['modal', 'drawer']);
928
- export function ensurePageContainer(schema, rootContainer = pageContainerNode) {
982
+ export function ensurePageContainer(schema) {
929
983
  const nodes = asObjects(schema);
930
984
  if (nodes.some(node => node.elementId === PAGE_CONTAINER_ELEMENT_ID))
931
985
  return { schema: nodes, fixes: [] };
932
- const container = rootContainer();
986
+ const container = pageContainerNode();
933
987
  const layers = nodes.filter(node => ROOT_LAYER_TYPES.has(String(node.type ?? '')));
934
988
  container.children = nodes.filter(node => !ROOT_LAYER_TYPES.has(String(node.type ?? '')));
935
989
  const moved = container.children.length;
@@ -972,7 +1026,7 @@ export function clampBlockSizes(nodes, maxSizes) {
972
1026
  * başlatır (`ComponentHeightType.Fixed = 0`), yani "alan yok" = "sabit yükseklik". Studio'nun
973
1027
  * kendi bırakma yolu bunu ASLA yapmaz: katalogdaki `isDefaultAutoHeight`e bakıp
974
1028
  * `heightType: isDefaultAutoHeight ? 'auto' : 'fixed'` yazar
975
- * (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts` `createDefaultSchemaNode`). Katalogda varsayılan
1029
+ * (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts:233`). Katalogda varsayılan
976
1030
  * `true`'dur (`ZeyrekComponent.ts:62`); `false` diyen yalnız sekiz tip var — auth-layout, html,
977
1031
  * image, layout, qrcode, table, text-editor, video.
978
1032
  *
@@ -1758,18 +1812,19 @@ export function viewAliasNote(fixes) {
1758
1812
  return [`view alanlarının entity bağı id'den alias'a çevrildi (${fixes.join(', ')}): yazma tarafı viewEntityAlias ister, okuma tarafı viewEntityId döndürür — alias boş kalsa platform tüm alanları ilk tabloya düşürürdü`];
1759
1813
  }
1760
1814
  /**
1761
- * `storage` kayıtta isteğe bağlıdır (`docs/adr/0004-state-saklama-turu.md`). Tanınmayan tür ya da
1762
- * metin olmayan değer çalışma zamanında da yok sayılır (`@ng-apps/ui-native` `variableStorageKinds`);
1763
- * gateway onu taşımaz ki bir sonraki yazım bozuk değeri kalıcılaştırmasın.
1815
+ * Değişken seti tek bir kayıtta yaşar: `CreateAppVariableCommand`/`CreatePageVariableCommand`
1816
+ * yalnız `Data` alanı taşır (Studio uygulama başına ve sayfa başına TEK satır tutar —
1817
+ * `IsVariableExistForApplicationAsync` doluysa create update'e döner). Studio'nun gönderdiği şekil
1818
+ * `data`'nın **JSON string** olmasıdır: "[{\"key\":\"MyTest\",\"value\":{\"isActive\":true}}]".
1819
+ * `Data` tipi `object` olduğu için platform her gövdeyi kabul eder; alan adı tutmayan bir gövde
1820
+ * (name/type/defaultValue gibi) `Data`'yı null bırakır ve istek 200 döner ama HİÇBİR ŞEY yazılmaz
1821
+ * (17/Ç1). Okuma tarafı da aynı string'i geri verir (`AppVariablesDto.Map` → GetRawText).
1764
1822
  */
1765
1823
  export function parseVariableEntries(data) {
1766
1824
  const source = typeof data === 'string' ? safeParse(data) : data;
1767
1825
  return asObjects(source)
1768
1826
  .filter(entry => typeof entry.key === 'string' && entry.key !== '')
1769
- .map(entry => {
1770
- const storage = STATE_STORAGE_KINDS.find(kind => kind === entry.storage);
1771
- return { key: String(entry.key), value: entry.value, ...(storage ? { storage } : {}) };
1772
- });
1827
+ .map(entry => ({ key: String(entry.key), value: entry.value }));
1773
1828
  }
1774
1829
  function safeParse(value) {
1775
1830
  try {
@@ -1784,29 +1839,17 @@ function safeParse(value) {
1784
1839
  * mevcut seti okuyup anahtar bazında birleştirir; `replace: true` verilirse bilinçli olarak ezer.
1785
1840
  */
1786
1841
  export function mergeVariableEntries(existing, incoming, replace) {
1787
- const stored = (entry, current) => {
1788
- const storage = entry.storage === undefined ? current?.storage : STATE_STORAGE_KINDS.find(kind => kind === entry.storage);
1789
- const value = entry.value === undefined ? (current ? current.value : null) : entry.value;
1790
- return { key: entry.key, value, ...(storage ? { storage } : {}) };
1791
- };
1792
1842
  if (replace)
1793
- return { entries: incoming.map(entry => stored(entry)), fixes: [] };
1843
+ return { entries: incoming, fixes: [] };
1794
1844
  const merged = [...existing];
1795
1845
  const kept = [];
1796
- const keptStorage = [];
1797
- const keptValue = [];
1798
1846
  for (const entry of incoming) {
1799
1847
  const index = merged.findIndex(current => current.key === entry.key);
1800
1848
  if (index === -1) {
1801
- merged.push(stored(entry));
1849
+ merged.push(entry);
1802
1850
  continue;
1803
1851
  }
1804
- const current = merged[index];
1805
- if (entry.storage === undefined && current?.storage)
1806
- keptStorage.push(`'${entry.key}' → ${current.storage}`);
1807
- if (entry.value === undefined)
1808
- keptValue.push(`'${entry.key}'`);
1809
- merged[index] = stored(entry, current);
1852
+ merged[index] = entry;
1810
1853
  }
1811
1854
  for (const entry of existing) {
1812
1855
  if (!incoming.some(current => current.key === entry.key))
@@ -1814,17 +1857,9 @@ export function mergeVariableEntries(existing, incoming, replace) {
1814
1857
  }
1815
1858
  return {
1816
1859
  entries: merged,
1817
- fixes: [
1818
- ...(kept.length > 0
1819
- ? [`mevcut değişkenler korundu (${kept.join(', ')}): uç seti komple değiştirir, gateway anahtar bazında birleştirdi — kasten silmek için replace: true verin`]
1820
- : []),
1821
- ...(keptStorage.length > 0
1822
- ? [`saklama türü korundu (${keptStorage.join(', ')}): gelen değişken storage taşımıyordu, kayıttaki tür silinmedi — belleğe çevirmek için storage: 'memory' verin`]
1823
- : []),
1824
- ...(keptValue.length > 0
1825
- ? [`değer korundu (${keptValue.join(', ')}): gelen değişken value taşımıyordu, kayıttaki değer silinmedi — boşaltmak için value: null verin`]
1826
- : [])
1827
- ]
1860
+ fixes: kept.length > 0
1861
+ ? [`mevcut değişkenler korundu (${kept.join(', ')}): uç seti komple değiştirir, gateway anahtar bazında birleştirdi — kasten silmek için replace: true verin`]
1862
+ : []
1828
1863
  };
1829
1864
  }
1830
1865
  export function blockSizeNote(clamped) {
@@ -1860,7 +1895,7 @@ export function rootAddsNote(retargeted, containerElementId) {
1860
1895
  export function componentDefaultsNote(fixed) {
1861
1896
  if (fixed.length === 0)
1862
1897
  return [];
1863
- return [`komponent gövdelerine eksik zorunlu alanlar eklendi (${fixed.join(' · ')}): bunlar olmadan platform NullReferenceException verir ve page_schema_validate bunu yakalamaz`];
1898
+ return [`komponent gövdelerine eksik varsayılan alanlar eklendi (${fixed.join(' · ')}): bunlar olmadan platform NullReferenceException verir ve page_schema_validate bunu yakalamaz. blocks eklenmez — gövdede olmalı (PAGE-037)`];
1864
1899
  }
1865
1900
  /**
1866
1901
  * Create yolu junction kaydını açar ama fiziksel tabloyu kurmaz (platform bug'ı P-01,
@@ -1905,22 +1940,12 @@ export function nestedRepeaterNodes(nodes) {
1905
1940
  walk(asObjects(nodes), false);
1906
1941
  return found;
1907
1942
  }
1908
- /**
1909
- * Mobil profilde gruplu listenin (gün/kategori başlığı altında satırlar) hazır bileşeni vardır:
1910
- * `grouped-list` (ui-native, ADR 0007). Web'de karşılığı yok — web mesajı textarea tarifinde kalır.
1911
- */
1912
- export function nestedRepeaterMessage(ids, platform = 'web') {
1913
- const measured = `PAGE-013 — repeater içinde repeater (istek gönderilmedi): ${ids.join(' · ')}. `
1943
+ export function nestedRepeaterMessage(ids) {
1944
+ return `PAGE-013 — repeater içinde repeater (istek gönderilmedi): ${ids.join(' · ')}. `
1914
1945
  + 'Ölçüldü (2026-08-19): iç repeater OKUMADA çalışır ama girilen değer dış satıra GERİ YAZILMAZ '
1915
1946
  + '(_repeaterValues null kalır) ve tek düzenlemeden sonra DOM bozulur. Sebep yapısal: şemada iç '
1916
- + 'repeater tek düğümdür, dış satır başına ayrı düğüm yoktur. ';
1917
- const textarea = "Satır içi listeyi tek bir textarea ile topla (satır başına bir öğe) ve kaydederken split('\n') ile böl — platform_guide('page') Kural 1g.";
1918
- if (platform !== 'mobile')
1919
- return measured + textarea;
1920
- return measured
1921
- + 'Başlıklar altında gruplanmış liste (güne/kategoriye göre) için mobilde tek `grouped-list` kur: düz `rows` + '
1922
- + '`groupBy` alan yolu; çocuk 0 bölüm başlığı (`{{ Section.title }}`), çocuk 1 öğe şablonu (`Row`, `{{ item.<alan> }}`) — '
1923
- + "platform_guide('mobile') §Güne göre görev listesi. Satır içinde düzenlenen alt liste gerekiyorsa: " + textarea;
1947
+ + 'repeater tek düğümdür, dış satır başına ayrı düğüm yoktur. Satır içi listeyi tek bir textarea '
1948
+ + "ile topla (satır başına bir öğe) ve kaydederken split('\n') ile böl — platform_guide('page') Kural 1g.";
1924
1949
  }
1925
1950
  /**
1926
1951
  * `style` prop'u düz CSS STRING verilmiş düğümler. Çalışır (emotion string'i CSS metni sayar) ama
@@ -1934,7 +1959,7 @@ export function stringStyleNodes(nodes) {
1934
1959
  for (const node of list) {
1935
1960
  const props = (node.props ?? {});
1936
1961
  const style = props.style;
1937
- if (style && typeof style.data === 'string' && style.data.includes(':') && !DOCUMENT_STYLE_TYPES.has(String(node.type))) {
1962
+ if (style && typeof style.data === 'string' && style.data.includes(':')) {
1938
1963
  found.push(String(node.elementId ?? node.name ?? '?'));
1939
1964
  }
1940
1965
  walk(asObjects(node.children));
@@ -2073,26 +2098,10 @@ export function flowBindings(schema, hostEvents) {
2073
2098
  */
2074
2099
  export function orphanedFlowPlan(schema, pageEvents, ops) {
2075
2100
  const nodes = asObjects(schema);
2076
- // `batch` açılır: içindeki silme de plana girer (kapı yalnız üst düzeye bakınca batch'teki
2077
- // `remove_component` akışı uyarısız siliyordu).
2078
- const opList = asObjects(ops).flatMap(op => op.op === 'batch' ? asObjects(op.ops) : [op]);
2101
+ const opList = asObjects(ops);
2079
2102
  const plan = [];
2080
- // Plan yamanın SON durumuna bakar: aynı yamada başka düğüme ya da eklenen gövdeye bağlanan akış
2081
- // referanssız değildir (K37-d: bağı `click`'ten `itemPress`'e taşıyan yama reddediliyordu). Aynı
2082
- // yamada kaldırılan düğüme eklenen bağ sayılmaz.
2083
- const removedTargets = new Set(opList.filter(op => op.op === 'remove_component').map(op => String(op.target ?? '')));
2084
- const boundByPatch = new Set();
2085
- for (const op of opList) {
2086
- if ((op.op === 'add_event' || op.op === 'set_event') && typeof op.eventValue === 'string' && !removedTargets.has(String(op.target ?? ''))) {
2087
- boundByPatch.add(op.eventValue);
2088
- }
2089
- if (op.op === 'add_component' && op.component && typeof op.component === 'object') {
2090
- for (const flowId of collectFlowRefs(op.component))
2091
- boundByPatch.add(flowId);
2092
- }
2093
- }
2094
2103
  const survivingRefs = (skipElementId, skipEvent) => {
2095
- const surviving = new Set(boundByPatch);
2104
+ const surviving = new Set();
2096
2105
  for (const event of asObjects(pageEvents)) {
2097
2106
  if (typeof event.value === 'string')
2098
2107
  surviving.add(event.value);
@@ -2142,7 +2151,7 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
2142
2151
  if (op.op === 'remove_event' && target === 'page' && Array.isArray(pageEvents)) {
2143
2152
  const hostEvents = asObjects(pageEvents);
2144
2153
  const removed = removedBy(boundTo(hostEvents));
2145
- const surviving = new Set([...boundByPatch, ...hostEvents.filter(event => !removed.includes(event) && typeof event.value === 'string').map(event => String(event.value))]);
2154
+ const surviving = new Set(hostEvents.filter(event => !removed.includes(event) && typeof event.value === 'string').map(event => String(event.value)));
2146
2155
  collectFlowRefsExcept(nodes, '', surviving);
2147
2156
  const flowIds = [...new Set(removed.map(event => String(event.value)))].filter(flowId => !surviving.has(flowId));
2148
2157
  if (flowIds.length > 0)