@appaflytech/zeyrek-ai-mcp 0.0.28 → 0.0.30

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 (201) hide show
  1. package/.env.example +15 -0
  2. package/README.md +5 -5
  3. package/dist/config.js +37 -0
  4. package/dist/index.js +2 -0
  5. package/dist/knowledge/access.js +802 -0
  6. package/dist/knowledge/backendConstraints.js +18 -1
  7. package/dist/knowledge/case.js +41 -0
  8. package/dist/knowledge/componentCatalog.js +494 -34
  9. package/dist/knowledge/componentEvents.js +132 -7
  10. package/dist/knowledge/connectDataBind.js +819 -0
  11. package/dist/knowledge/connectDataDefinition.js +341 -0
  12. package/dist/knowledge/connectDataExecute.js +93 -0
  13. package/dist/knowledge/connectDataRules.js +128 -0
  14. package/dist/knowledge/decision.js +121 -0
  15. package/dist/knowledge/expressionPrelude.js +59 -0
  16. package/dist/knowledge/layoutSummary.js +140 -2
  17. package/dist/knowledge/microserviceParameters.js +58 -0
  18. package/dist/knowledge/mining.js +94 -0
  19. package/dist/knowledge/mobileComponentCatalog.js +859 -0
  20. package/dist/knowledge/mobileComponentEvents.js +239 -0
  21. package/dist/knowledge/normalize.js +236 -67
  22. package/dist/knowledge/outlines.js +36 -0
  23. package/dist/knowledge/platform/lint.js +385 -0
  24. package/dist/knowledge/platform/mobile.js +142 -0
  25. package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
  26. package/dist/knowledge/platform/mobileRules.js +231 -0
  27. package/dist/knowledge/platform/mobileSpacing.js +82 -0
  28. package/dist/knowledge/platform/mobileTabs.js +108 -0
  29. package/dist/knowledge/platform/nativeBoxModel.js +44 -0
  30. package/dist/knowledge/platform/profile.js +25 -0
  31. package/dist/knowledge/platform/resolve.js +122 -0
  32. package/dist/knowledge/platform/web.js +39 -0
  33. package/dist/knowledge/policy.js +18 -4
  34. package/dist/knowledge/process.js +510 -0
  35. package/dist/knowledge/reservedTables.js +79 -0
  36. package/dist/knowledge/rowFilter.js +43 -0
  37. package/dist/knowledge/rules.js +319 -21
  38. package/dist/knowledge/schemaGuard.js +11 -0
  39. package/dist/knowledge/styleResolve.js +50 -4
  40. package/dist/knowledge/styleResolveNative.js +527 -0
  41. package/dist/knowledge/themeResolve.js +3 -3
  42. package/dist/observability/trace.js +6 -3
  43. package/dist/platform/argumentAliases.js +128 -0
  44. package/dist/platform/bodyFile.js +103 -0
  45. package/dist/platform/capture/actions.js +333 -0
  46. package/dist/platform/capture/browser.js +1 -0
  47. package/dist/platform/{screenshot.js → capture/capture.js} +105 -519
  48. package/dist/platform/capture/console-log.js +122 -0
  49. package/dist/platform/capture/index.js +11 -0
  50. package/dist/platform/capture/readiness.js +103 -0
  51. package/dist/platform/capture/summary.js +77 -0
  52. package/dist/platform/capture/target.js +5 -0
  53. package/dist/platform/capture/targets/studio-mobile.js +15 -0
  54. package/dist/platform/capture/targets/studio-web.js +5 -0
  55. package/dist/platform/diagnostics.js +10 -4
  56. package/dist/platform/domSummary.js +1 -1
  57. package/dist/platform/errors.js +162 -10
  58. package/dist/platform/http.js +29 -8
  59. package/dist/platform/impersonation.js +45 -0
  60. package/dist/platform/jsonArray.js +24 -0
  61. package/dist/platform/responses.js +39 -5
  62. package/dist/platform/schemaReadMemory.js +60 -0
  63. package/dist/platform/secrets.js +17 -1
  64. package/dist/platform/strictArguments.js +68 -12
  65. package/dist/platform/tokenVault.js +187 -4
  66. package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
  67. package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
  68. package/dist/resources/examples/bpm-satinalma.json +376 -0
  69. package/dist/resources/examples/connect-data-convert-verify.json +107 -0
  70. package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
  71. package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
  72. package/dist/resources/examples/connect-data-query-params.json +50 -0
  73. package/dist/resources/examples/connect-data-table-entity.json +147 -0
  74. package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
  75. package/dist/resources/examples/mobile-app-shell-drawer.json +243 -0
  76. package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
  77. package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
  78. package/dist/resources/examples/mobile-form-screen.json +365 -0
  79. package/dist/resources/examples/mobile-list-detail-form.json +672 -0
  80. package/dist/resources/examples/page-detail-profile.json +2 -1
  81. package/dist/resources/examples/page-dynamic-form.json +3 -2
  82. package/dist/resources/examples/page-flex-sections.json +1 -1
  83. package/dist/resources/examples/page-html-embed.json +1 -1
  84. package/dist/resources/examples/workflow-basic.json +8 -2
  85. package/dist/resources/guides/access.md +796 -0
  86. package/dist/resources/guides/bpm.md +686 -0
  87. package/dist/resources/guides/case.md +153 -0
  88. package/dist/resources/guides/component.md +91 -4
  89. package/dist/resources/guides/decision.md +185 -0
  90. package/dist/resources/guides/entity.md +50 -8
  91. package/dist/resources/guides/expressions.md +14 -5
  92. package/dist/resources/guides/functions.md +1 -1
  93. package/dist/resources/guides/getting-started.md +38 -1
  94. package/dist/resources/guides/layout.md +11 -7
  95. package/dist/resources/guides/microservice.md +81 -2
  96. package/dist/resources/guides/middleware.md +44 -2
  97. package/dist/resources/guides/mobile-layout.md +193 -0
  98. package/dist/resources/guides/mobile.md +495 -0
  99. package/dist/resources/guides/page.md +454 -75
  100. package/dist/resources/guides/theme.md +8 -2
  101. package/dist/resources/guides/translation.md +1 -1
  102. package/dist/resources/guides/workflow.md +58 -1
  103. package/dist/resources/read.js +41 -0
  104. package/dist/resources/rules.js +11 -5
  105. package/dist/resources/schema-fingerprint.json +7 -5
  106. package/dist/resources/schemas/AccessExplanationDto.json +144 -0
  107. package/dist/resources/schemas/AccessMatrixDto.json +170 -0
  108. package/dist/resources/schemas/AccessPermissionDto.json +57 -0
  109. package/dist/resources/schemas/AccessPolicyDto.json +223 -0
  110. package/dist/resources/schemas/AccessResourceDto.json +86 -0
  111. package/dist/resources/schemas/AppSessionDto.json +53 -0
  112. package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
  113. package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
  114. package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
  115. package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
  116. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
  117. package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
  118. package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
  119. package/dist/resources/schemas/CreateEntityCommand.json +118 -0
  120. package/dist/resources/schemas/CreateMicroserviceCommand.json +13 -1
  121. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
  122. package/dist/resources/schemas/CreateQueryCommand.json +4 -0
  123. package/dist/resources/schemas/CreateWorkflowCommand.json +143 -1
  124. package/dist/resources/schemas/DataJobDto.json +6 -1
  125. package/dist/resources/schemas/DecisionDto.json +302 -0
  126. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
  127. package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
  128. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
  129. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +21 -1
  130. package/dist/resources/schemas/MicroserviceDto.json +15 -3
  131. package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
  132. package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
  133. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
  134. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
  135. package/dist/resources/schemas/PreviewMicroserviceCommand.json +10 -1
  136. package/dist/resources/schemas/PreviewWorkflowCommand.json +22 -1
  137. package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
  138. package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
  139. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
  140. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
  141. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
  142. package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
  143. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
  144. package/dist/resources/schemas/StepDto.json +22 -1
  145. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
  146. package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
  147. package/dist/resources/schemas/UpdateEntityCommand.json +118 -0
  148. package/dist/resources/schemas/UpdateMicroserviceCommand.json +13 -1
  149. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
  150. package/dist/resources/schemas/UpdateQueryCommand.json +4 -0
  151. package/dist/resources/schemas/UpdateViewCommand.json +0 -2
  152. package/dist/resources/schemas/UpdateWorkflowCommand.json +143 -1
  153. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
  154. package/dist/server.js +27 -1
  155. package/dist/tools/access.js +369 -2
  156. package/dist/tools/accessOperations.js +135 -0
  157. package/dist/tools/accessPolicies.js +170 -0
  158. package/dist/tools/accessRuntime.js +203 -0
  159. package/dist/tools/applications.js +60 -3
  160. package/dist/tools/bpm.js +343 -0
  161. package/dist/tools/bpmGovernance.js +266 -0
  162. package/dist/tools/bpmOperations.js +230 -0
  163. package/dist/tools/bpmReporting.js +154 -0
  164. package/dist/tools/bpmRouting.js +150 -0
  165. package/dist/tools/bpmRuntime.js +396 -0
  166. package/dist/tools/case.js +178 -0
  167. package/dist/tools/caseRuntime.js +89 -0
  168. package/dist/tools/common.js +7 -0
  169. package/dist/tools/components.js +118 -14
  170. package/dist/tools/connectData.js +449 -0
  171. package/dist/tools/connectors.js +193 -0
  172. package/dist/tools/datasources.js +3 -3
  173. package/dist/tools/decisions.js +206 -0
  174. package/dist/tools/dependencies.js +1 -1
  175. package/dist/tools/deployments.js +2 -2
  176. package/dist/tools/designSchemaPatch.js +34 -9
  177. package/dist/tools/dtos.js +36 -5
  178. package/dist/tools/entities.js +79 -12
  179. package/dist/tools/externalComponents.js +26 -5
  180. package/dist/tools/flows.js +122 -14
  181. package/dist/tools/folders.js +1 -1
  182. package/dist/tools/imports.js +5 -2
  183. package/dist/tools/layouts.js +50 -17
  184. package/dist/tools/merges.js +1 -1
  185. package/dist/tools/microservices.js +77 -25
  186. package/dist/tools/mobile.js +221 -0
  187. package/dist/tools/modules.js +48 -0
  188. package/dist/tools/organizationStructure.js +137 -0
  189. package/dist/tools/pages.js +465 -98
  190. package/dist/tools/platformInfo.js +27 -8
  191. package/dist/tools/profileWrite.js +92 -0
  192. package/dist/tools/projects.js +71 -9
  193. package/dist/tools/rows.js +69 -13
  194. package/dist/tools/schemaOps.js +61 -1
  195. package/dist/tools/screenWrite.js +37 -8
  196. package/dist/tools/screens.js +95 -5
  197. package/dist/tools/templates.js +26 -1
  198. package/dist/tools/translations.js +1 -1
  199. package/dist/tools/variables.js +11 -5
  200. package/dist/tools/workflows.js +10 -5
  201. package/package.json +2 -2
@@ -1,7 +1,9 @@
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 { TYPED_STYLE_COMPONENTS } from './styleResolve.js';
4
+ import { DOCUMENT_STYLE_TYPES, TYPED_STYLE_COMPONENTS } from './styleResolve.js';
5
+ import { STATE_STORAGE_KINDS, STEP_ALIASES } from './platform/profile.js';
6
+ import { inlineStyleFields } from './componentCatalog.js';
5
7
  const SORT_DEFAULT = { name: 'sortField', type: 'sortType', source: 'query-string' };
6
8
  const LIMIT_DEFAULT = { name: 'limit', offset: 'offset', source: 'query-string' };
7
9
  function asArray(value) {
@@ -269,12 +271,11 @@ export function normalizeWorkflowDefinition(definition) {
269
271
  */
270
272
  /**
271
273
  * Adım tipi sözlüğü backend'in, KOŞAN tipler barındırıcının: motor yedi tip register eder, web
272
- * `Runtime.svelte` altı, mobil `ScreenRuntime.tsx` beş tip ekler ve aynı sayfa kaydı ikisinde de
274
+ * `Runtime.svelte` altı, mobil `runtime-tasks.ts` yedi tip ekler ve aynı sayfa kaydı ikisinde de
273
275
  * koşar. Register edilmemiş bir tipe gelen akış sessizce ölür (`flow-engine.ts` `process()`
274
276
  * callback bulamazsa next/completed/stopped hiç çağrılmaz), üstelik `run()` promise'i
275
277
  * çözülmediği için `__ngAppsFlowActivity.running` sıfıra inmez. İki hâl tamamen türetilebilir
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
+ * olduğu için lint değil NORMALİZASYON; `FLOW-023` kalan hâlleri uyarır.
278
279
  */
279
280
  function normalizeFlowHostGaps(steps, list) {
280
281
  const fixes = [];
@@ -288,12 +289,15 @@ 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 }) 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`);
292
+ // navigate ile redirect'in argümanı AYNI ({ path, pageId, query, targetBlank, presentation })
293
+ // ama navigate'i yalnız mobil register eder; redirect ise iki barındırıcıda da koşar (mobilde
294
+ // aynı navigate uygulamasına eşlenir), yani redirect kesin üstün. `presentation`
295
+ // (push | modal | replace) yalnız mobil barındırıcıda okunur; web yok sayar.
296
+ const alias = STEP_ALIASES[String(step.type ?? '')];
297
+ if (alias) {
298
+ const original = String(step.type);
299
+ step.type = alias;
300
+ 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`);
297
301
  }
298
302
  if (endStepIds.size === 0)
299
303
  continue;
@@ -369,9 +373,17 @@ const REQUIRED_COLLECTIONS = ['events', 'validations', 'stateBindings', 'childre
369
373
  // PropValueType (DesignComponentProperty.cs:421) — 'translation' listeden düşünce çeviriye bağlı
370
374
  // prop'un KENDİSİ veri sanılıp static Prop'a sarılıyordu: istek 200 dönüyor, prop bozuk kuruluyordu
371
375
  // (09-04 Y-22). Enum burada eksiksiz tutulur.
372
- export const PROP_VALUE_TYPES = new Set(['static', 'file', 'flow', 'widget', 'element', 'page', 'code', 'translation']);
376
+ export const PROP_VALUE_TYPES = new Set(['static', 'file', 'flow', 'widget', 'element', 'page', 'code', 'translation', 'connectData']);
377
+ // Prop'un TAŞIYICISI da aranır: `type` tek başına yetmez, çünkü liste öğesinin kendi `type` alanı
378
+ // olabilir ve değeri Prop tipi adıyla çakışabilir — datatable kolonunda dosya alanı tam olarak
379
+ // böyledir (`{ name, label, type: 'file', isFilterable }`). Yalnız `type`'a bakan sürüm o öğeyi
380
+ // kurulu bir Prop sanıp sarmadan bırakıyordu ve platform 500 JsonException veriyordu (koşu
381
+ // bulgusu S-2'nin gateway ayağı; Studio ayağı `staticFieldListItems` ile aynı kararı verdi).
373
382
  function isPropShaped(value) {
374
- return Boolean(value) && typeof value === 'object' && !Array.isArray(value) && PROP_VALUE_TYPES.has(String(value.type));
383
+ if (!value || typeof value !== 'object' || Array.isArray(value))
384
+ return false;
385
+ const candidate = value;
386
+ return PROP_VALUE_TYPES.has(String(candidate.type)) && ('data' in candidate || 'ref' in candidate);
375
387
  }
376
388
  function wrapPropDictionaryValues(dictionary) {
377
389
  let wrapped = false;
@@ -614,12 +626,16 @@ export function codePropTemplateErrors(ops) {
614
626
  *
615
627
  * Seçici anahtarlara (`&__body`, `:hover`, `--token`) DOKUNULMAZ; yalnız `a-b` biçimli düz CSS
616
628
  * özellik adları camelCase'e çevrilir ve çevrim `gatewayNormalized` ile bildirilir.
629
+ *
630
+ * TB-129 — `inlineFields` verilirse o ÜST DÜZEY alanların altına hiç girilmez: `table.style.th`
631
+ * gibi dallar satır içi `style` attribute'una basılır ve kebab-case zorunludur
632
+ * (`INLINE_STYLE_FIELDS_BY_TYPE`). Çeviri orada stili öldürüyordu.
617
633
  */
618
634
  const styleKeyPattern = /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/;
619
635
  export function isStylePropName(name) {
620
636
  return name === 'style' || /Style$/.test(name);
621
637
  }
622
- export function normalizeStyleKeys(value, label, fixed) {
638
+ export function normalizeStyleKeys(value, label, fixed, inlineFields) {
623
639
  if (Array.isArray(value)) {
624
640
  for (const entry of value)
625
641
  normalizeStyleKeys(entry, label, fixed);
@@ -628,7 +644,10 @@ export function normalizeStyleKeys(value, label, fixed) {
628
644
  if (!value || typeof value !== 'object')
629
645
  return;
630
646
  const record = value;
647
+ const skipped = new Set(inlineFields ?? []);
631
648
  for (const key of Object.keys(record)) {
649
+ if (skipped.has(key))
650
+ continue;
632
651
  normalizeStyleKeys(record[key], label, fixed);
633
652
  if (!styleKeyPattern.test(key))
634
653
  continue;
@@ -650,6 +669,44 @@ export function styleKeyNote(fixed) {
650
669
  + 'değer kaydedilir ama hiç uygulanmaz ve tek işareti tarayıcı konsoludur (F-06). '
651
670
  + "Seçici anahtarlara ('&__body', ':hover', '--token') dokunulmadı."];
652
671
  }
672
+ /**
673
+ * Kabın `states.isDroppable`ı KATALOĞUN kararıdır. Gateway düğümü kurarken bu alanı
674
+ * yazmıyordu (`DEFAULT_STATES` hepsini `false` bırakır) ve Studio kanvası düğümü kap saymıyordu:
675
+ * imleç `scroll-view`un İÇİNDEYKEN bırakma planı sayfa kabına düşüyor, çizgi kabın üst kenarına
676
+ * çiziliyordu (ölçüldü 2026-09-21, `test/mobile app` › `Satislar`). Aynı tipi paletten ekleyen
677
+ * Studio katalog değerini yazdığı için tek şemada iki türlü davranan kap oluyordu.
678
+ *
679
+ * Değer uygulamanın KENDİ sözlüğünden gelir (`listComponents`; mobil uygulamada `type=mobile`
680
+ * satırları), yani kural platformdan bağımsızdır ve kuruluşun kendi komponentlerini de kapsar.
681
+ * Yalnız `true` yazılır: katalog bir tipi kap saymıyorsa düğüme dokunulmaz.
682
+ */
683
+ export function normalizeDroppableStates(nodes, droppable) {
684
+ const fixed = [];
685
+ if (droppable.size === 0)
686
+ return fixed;
687
+ for (const node of asObjects(nodes)) {
688
+ const type = typeof node.type === 'string' ? node.type : '';
689
+ if (droppable.get(type) === true) {
690
+ // `states` normalde `normalizeComponentDefaults`tan geçmiş olur; gelmediyse burada da
691
+ // eksiksiz kurulur — yarım `states` platformda NullReference üretir.
692
+ if (!node.states || typeof node.states !== 'object' || Array.isArray(node.states)) {
693
+ node.states = { ...DEFAULT_STATES };
694
+ }
695
+ const states = node.states;
696
+ if (states.isDroppable !== true) {
697
+ states.isDroppable = true;
698
+ fixed.push(`'${String(node.elementId ?? node.name ?? type)}' (${type})`);
699
+ }
700
+ }
701
+ fixed.push(...normalizeDroppableStates(node.children, droppable));
702
+ }
703
+ return fixed;
704
+ }
705
+ export function droppableStatesNote(fixed) {
706
+ return fixed.length === 0
707
+ ? []
708
+ : [`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`];
709
+ }
653
710
  export function normalizeComponentDefaults(nodes) {
654
711
  const fixed = [];
655
712
  for (const node of asObjects(nodes)) {
@@ -689,8 +746,10 @@ export function normalizeComponentDefaults(nodes) {
689
746
  if (node.props && typeof node.props === 'object' && !Array.isArray(node.props)) {
690
747
  const props = node.props;
691
748
  const styleKeys = [];
749
+ // Satır içi stil dalları komponent TİPİNE göre atlanır; tip bilinmiyorsa eski davranış.
750
+ const inlineFields = (name) => name === 'style' ? inlineStyleFields(typeof node.type === 'string' ? node.type : undefined) : undefined;
692
751
  for (const name of Object.keys(props).filter(isStylePropName)) {
693
- normalizeStyleKeys(props[name], `${String(node.elementId ?? node.name ?? '?')}.${name}`, styleKeys);
752
+ normalizeStyleKeys(props[name], `${String(node.elementId ?? node.name ?? '?')}.${name}`, styleKeys, inlineFields(name));
694
753
  }
695
754
  if (styleKeys.length > 0)
696
755
  missing.push(`stil anahtarları camelCase'e çevrildi: ${styleKeys.join(' · ')}`);
@@ -795,19 +854,31 @@ function normalizeReplacePropValue(op) {
795
854
  }
796
855
  return notes;
797
856
  }
857
+ // connectData sarmalı burada değiştirilmez: gövde duvarı (CD-005, `connectDataOpIssues`) op'u
858
+ // set_connect_data'ya yönlendirerek rejectedOps'a yazar; burada atmak listeyi tek hataya indirirdi.
859
+ if (propType === 'connectData')
860
+ return notes;
798
861
  // Applier her sarmalın tipini korur, ama page/file/flow/widget/element taşıyıcıları başka alanlara
799
862
  // (FlowId, RedirectPageId, dosya) yazılır ve bu op'la bağları kurulmaz. Remove+add önerilmez:
800
863
  // düğümü yeniden kurmak ona yazan setter iteratee'lerinin element'ini siler (G-04, FLOW-018).
801
864
  throw new PlatformApiError(`${label}: '${propType}' tipli Prop replace_prop ile kurulmaz — bu op static, code ve translation sarmalını taşır. Komponenti silip yeniden EKLEMEYİN: ona yazan setter adımlarının hedefi silinir (FLOW-018). Akış bağı için set_event, diğer tipler için page_update(schema) ile tam şema yazın.`, 400);
802
865
  }
803
- export function normalizeSchemaOps(ops) {
866
+ /**
867
+ * `typesByElementId` — TB-129: `replace_prop` op'u yalnız elementId taşır, stil çevirisinin
868
+ * komponent tipine bakabilmesi için haritayı çağıran (okuduğu şemadan) verir. Verilmezse çeviri
869
+ * tip ayrımı yapmaz; bu, harita okunamadığında yazmayı engellememek için bilinçli düşüştür.
870
+ */
871
+ export function normalizeSchemaOps(ops, typesByElementId) {
804
872
  const components = [];
805
873
  const props = [];
806
874
  const validations = [];
807
875
  for (const op of asObjects(ops)) {
808
876
  if (op.op === 'replace_prop') {
809
877
  if (isStylePropName(String(op.prop ?? ''))) {
810
- normalizeStyleKeys(op.value, `'${String(op.target ?? '?')}.${String(op.prop)}'`, props);
878
+ const inline = String(op.prop) === 'style'
879
+ ? inlineStyleFields(typesByElementId?.get(String(op.target ?? '')))
880
+ : undefined;
881
+ normalizeStyleKeys(op.value, `'${String(op.target ?? '?')}.${String(op.prop)}'`, props, inline);
811
882
  }
812
883
  props.push(...normalizeReplacePropValue(op));
813
884
  continue;
@@ -884,11 +955,11 @@ export function pageContainerNode() {
884
955
  * çekilirlerse sayfa içeriğinin akışına girer ve katman olarak açılmazlar.
885
956
  */
886
957
  const ROOT_LAYER_TYPES = new Set(['modal', 'drawer']);
887
- export function ensurePageContainer(schema) {
958
+ export function ensurePageContainer(schema, rootContainer = pageContainerNode) {
888
959
  const nodes = asObjects(schema);
889
960
  if (nodes.some(node => node.elementId === PAGE_CONTAINER_ELEMENT_ID))
890
961
  return { schema: nodes, fixes: [] };
891
- const container = pageContainerNode();
962
+ const container = rootContainer();
892
963
  const layers = nodes.filter(node => ROOT_LAYER_TYPES.has(String(node.type ?? '')));
893
964
  container.children = nodes.filter(node => !ROOT_LAYER_TYPES.has(String(node.type ?? '')));
894
965
  const moved = container.children.length;
@@ -931,7 +1002,7 @@ export function clampBlockSizes(nodes, maxSizes) {
931
1002
  * başlatır (`ComponentHeightType.Fixed = 0`), yani "alan yok" = "sabit yükseklik". Studio'nun
932
1003
  * kendi bırakma yolu bunu ASLA yapmaz: katalogdaki `isDefaultAutoHeight`e bakıp
933
1004
  * `heightType: isDefaultAutoHeight ? 'auto' : 'fixed'` yazar
934
- * (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts:233`). Katalogda varsayılan
1005
+ * (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts` `createDefaultSchemaNode`). Katalogda varsayılan
935
1006
  * `true`'dur (`ZeyrekComponent.ts:62`); `false` diyen yalnız sekiz tip var — auth-layout, html,
936
1007
  * image, layout, qrcode, table, text-editor, video.
937
1008
  *
@@ -1717,19 +1788,18 @@ export function viewAliasNote(fixes) {
1717
1788
  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ü`];
1718
1789
  }
1719
1790
  /**
1720
- * Değişken seti tek bir kayıtta yaşar: `CreateAppVariableCommand`/`CreatePageVariableCommand`
1721
- * yalnız `Data` alanı taşır (Studio uygulama başına ve sayfa başına TEK satır tutar —
1722
- * `IsVariableExistForApplicationAsync` doluysa create update'e döner). Studio'nun gönderdiği şekil
1723
- * `data`'nın **JSON string** olmasıdır: "[{\"key\":\"MyTest\",\"value\":{\"isActive\":true}}]".
1724
- * `Data` tipi `object` olduğu için platform her gövdeyi kabul eder; alan adı tutmayan bir gövde
1725
- * (name/type/defaultValue gibi) `Data`'yı null bırakır ve istek 200 döner ama HİÇBİR ŞEY yazılmaz
1726
- * (17/Ç1). Okuma tarafı da aynı string'i geri verir (`AppVariablesDto.Map` → GetRawText).
1791
+ * `storage` kayıtta isteğe bağlıdır (`docs/adr/0004-state-saklama-turu.md`). Tanınmayan tür ya da
1792
+ * metin olmayan değer çalışma zamanında da yok sayılır (`@ng-apps/ui-native` `variableStorageKinds`);
1793
+ * gateway onu taşımaz ki bir sonraki yazım bozuk değeri kalıcılaştırmasın.
1727
1794
  */
1728
1795
  export function parseVariableEntries(data) {
1729
1796
  const source = typeof data === 'string' ? safeParse(data) : data;
1730
1797
  return asObjects(source)
1731
1798
  .filter(entry => typeof entry.key === 'string' && entry.key !== '')
1732
- .map(entry => ({ key: String(entry.key), value: entry.value }));
1799
+ .map(entry => {
1800
+ const storage = STATE_STORAGE_KINDS.find(kind => kind === entry.storage);
1801
+ return { key: String(entry.key), value: entry.value, ...(storage ? { storage } : {}) };
1802
+ });
1733
1803
  }
1734
1804
  function safeParse(value) {
1735
1805
  try {
@@ -1744,17 +1814,29 @@ function safeParse(value) {
1744
1814
  * mevcut seti okuyup anahtar bazında birleştirir; `replace: true` verilirse bilinçli olarak ezer.
1745
1815
  */
1746
1816
  export function mergeVariableEntries(existing, incoming, replace) {
1817
+ const stored = (entry, current) => {
1818
+ const storage = entry.storage === undefined ? current?.storage : STATE_STORAGE_KINDS.find(kind => kind === entry.storage);
1819
+ const value = entry.value === undefined ? (current ? current.value : null) : entry.value;
1820
+ return { key: entry.key, value, ...(storage ? { storage } : {}) };
1821
+ };
1747
1822
  if (replace)
1748
- return { entries: incoming, fixes: [] };
1823
+ return { entries: incoming.map(entry => stored(entry)), fixes: [] };
1749
1824
  const merged = [...existing];
1750
1825
  const kept = [];
1826
+ const keptStorage = [];
1827
+ const keptValue = [];
1751
1828
  for (const entry of incoming) {
1752
1829
  const index = merged.findIndex(current => current.key === entry.key);
1753
1830
  if (index === -1) {
1754
- merged.push(entry);
1831
+ merged.push(stored(entry));
1755
1832
  continue;
1756
1833
  }
1757
- merged[index] = entry;
1834
+ const current = merged[index];
1835
+ if (entry.storage === undefined && current?.storage)
1836
+ keptStorage.push(`'${entry.key}' → ${current.storage}`);
1837
+ if (entry.value === undefined)
1838
+ keptValue.push(`'${entry.key}'`);
1839
+ merged[index] = stored(entry, current);
1758
1840
  }
1759
1841
  for (const entry of existing) {
1760
1842
  if (!incoming.some(current => current.key === entry.key))
@@ -1762,9 +1844,17 @@ export function mergeVariableEntries(existing, incoming, replace) {
1762
1844
  }
1763
1845
  return {
1764
1846
  entries: merged,
1765
- fixes: kept.length > 0
1766
- ? [`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`]
1767
- : []
1847
+ fixes: [
1848
+ ...(kept.length > 0
1849
+ ? [`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`]
1850
+ : []),
1851
+ ...(keptStorage.length > 0
1852
+ ? [`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`]
1853
+ : []),
1854
+ ...(keptValue.length > 0
1855
+ ? [`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`]
1856
+ : [])
1857
+ ]
1768
1858
  };
1769
1859
  }
1770
1860
  export function blockSizeNote(clamped) {
@@ -1845,12 +1935,22 @@ export function nestedRepeaterNodes(nodes) {
1845
1935
  walk(asObjects(nodes), false);
1846
1936
  return found;
1847
1937
  }
1848
- export function nestedRepeaterMessage(ids) {
1849
- return `PAGE-013 — repeater içinde repeater (istek gönderilmedi): ${ids.join(' · ')}. `
1938
+ /**
1939
+ * Mobil profilde gruplu listenin (gün/kategori başlığı altında satırlar) hazır bileşeni vardır:
1940
+ * `grouped-list` (ui-native, ADR 0007). Web'de karşılığı yok — web mesajı textarea tarifinde kalır.
1941
+ */
1942
+ export function nestedRepeaterMessage(ids, platform = 'web') {
1943
+ const measured = `PAGE-013 — repeater içinde repeater (istek gönderilmedi): ${ids.join(' · ')}. `
1850
1944
  + 'Ölçüldü (2026-08-19): iç repeater OKUMADA çalışır ama girilen değer dış satıra GERİ YAZILMAZ '
1851
1945
  + '(_repeaterValues null kalır) ve tek düzenlemeden sonra DOM bozulur. Sebep yapısal: şemada iç '
1852
- + 'repeater tek düğümdür, dış satır başına ayrı düğüm yoktur. Satır içi listeyi tek bir textarea '
1853
- + "ile topla (satır başına bir öğe) ve kaydederken split('\n') ile böl — platform_guide('page') Kural 1g.";
1946
+ + 'repeater tek düğümdür, dış satır başına ayrı düğüm yoktur. ';
1947
+ 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.";
1948
+ if (platform !== 'mobile')
1949
+ return measured + textarea;
1950
+ return measured
1951
+ + 'Başlıklar altında gruplanmış liste (güne/kategoriye göre) için mobilde tek `grouped-list` kur: düz `rows` + '
1952
+ + '`groupBy` alan yolu; çocuk 0 bölüm başlığı (`{{ Section.title }}`), çocuk 1 öğe şablonu (`Row`, `{{ item.<alan> }}`) — '
1953
+ + "platform_guide('mobile') §Güne göre görev listesi. Satır içinde düzenlenen alt liste gerekiyorsa: " + textarea;
1854
1954
  }
1855
1955
  /**
1856
1956
  * `style` prop'u düz CSS STRING verilmiş düğümler. Çalışır (emotion string'i CSS metni sayar) ama
@@ -1864,7 +1964,7 @@ export function stringStyleNodes(nodes) {
1864
1964
  for (const node of list) {
1865
1965
  const props = (node.props ?? {});
1866
1966
  const style = props.style;
1867
- if (style && typeof style.data === 'string' && style.data.includes(':')) {
1967
+ if (style && typeof style.data === 'string' && style.data.includes(':') && !DOCUMENT_STYLE_TYPES.has(String(node.type))) {
1868
1968
  found.push(String(node.elementId ?? node.name ?? '?'));
1869
1969
  }
1870
1970
  walk(asObjects(node.children));
@@ -1995,6 +2095,95 @@ export function flowBindings(schema, hostEvents) {
1995
2095
  visitNode(node);
1996
2096
  return bindings;
1997
2097
  }
2098
+ /**
2099
+ * TB-125 — op listesi UYGULANDIKTAN sonra şemada (ve düzey olaylarında) hâlâ referanslı olan
2100
+ * akışlar. Simülasyon yalnız akış referansını umursar: eklenen düğüm ağacın köküne konur (konum
2101
+ * sayıma girmez), silinen düğüm ağaçtan çıkarılır, olay op'ları olay dizisini günceller.
2102
+ * `batch` op'u iç listesiyle düzleştirilir.
2103
+ */
2104
+ function survivingFlowRefs(nodes, hostEvents, ops) {
2105
+ const simulated = structuredClone(nodes);
2106
+ const simulatedHostEvents = structuredClone(hostEvents);
2107
+ const removeNode = (list, target) => {
2108
+ const index = list.findIndex(node => node.elementId === target);
2109
+ if (index >= 0) {
2110
+ list.splice(index, 1);
2111
+ return true;
2112
+ }
2113
+ for (const node of list) {
2114
+ if (Array.isArray(node.children) && removeNode(node.children, target))
2115
+ return true;
2116
+ }
2117
+ return false;
2118
+ };
2119
+ const eventsOf = (target) => {
2120
+ if (target === 'page')
2121
+ return simulatedHostEvents;
2122
+ const node = findNodeByElementId(simulated, target);
2123
+ if (!node)
2124
+ return undefined;
2125
+ if (!Array.isArray(node.events))
2126
+ node.events = [];
2127
+ return node.events;
2128
+ };
2129
+ const apply = (op) => {
2130
+ if (op.op === 'batch') {
2131
+ for (const inner of asObjects(op.ops))
2132
+ apply(inner);
2133
+ return;
2134
+ }
2135
+ if (op.op === 'add_component' && op.component && typeof op.component === 'object') {
2136
+ simulated.push(structuredClone(op.component));
2137
+ return;
2138
+ }
2139
+ const target = String(op.target ?? '');
2140
+ if (target === '')
2141
+ return;
2142
+ if (op.op === 'remove_component') {
2143
+ removeNode(simulated, target);
2144
+ return;
2145
+ }
2146
+ if (op.op !== 'set_event' && op.op !== 'add_event' && op.op !== 'remove_event')
2147
+ return;
2148
+ const events = eventsOf(target);
2149
+ if (events === undefined)
2150
+ return;
2151
+ const eventName = String(op.event ?? '');
2152
+ const eventValue = typeof op.eventValue === 'string' ? op.eventValue : undefined;
2153
+ const named = events.filter(event => String(event.name ?? '') === eventName && typeof event.value === 'string' && event.value !== '');
2154
+ if (op.op === 'add_event') {
2155
+ if (eventValue !== undefined)
2156
+ events.push({ name: eventName, value: eventValue });
2157
+ return;
2158
+ }
2159
+ if (op.op === 'set_event') {
2160
+ // set_event adın BÜTÜN bağlarını tek kayda indirir.
2161
+ for (const event of named)
2162
+ events.splice(events.indexOf(event), 1);
2163
+ if (eventValue !== undefined)
2164
+ events.push({ name: eventName, value: eventValue });
2165
+ return;
2166
+ }
2167
+ // Değersiz remove_event çoklu bağda platformda ambiguous-event ile düşer: hiçbir bağ kalkmaz.
2168
+ const removed = eventValue === undefined
2169
+ ? (named.length === 1 ? named : [])
2170
+ : named.filter(event => event.value === eventValue);
2171
+ for (const event of removed)
2172
+ events.splice(events.indexOf(event), 1);
2173
+ };
2174
+ for (const op of ops)
2175
+ apply(op);
2176
+ const surviving = new Set();
2177
+ for (const event of simulatedHostEvents) {
2178
+ if (typeof event.value === 'string')
2179
+ surviving.add(event.value);
2180
+ }
2181
+ for (const node of simulated) {
2182
+ for (const flowId of collectFlowRefs(node))
2183
+ surviving.add(flowId);
2184
+ }
2185
+ return surviving;
2186
+ }
1998
2187
  /**
1999
2188
  * Bir yamanın SİLECEĞİ akışlar. Platform referanssız kalan akışı KALICI siler; uyarı yamadan sonra
2000
2189
  * geldiğinde "önce yedekle" tavsiyesi uygulanamaz hâle geliyordu (09-05 koşusu: sekiz adımlı giriş
@@ -2003,26 +2192,15 @@ export function flowBindings(schema, hostEvents) {
2003
2192
  */
2004
2193
  export function orphanedFlowPlan(schema, pageEvents, ops) {
2005
2194
  const nodes = asObjects(schema);
2006
- const opList = asObjects(ops);
2195
+ // `batch` açılır: içindeki silme de plana girer (kapı yalnız üst düzeye bakınca batch'teki
2196
+ // `remove_component` akışı uyarısız siliyordu).
2197
+ const opList = asObjects(ops).flatMap(op => op.op === 'batch' ? asObjects(op.ops) : [op]);
2007
2198
  const plan = [];
2008
- const survivingRefs = (skipElementId, skipEvent) => {
2009
- const surviving = new Set();
2010
- for (const event of asObjects(pageEvents)) {
2011
- if (typeof event.value === 'string')
2012
- surviving.add(event.value);
2013
- }
2014
- collectFlowRefsExcept(nodes, skipElementId, surviving);
2015
- if (skipEvent !== undefined) {
2016
- const node = findNodeByElementId(nodes, skipElementId);
2017
- for (const event of asObjects(node?.events)) {
2018
- if (String(event.name ?? '') !== skipEvent && typeof event.value === 'string')
2019
- surviving.add(event.value);
2020
- }
2021
- for (const flowId of collectFlowRefs({ ...(node ?? {}), events: [] }))
2022
- surviving.add(flowId);
2023
- }
2024
- return surviving;
2025
- };
2199
+ // TB-125 — hayatta kalan referanslar yamanın SONUCUNDAN okunur, op op özgün ağaçtan değil. Eski
2200
+ // hesap her op'a tek başına baktığı için aynı yamada başka bir düğüme bağlanan akışı da
2201
+ // "referanssız" sayıyor ve düğüm taşıyan her yamayı ikiye böldürüyordu (S2-35). İstek atomik
2202
+ // olduğuna göre doğru soru tektir: yama bittiğinde bu akışa referans kalıyor mu?
2203
+ const surviving = survivingFlowRefs(nodes, asObjects(pageEvents), opList);
2026
2204
  for (const op of opList) {
2027
2205
  const target = String(op.target ?? '');
2028
2206
  if (target === '')
@@ -2032,7 +2210,6 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
2032
2210
  if (!doomed)
2033
2211
  continue;
2034
2212
  const losing = collectFlowRefs(doomed);
2035
- const surviving = survivingRefs(target);
2036
2213
  const orphaned = [...losing].filter(flowId => !surviving.has(flowId));
2037
2214
  if (orphaned.length > 0)
2038
2215
  plan.push({ target, op: 'remove_component', flowIds: orphaned });
@@ -2054,10 +2231,7 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
2054
2231
  // oraya bağlı akış kapıdan geçip kalıcı silinirdi. Düzey olayı olmayan widget'ta applier da
2055
2232
  // düğüm aramasına düşer.
2056
2233
  if (op.op === 'remove_event' && target === 'page' && Array.isArray(pageEvents)) {
2057
- const hostEvents = asObjects(pageEvents);
2058
- const removed = removedBy(boundTo(hostEvents));
2059
- const surviving = new Set(hostEvents.filter(event => !removed.includes(event) && typeof event.value === 'string').map(event => String(event.value)));
2060
- collectFlowRefsExcept(nodes, '', surviving);
2234
+ const removed = removedBy(boundTo(asObjects(pageEvents)));
2061
2235
  const flowIds = [...new Set(removed.map(event => String(event.value)))].filter(flowId => !surviving.has(flowId));
2062
2236
  if (flowIds.length > 0)
2063
2237
  plan.push({ target, op: 'remove_event', flowIds });
@@ -2069,11 +2243,6 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
2069
2243
  const losing = op.op === 'set_event' ? named.filter(event => event.value !== eventValue) : removedBy(named);
2070
2244
  if (losing.length === 0)
2071
2245
  continue;
2072
- const surviving = survivingRefs(target, eventName);
2073
- for (const event of named) {
2074
- if (!losing.includes(event))
2075
- surviving.add(String(event.value));
2076
- }
2077
2246
  const flowIds = [...new Set(losing.map(event => String(event.value)))].filter(flowId => !surviving.has(flowId));
2078
2247
  if (flowIds.length > 0)
2079
2248
  plan.push({ target, op: String(op.op), flowIds });
@@ -357,3 +357,39 @@ export function functionOutline(definition) {
357
357
  view: 'outline'
358
358
  };
359
359
  }
360
+ export function processOutline(payload) {
361
+ const model = (payload.definition && typeof payload.definition === 'object' ? payload.definition : payload);
362
+ const describeAssignee = (value) => {
363
+ if (!value || typeof value !== 'object' || Array.isArray(value))
364
+ return value ?? null;
365
+ const assignee = value;
366
+ const rule = [assignee.rule, assignee.arg].filter(part => part !== undefined && part !== null).join(':');
367
+ return assignee.of ? `${rule} of ${String(assignee.of)}` : rule;
368
+ };
369
+ const describeNodes = (nodes, depth) => asArray(nodes).flatMap(node => [{
370
+ id: node.id,
371
+ type: node.type,
372
+ depth,
373
+ editable: node.editable ?? 'locked',
374
+ description: node.description ?? null,
375
+ assignee: describeAssignee(node.assignee ?? node.to),
376
+ policy: node.policy ?? null,
377
+ sla: Array.isArray(node.sla) ? asArray(node.sla).map(sla => sla.duration) : node.sla ?? null,
378
+ on: asArray(node.on).map(handler => `${String(handler.event)} → ${String(handler.handler?.type ?? '?')}${handler.afterHandlers ? ` (${String(handler.afterHandlers)})` : ''}`)
379
+ }, ...describeNodes(node.nodes, depth + 1)]);
380
+ const nodes = describeNodes(model.nodes, 0);
381
+ return {
382
+ id: payload.id ?? null,
383
+ slug: model.slug ?? payload.slug,
384
+ name: model.name ?? payload.name,
385
+ version: payload.version ?? null,
386
+ activeVersionId: payload.activeVersionId ?? null,
387
+ versions: asArray(payload.versions).map(version => ({ number: version.number, state: version.state })),
388
+ nodeCount: nodes.length,
389
+ nodes,
390
+ edgeCount: asArray(model.edges).length,
391
+ on: asArray(model.on).map(handler => String(handler.event)),
392
+ view: 'outline',
393
+ hint: "Tek düğüm için process_definition_get view:'part', part:'definition.nodes[id=<düğüm>]'; değişiklik için process_definition_patch (yol /nodes[id=<düğüm>]/…)."
394
+ };
395
+ }