@appaflytech/zeyrek-ai-mcp 0.0.33 → 0.0.35

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 (170) 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 +634 -255
  6. package/dist/knowledge/componentEvents.js +38 -32
  7. package/dist/knowledge/layoutSummary.js +2 -140
  8. package/dist/knowledge/normalize.js +144 -117
  9. package/dist/knowledge/rules.js +42 -291
  10. package/dist/knowledge/styleResolve.js +53 -58
  11. package/dist/knowledge/themeResolve.js +4 -4
  12. package/dist/knowledge/themeSchema.js +2 -1
  13. package/dist/observability/trace.js +1 -1
  14. package/dist/platform/diagnostics.js +4 -10
  15. package/dist/platform/domSummary.js +1 -1
  16. package/dist/platform/http.js +7 -23
  17. package/dist/platform/responses.js +2 -6
  18. package/dist/platform/screenshot.js +1162 -0
  19. package/dist/platform/secrets.js +0 -9
  20. package/dist/platform/strictArguments.js +12 -68
  21. package/dist/platform/tokenVault.js +4 -187
  22. package/dist/resources/examples/layout-app-shell.json +707 -229
  23. package/dist/resources/examples/page-flex-sections.json +1 -1
  24. package/dist/resources/guides/component.md +6 -14
  25. package/dist/resources/guides/entity.md +5 -3
  26. package/dist/resources/guides/expressions.md +5 -14
  27. package/dist/resources/guides/functions.md +1 -1
  28. package/dist/resources/guides/layout.md +58 -55
  29. package/dist/resources/guides/microservice.md +2 -9
  30. package/dist/resources/guides/middleware.md +2 -34
  31. package/dist/resources/guides/page.md +179 -256
  32. package/dist/resources/guides/theme.md +3 -8
  33. package/dist/resources/guides/translation.md +1 -1
  34. package/dist/resources/guides/workflow.md +1 -7
  35. package/dist/resources/schema-fingerprint.json +4 -4
  36. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -3
  37. package/dist/resources/schemas/MicroserviceDto.json +2 -2
  38. package/dist/server.js +1 -7
  39. package/dist/tools/applications.js +3 -60
  40. package/dist/tools/components.js +16 -103
  41. package/dist/tools/datasources.js +1 -1
  42. package/dist/tools/designSchemaPatch.js +19 -23
  43. package/dist/tools/externalComponents.js +4 -25
  44. package/dist/tools/flows.js +13 -80
  45. package/dist/tools/layouts.js +20 -48
  46. package/dist/tools/microservices.js +10 -32
  47. package/dist/tools/pages.js +115 -396
  48. package/dist/tools/platformInfo.js +2 -7
  49. package/dist/tools/rows.js +1 -7
  50. package/dist/tools/schemaOps.js +4 -35
  51. package/dist/tools/screenWrite.js +37 -25
  52. package/dist/tools/screens.js +4 -91
  53. package/dist/tools/variables.js +5 -11
  54. package/package.json +2 -2
  55. package/dist/knowledge/access.js +0 -802
  56. package/dist/knowledge/case.js +0 -41
  57. package/dist/knowledge/connectDataBind.js +0 -819
  58. package/dist/knowledge/connectDataDefinition.js +0 -341
  59. package/dist/knowledge/connectDataExecute.js +0 -93
  60. package/dist/knowledge/connectDataRules.js +0 -128
  61. package/dist/knowledge/decision.js +0 -121
  62. package/dist/knowledge/expressionPrelude.js +0 -59
  63. package/dist/knowledge/microserviceParameters.js +0 -58
  64. package/dist/knowledge/mining.js +0 -94
  65. package/dist/knowledge/mobileComponentCatalog.js +0 -864
  66. package/dist/knowledge/mobileComponentEvents.js +0 -239
  67. package/dist/knowledge/mobileStore.js +0 -227
  68. package/dist/knowledge/platform/lint.js +0 -385
  69. package/dist/knowledge/platform/mobile.js +0 -142
  70. package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
  71. package/dist/knowledge/platform/mobileRules.js +0 -231
  72. package/dist/knowledge/platform/mobileSpacing.js +0 -82
  73. package/dist/knowledge/platform/mobileTabs.js +0 -108
  74. package/dist/knowledge/platform/nativeBoxModel.js +0 -44
  75. package/dist/knowledge/platform/profile.js +0 -25
  76. package/dist/knowledge/platform/resolve.js +0 -122
  77. package/dist/knowledge/platform/web.js +0 -39
  78. package/dist/knowledge/process.js +0 -510
  79. package/dist/knowledge/rowFilter.js +0 -43
  80. package/dist/knowledge/styleResolveNative.js +0 -527
  81. package/dist/platform/argumentAliases.js +0 -128
  82. package/dist/platform/bodyFile.js +0 -103
  83. package/dist/platform/capture/actions.js +0 -333
  84. package/dist/platform/capture/browser.js +0 -1
  85. package/dist/platform/capture/capture.js +0 -659
  86. package/dist/platform/capture/console-log.js +0 -122
  87. package/dist/platform/capture/index.js +0 -11
  88. package/dist/platform/capture/readiness.js +0 -103
  89. package/dist/platform/capture/summary.js +0 -77
  90. package/dist/platform/capture/target.js +0 -5
  91. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  92. package/dist/platform/capture/targets/studio-web.js +0 -5
  93. package/dist/platform/impersonation.js +0 -45
  94. package/dist/platform/jsonArray.js +0 -24
  95. package/dist/platform/schemaReadMemory.js +0 -60
  96. package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
  97. package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
  98. package/dist/resources/examples/bpm-satinalma.json +0 -376
  99. package/dist/resources/examples/connect-data-convert-verify.json +0 -107
  100. package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
  101. package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
  102. package/dist/resources/examples/connect-data-query-params.json +0 -50
  103. package/dist/resources/examples/connect-data-table-entity.json +0 -147
  104. package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
  105. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -244
  106. package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
  107. package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
  108. package/dist/resources/examples/mobile-form-screen.json +0 -365
  109. package/dist/resources/examples/mobile-list-detail-form.json +0 -703
  110. package/dist/resources/guides/access.md +0 -796
  111. package/dist/resources/guides/bpm.md +0 -686
  112. package/dist/resources/guides/case.md +0 -153
  113. package/dist/resources/guides/decision.md +0 -185
  114. package/dist/resources/guides/mobile-layout.md +0 -193
  115. package/dist/resources/guides/mobile.md +0 -578
  116. package/dist/resources/read.js +0 -41
  117. package/dist/resources/schemas/AccessExplanationDto.json +0 -144
  118. package/dist/resources/schemas/AccessMatrixDto.json +0 -170
  119. package/dist/resources/schemas/AccessPermissionDto.json +0 -57
  120. package/dist/resources/schemas/AccessPolicyDto.json +0 -223
  121. package/dist/resources/schemas/AccessResourceDto.json +0 -86
  122. package/dist/resources/schemas/AppSessionDto.json +0 -53
  123. package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
  124. package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
  125. package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
  126. package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
  127. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
  128. package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
  129. package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
  130. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
  131. package/dist/resources/schemas/DecisionDto.json +0 -302
  132. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
  133. package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
  134. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
  135. package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
  136. package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
  137. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
  138. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
  139. package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
  140. package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
  141. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
  142. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
  143. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
  144. package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
  145. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
  146. package/dist/resources/schemas/StartMobileBuildCommand.json +0 -54
  147. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
  148. package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
  149. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
  150. package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +0 -259
  151. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
  152. package/dist/tools/accessOperations.js +0 -135
  153. package/dist/tools/accessPolicies.js +0 -170
  154. package/dist/tools/accessRuntime.js +0 -203
  155. package/dist/tools/bpm.js +0 -343
  156. package/dist/tools/bpmGovernance.js +0 -266
  157. package/dist/tools/bpmOperations.js +0 -230
  158. package/dist/tools/bpmReporting.js +0 -154
  159. package/dist/tools/bpmRouting.js +0 -150
  160. package/dist/tools/bpmRuntime.js +0 -396
  161. package/dist/tools/case.js +0 -178
  162. package/dist/tools/caseRuntime.js +0 -89
  163. package/dist/tools/connectData.js +0 -449
  164. package/dist/tools/connectors.js +0 -193
  165. package/dist/tools/decisions.js +0 -206
  166. package/dist/tools/mobile.js +0 -221
  167. package/dist/tools/mobileStore.js +0 -268
  168. package/dist/tools/modules.js +0 -48
  169. package/dist/tools/organizationStructure.js +0 -137
  170. package/dist/tools/profileWrite.js +0 -92
@@ -1,8 +1,8 @@
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';
5
+ import { FUNCTIONS_NAMESPACE } from './functionGuards.js';
6
6
  const SORT_DEFAULT = { name: 'sortField', type: 'sortType', source: 'query-string' };
7
7
  const LIMIT_DEFAULT = { name: 'limit', offset: 'offset', source: 'query-string' };
8
8
  function asArray(value) {
@@ -270,11 +270,12 @@ export function normalizeWorkflowDefinition(definition) {
270
270
  */
271
271
  /**
272
272
  * 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
273
+ * `Runtime.svelte` altı, mobil `ScreenRuntime.tsx` beş tip ekler ve aynı sayfa kaydı ikisinde de
274
274
  * koşar. Register edilmemiş bir tipe gelen akış sessizce ölür (`flow-engine.ts` `process()`
275
275
  * callback bulamazsa next/completed/stopped hiç çağrılmaz), üstelik `run()` promise'i
276
276
  * çö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.
277
+ * olduğu için lint değil NORMALİZASYON — kalanı (`confirm`/`download` mobilde yok) yalnız
278
+ * uygulama tarafında kapanabilir, `FLOW-023` onları uyarır.
278
279
  */
279
280
  function normalizeFlowHostGaps(steps, list) {
280
281
  const fixes = [];
@@ -288,15 +289,12 @@ function normalizeFlowHostGaps(steps, list) {
288
289
  .map(step => String(step.stepId ?? ''))
289
290
  .filter(id => id.length > 0));
290
291
  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`);
292
+ // navigate ile redirect'in argümanı AYNI ({ path, pageId, query, targetBlank }) ama navigate'i
293
+ // yalnız mobil register eder; redirect ise iki barındırıcıda da koşar (mobilde aynı navigate
294
+ // uygulamasına eşlenir), yani redirect kesin üstün.
295
+ if (step.type === 'navigate') {
296
+ step.type = 'redirect';
297
+ 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
298
  }
301
299
  if (endStepIds.size === 0)
302
300
  continue;
@@ -361,6 +359,7 @@ const REQUIRED_COLLECTIONS = ['events', 'validations', 'stateBindings', 'childre
361
359
  *
362
360
  * - `states`: DesignComponentManagementSchema.ToDomain:47 `States.IsSticky`'yi guard'sız okur;
363
361
  * Appearance'ın satır 24'te varsayılanı var, States'in yok.
362
+ * - `blocks` doldurulmaz: konum ebeveynin düzenine bağlıdır, eksikse PAGE-037 ile reddedilir.
364
363
  * - `events` / `validations` / `stateBindings`: yalnız **micro-op yolunda** zorunlu.
365
364
  * `page_create` (POST /pages) bunlarsız 200 döner, `PATCH …/schema` NRE verir; canlı deneyde
366
365
  * üçü birlikte verilince geçti, her biri tek başına verilince patladı (klinik H-005 eki).
@@ -459,7 +458,13 @@ const VALIDATION_TYPE_ALIASES = new Map([
459
458
  ...VALIDATION_CANONICAL_TYPES.map(type => [type.replace(/-/g, ''), type]),
460
459
  ['pattern', 'regex'],
461
460
  ['min', 'min-value'],
462
- ['max', 'max-value']
461
+ ['max', 'max-value'],
462
+ // OR-2 (2026-10-03): kayıt defteri checkboxgroup/multi-select/tag-input kuralını minItems/maxItems
463
+ // adıyla ilan eder (component_get.validations); backend ValidationType'ta bu ad yok, runtime da tanımaz.
464
+ // Studio paneli bu üçüne 'custom' şablonundan min-length/max-length yazar (ng-apps-types
465
+ // validation/constants.ts) ve Form uzunluk kuralı dizide SEÇİLİ ELEMAN sayısını ölçer.
466
+ ['minitems', 'min-length'],
467
+ ['maxitems', 'max-length']
463
468
  ]);
464
469
  const VALIDATION_VALUE_REQUIRED = new Set(['regex', 'max-length', 'min-length', 'max-value', 'min-value', 'value-options']);
465
470
  function canonicalValidationType(value) {
@@ -653,48 +658,54 @@ export function styleKeyNote(fixed) {
653
658
  + 'değer kaydedilir ama hiç uygulanmaz ve tek işareti tarayıcı konsoludur (F-06). '
654
659
  + "Seçici anahtarlara ('&__body', ':hover', '--token') dokunulmadı."];
655
660
  }
661
+ /** PAGE-009 ile aynı kural: JS tanımlayıcısı (tireler çıkarılınca) ve ayrılmış `Functions` değil. */
662
+ function isDerivableComponentName(name) {
663
+ const bare = name.replace(/-/g, '');
664
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(bare) && bare !== FUNCTIONS_NAMESPACE;
665
+ }
656
666
  /**
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.
667
+ * Y-15 — adı eksik, null ya da boş/boşluk olan düğüm runtime'ın ifade ön sözünü bozar: `getNodeNames`
668
+ * null adı `"null"` anahtarına çevirir, `runCode` `const null = Components["null"]` satırını üretir
669
+ * (`ng-apps-flow/src/flow-execution.functions.ts`) ve sayfadaki BÜTÜN ifadeler SyntaxError'la düşer;
670
+ * hata yalnız akış adımının runtimeErrors'ında görünür (ölçüldü 2026-10-03, `y15-adsiz`). Backend adı
671
+ * hiç denetlemez (`PageSchemaValidator.cs`); Studio her düğüme `name = elementId` yazar
672
+ * (`ScreenBuilderDroppable.svelte`). Kural deterministik olduğu için reddetmek yerine dolduruyoruz.
673
+ * Doldurulan ad da PAGE-009'dan geçmek zorunda: çağıran bunu denetimden ÖNCE koşar. Dolu ada dokunulmaz.
674
+ * `normalizeComponentDefaults` aynı boşluğu yalnız geçerli bir elementId için ikinci kez kapatır (güvenlik ağı).
666
675
  */
667
- export function normalizeDroppableStates(nodes, droppable) {
668
- const fixed = [];
669
- if (droppable.size === 0)
670
- return fixed;
676
+ export function fillComponentNames(nodes) {
677
+ const filled = [];
671
678
  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
- }
679
+ const name = node.name;
680
+ const blank = name === undefined || name === null || (typeof name === 'string' && name.trim().length === 0);
681
+ if (blank && typeof node.elementId === 'string' && node.elementId.length > 0) {
682
+ node.name = node.elementId;
683
+ filled.push(node.elementId);
684
684
  }
685
- fixed.push(...normalizeDroppableStates(node.children, droppable));
685
+ filled.push(...fillComponentNames(node.children));
686
686
  }
687
- return fixed;
687
+ return filled;
688
688
  }
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`];
689
+ export function componentNameNote(filled) {
690
+ if (filled.length === 0)
691
+ return [];
692
+ const access = filled.length === 1 ? filled[0] : "her düğümün kendi elementId'si";
693
+ 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
694
  }
694
695
  export function normalizeComponentDefaults(nodes) {
695
696
  const fixed = [];
696
697
  for (const node of asObjects(nodes)) {
697
698
  const missing = [];
699
+ // name'siz düğümü platform kabul eder ama sayfada bir akış ya da `{{ }}` kod prop'u varsa
700
+ // FlowEngine runCode "Cannot read properties of undefined (reading 'catch')" ile düşer, akış
701
+ // `running:1`'de takılır ve hata adsız düğümü işaret etmez (image ölçüm turu, 2026-10-04).
702
+ // Yalnız PAGE-009'un geçerli saydığı elementId'den türetilir: page_create/page_update/layout
703
+ // yollarında PAGE-009 denetimi bu normalizasyondan ÖNCE koşar; bozuk bir elementId'den türeyen
704
+ // ad denetimi atlatıp "Missing initializer in const declaration" ile sayfayı öldürürdü.
705
+ if ((typeof node.name !== 'string' || node.name.trim() === '') && typeof node.elementId === 'string' && isDerivableComponentName(node.elementId)) {
706
+ node.name = node.elementId;
707
+ missing.push('name');
708
+ }
698
709
  if (!node.states || typeof node.states !== 'object') {
699
710
  node.states = { ...DEFAULT_STATES };
700
711
  missing.push('states');
@@ -749,6 +760,65 @@ export function normalizeComponentDefaults(nodes) {
749
760
  }
750
761
  return fixed;
751
762
  }
763
+ export const COMPONENT_BODY_RULE = "Asgari gövde: { elementId, name (= elementId), type, props, blocks: [{ breakpoint: 1024, size: { w, h }, position: { x, y } }] }. "
764
+ + "Gateway blocks'u doldurmaz: blocks'u olmayan ya da null olan düğüm platformda kayıt sırasında 500 NullReferenceException verir. "
765
+ + "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), "
766
+ + 'ızgara kapta x:0, y: kardeşlerin altı (en büyük y+h).';
767
+ /**
768
+ * Y-13 / PAGE-037 — `blocks` alanı hiç olmayan ya da `null` olan düğümleri (çocuklar dahil) toplar.
769
+ * `DesignComponentManagementSchema.Blocks`'un varsayılanı yoktur; `ToDomain` null listeyi
770
+ * `AddBlocks(null)` ile atlar, `_blocks` başlatılmaz ve `Blocks` getter'ı kayıtta patlar
771
+ * (`DesignComponent.cs:36-37,305`; yeni düğümde revizyon yakalama `ToObject:464`, var olan düğümde
772
+ * `DesignComponentRepository.UpsertRange` → `Override`). Ölçüldü 2026-10-04: son 7 günde eklenen
773
+ * düğümlerin ~%20'si blocks'suz geldi ve hepsi 500 aldı. Konum ebeveynin düzenine bağlı olduğu için
774
+ * doldurmuyoruz, reddediyoruz. `blocks: []` platformda kaydolur (ölçüldü 2026-10-04, `y13-blocks`) ve buraya girmez.
775
+ */
776
+ export function missingBlocksNodes(nodes) {
777
+ const missing = [];
778
+ for (const node of asObjects(nodes)) {
779
+ if (node.blocks === undefined || node.blocks === null) {
780
+ missing.push(`'${String(node.elementId ?? node.name ?? node.type ?? '?')}': blocks eksik — şunu ver: [{breakpoint:1024, size:{w,h}, position:{x,y}}]`);
781
+ }
782
+ missing.push(...missingBlocksNodes(node.children));
783
+ }
784
+ return missing;
785
+ }
786
+ /**
787
+ * PAGE-037 kimlik ayağı — platform elementId'siz add_component'i 'missing-id' ile reddeder
788
+ * (`PageSchemaMicroOpApplier.cs` add_component dalı) ama mesajı kimliğin hangi alan olduğunu
789
+ * söylemez. Ajanlar `name` verip elementId'yi atladı (Y-13 neden analizi N-B3, 5 düğüm).
790
+ */
791
+ export function addComponentIdErrors(ops) {
792
+ const errors = [];
793
+ for (const op of asObjects(ops)) {
794
+ if (op.op !== 'add_component')
795
+ continue;
796
+ const component = op.component && typeof op.component === 'object' ? op.component : {};
797
+ const elementId = component.elementId;
798
+ if (typeof elementId === 'string' && elementId.trim() !== '')
799
+ continue;
800
+ const name = typeof component.name === 'string' && component.name.trim() !== '' ? component.name : undefined;
801
+ 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}')` : ''}`);
802
+ }
803
+ return errors;
804
+ }
805
+ /**
806
+ * PAGE-037. Yalnız çağıranın verdiği ağaca bakar: page_create'in eklediği page_container
807
+ * blocks'la üretilir, okunan kayıttaki düğümler (layout_patch) platformdan blocks listesiyle gelir.
808
+ * Sayfa/layout yazma kapısı (`assertScreenWriteGuards`), `page_schema_validate` ve
809
+ * `component_update` çağırır; `page_schema_patch` aynı denetimi op başına toplar.
810
+ */
811
+ export function assertComponentBlocks(nodes) {
812
+ const missing = missingBlocksNodes(nodes);
813
+ if (missing.length === 0)
814
+ return;
815
+ throw new PlatformApiError(`PAGE-037 — komponent gövdesinde blocks yok (istek gönderilmedi): ${missing.join(' · ')}. ${COMPONENT_BODY_RULE}`, 400);
816
+ }
817
+ export function assertAddComponentIds(ops) {
818
+ const errors = addComponentIdErrors(ops);
819
+ if (errors.length > 0)
820
+ throw new PlatformApiError(`PAGE-037 — ${errors.join(' · ')} (istek gönderilmedi). ${COMPONENT_BODY_RULE}`, 400);
821
+ }
752
822
  /**
753
823
  * add_component micro-op'unun taşıdığı komponent ağacı da aynı ToDomain yolundan geçer.
754
824
  */
@@ -845,6 +915,7 @@ export function normalizeSchemaOps(ops) {
845
915
  const components = [];
846
916
  const props = [];
847
917
  const validations = [];
918
+ const names = [];
848
919
  for (const op of asObjects(ops)) {
849
920
  if (op.op === 'replace_prop') {
850
921
  if (isStylePropName(String(op.prop ?? ''))) {
@@ -866,9 +937,10 @@ export function normalizeSchemaOps(ops) {
866
937
  }
867
938
  if (op.op !== 'add_component' || !op.component)
868
939
  continue;
940
+ names.push(...fillComponentNames([op.component]));
869
941
  components.push(...normalizeComponentDefaults([op.component]));
870
942
  }
871
- return { components, props, validations };
943
+ return { components, props, validations, names };
872
944
  }
873
945
  export function validationNote(fixed) {
874
946
  return fixed.length === 0 ? [] : [`validation gövdeleri düzeltildi (${fixed.join(' · ')})`];
@@ -925,11 +997,11 @@ export function pageContainerNode() {
925
997
  * çekilirlerse sayfa içeriğinin akışına girer ve katman olarak açılmazlar.
926
998
  */
927
999
  const ROOT_LAYER_TYPES = new Set(['modal', 'drawer']);
928
- export function ensurePageContainer(schema, rootContainer = pageContainerNode) {
1000
+ export function ensurePageContainer(schema) {
929
1001
  const nodes = asObjects(schema);
930
1002
  if (nodes.some(node => node.elementId === PAGE_CONTAINER_ELEMENT_ID))
931
1003
  return { schema: nodes, fixes: [] };
932
- const container = rootContainer();
1004
+ const container = pageContainerNode();
933
1005
  const layers = nodes.filter(node => ROOT_LAYER_TYPES.has(String(node.type ?? '')));
934
1006
  container.children = nodes.filter(node => !ROOT_LAYER_TYPES.has(String(node.type ?? '')));
935
1007
  const moved = container.children.length;
@@ -972,7 +1044,7 @@ export function clampBlockSizes(nodes, maxSizes) {
972
1044
  * başlatır (`ComponentHeightType.Fixed = 0`), yani "alan yok" = "sabit yükseklik". Studio'nun
973
1045
  * kendi bırakma yolu bunu ASLA yapmaz: katalogdaki `isDefaultAutoHeight`e bakıp
974
1046
  * `heightType: isDefaultAutoHeight ? 'auto' : 'fixed'` yazar
975
- * (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts` `createDefaultSchemaNode`). Katalogda varsayılan
1047
+ * (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts:233`). Katalogda varsayılan
976
1048
  * `true`'dur (`ZeyrekComponent.ts:62`); `false` diyen yalnız sekiz tip var — auth-layout, html,
977
1049
  * image, layout, qrcode, table, text-editor, video.
978
1050
  *
@@ -1758,18 +1830,19 @@ export function viewAliasNote(fixes) {
1758
1830
  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
1831
  }
1760
1832
  /**
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.
1833
+ * Değişken seti tek bir kayıtta yaşar: `CreateAppVariableCommand`/`CreatePageVariableCommand`
1834
+ * yalnız `Data` alanı taşır (Studio uygulama başına ve sayfa başına TEK satır tutar —
1835
+ * `IsVariableExistForApplicationAsync` doluysa create update'e döner). Studio'nun gönderdiği şekil
1836
+ * `data`'nın **JSON string** olmasıdır: "[{\"key\":\"MyTest\",\"value\":{\"isActive\":true}}]".
1837
+ * `Data` tipi `object` olduğu için platform her gövdeyi kabul eder; alan adı tutmayan bir gövde
1838
+ * (name/type/defaultValue gibi) `Data`'yı null bırakır ve istek 200 döner ama HİÇBİR ŞEY yazılmaz
1839
+ * (17/Ç1). Okuma tarafı da aynı string'i geri verir (`AppVariablesDto.Map` → GetRawText).
1764
1840
  */
1765
1841
  export function parseVariableEntries(data) {
1766
1842
  const source = typeof data === 'string' ? safeParse(data) : data;
1767
1843
  return asObjects(source)
1768
1844
  .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
- });
1845
+ .map(entry => ({ key: String(entry.key), value: entry.value }));
1773
1846
  }
1774
1847
  function safeParse(value) {
1775
1848
  try {
@@ -1784,29 +1857,17 @@ function safeParse(value) {
1784
1857
  * mevcut seti okuyup anahtar bazında birleştirir; `replace: true` verilirse bilinçli olarak ezer.
1785
1858
  */
1786
1859
  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
1860
  if (replace)
1793
- return { entries: incoming.map(entry => stored(entry)), fixes: [] };
1861
+ return { entries: incoming, fixes: [] };
1794
1862
  const merged = [...existing];
1795
1863
  const kept = [];
1796
- const keptStorage = [];
1797
- const keptValue = [];
1798
1864
  for (const entry of incoming) {
1799
1865
  const index = merged.findIndex(current => current.key === entry.key);
1800
1866
  if (index === -1) {
1801
- merged.push(stored(entry));
1867
+ merged.push(entry);
1802
1868
  continue;
1803
1869
  }
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);
1870
+ merged[index] = entry;
1810
1871
  }
1811
1872
  for (const entry of existing) {
1812
1873
  if (!incoming.some(current => current.key === entry.key))
@@ -1814,17 +1875,9 @@ export function mergeVariableEntries(existing, incoming, replace) {
1814
1875
  }
1815
1876
  return {
1816
1877
  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
- ]
1878
+ fixes: kept.length > 0
1879
+ ? [`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`]
1880
+ : []
1828
1881
  };
1829
1882
  }
1830
1883
  export function blockSizeNote(clamped) {
@@ -1860,7 +1913,7 @@ export function rootAddsNote(retargeted, containerElementId) {
1860
1913
  export function componentDefaultsNote(fixed) {
1861
1914
  if (fixed.length === 0)
1862
1915
  return [];
1863
- return [`komponent gövdelerine eksik zorunlu alanlar eklendi (${fixed.join(' · ')}): bunlar olmadan platform NullReferenceException verir ve page_schema_validate bunu yakalamaz`];
1916
+ 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
1917
  }
1865
1918
  /**
1866
1919
  * Create yolu junction kaydını açar ama fiziksel tabloyu kurmaz (platform bug'ı P-01,
@@ -1905,22 +1958,12 @@ export function nestedRepeaterNodes(nodes) {
1905
1958
  walk(asObjects(nodes), false);
1906
1959
  return found;
1907
1960
  }
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(' · ')}. `
1961
+ export function nestedRepeaterMessage(ids) {
1962
+ return `PAGE-013 — repeater içinde repeater (istek gönderilmedi): ${ids.join(' · ')}. `
1914
1963
  + 'Ölçüldü (2026-08-19): iç repeater OKUMADA çalışır ama girilen değer dış satıra GERİ YAZILMAZ '
1915
1964
  + '(_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;
1965
+ + 'repeater tek düğümdür, dış satır başına ayrı düğüm yoktur. Satır içi listeyi tek bir textarea '
1966
+ + "ile topla (satır başına bir öğe) ve kaydederken split('\n') ile böl — platform_guide('page') Kural 1g.";
1924
1967
  }
1925
1968
  /**
1926
1969
  * `style` prop'u düz CSS STRING verilmiş düğümler. Çalışır (emotion string'i CSS metni sayar) ama
@@ -1934,7 +1977,7 @@ export function stringStyleNodes(nodes) {
1934
1977
  for (const node of list) {
1935
1978
  const props = (node.props ?? {});
1936
1979
  const style = props.style;
1937
- if (style && typeof style.data === 'string' && style.data.includes(':') && !DOCUMENT_STYLE_TYPES.has(String(node.type))) {
1980
+ if (style && typeof style.data === 'string' && style.data.includes(':')) {
1938
1981
  found.push(String(node.elementId ?? node.name ?? '?'));
1939
1982
  }
1940
1983
  walk(asObjects(node.children));
@@ -2073,26 +2116,10 @@ export function flowBindings(schema, hostEvents) {
2073
2116
  */
2074
2117
  export function orphanedFlowPlan(schema, pageEvents, ops) {
2075
2118
  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]);
2119
+ const opList = asObjects(ops);
2079
2120
  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
2121
  const survivingRefs = (skipElementId, skipEvent) => {
2095
- const surviving = new Set(boundByPatch);
2122
+ const surviving = new Set();
2096
2123
  for (const event of asObjects(pageEvents)) {
2097
2124
  if (typeof event.value === 'string')
2098
2125
  surviving.add(event.value);
@@ -2142,7 +2169,7 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
2142
2169
  if (op.op === 'remove_event' && target === 'page' && Array.isArray(pageEvents)) {
2143
2170
  const hostEvents = asObjects(pageEvents);
2144
2171
  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))]);
2172
+ const surviving = new Set(hostEvents.filter(event => !removed.includes(event) && typeof event.value === 'string').map(event => String(event.value)));
2146
2173
  collectFlowRefsExcept(nodes, '', surviving);
2147
2174
  const flowIds = [...new Set(removed.map(event => String(event.value)))].filter(flowId => !surviving.has(flowId));
2148
2175
  if (flowIds.length > 0)