@appaflytech/zeyrek-ai-mcp 0.0.32 → 0.0.33

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 (167) hide show
  1. package/.env.example +15 -0
  2. package/dist/config.js +11 -0
  3. package/dist/index.js +2 -0
  4. package/dist/knowledge/access.js +802 -0
  5. package/dist/knowledge/case.js +41 -0
  6. package/dist/knowledge/componentCatalog.js +82 -213
  7. package/dist/knowledge/componentEvents.js +21 -19
  8. package/dist/knowledge/connectDataBind.js +819 -0
  9. package/dist/knowledge/connectDataDefinition.js +341 -0
  10. package/dist/knowledge/connectDataExecute.js +93 -0
  11. package/dist/knowledge/connectDataRules.js +128 -0
  12. package/dist/knowledge/decision.js +121 -0
  13. package/dist/knowledge/expressionPrelude.js +59 -0
  14. package/dist/knowledge/layoutSummary.js +140 -2
  15. package/dist/knowledge/microserviceParameters.js +58 -0
  16. package/dist/knowledge/mining.js +94 -0
  17. package/dist/knowledge/mobileComponentCatalog.js +864 -0
  18. package/dist/knowledge/mobileComponentEvents.js +239 -0
  19. package/dist/knowledge/mobileStore.js +227 -0
  20. package/dist/knowledge/normalize.js +121 -35
  21. package/dist/knowledge/platform/lint.js +385 -0
  22. package/dist/knowledge/platform/mobile.js +142 -0
  23. package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
  24. package/dist/knowledge/platform/mobileRules.js +231 -0
  25. package/dist/knowledge/platform/mobileSpacing.js +82 -0
  26. package/dist/knowledge/platform/mobileTabs.js +108 -0
  27. package/dist/knowledge/platform/nativeBoxModel.js +44 -0
  28. package/dist/knowledge/platform/profile.js +25 -0
  29. package/dist/knowledge/platform/resolve.js +122 -0
  30. package/dist/knowledge/platform/web.js +39 -0
  31. package/dist/knowledge/process.js +510 -0
  32. package/dist/knowledge/rowFilter.js +43 -0
  33. package/dist/knowledge/rules.js +291 -19
  34. package/dist/knowledge/styleResolve.js +55 -38
  35. package/dist/knowledge/styleResolveNative.js +527 -0
  36. package/dist/knowledge/themeResolve.js +3 -3
  37. package/dist/observability/trace.js +1 -1
  38. package/dist/platform/argumentAliases.js +128 -0
  39. package/dist/platform/bodyFile.js +103 -0
  40. package/dist/platform/capture/actions.js +333 -0
  41. package/dist/platform/capture/browser.js +1 -0
  42. package/dist/platform/{screenshot.js → capture/capture.js} +81 -519
  43. package/dist/platform/capture/console-log.js +122 -0
  44. package/dist/platform/capture/index.js +11 -0
  45. package/dist/platform/capture/readiness.js +103 -0
  46. package/dist/platform/capture/summary.js +77 -0
  47. package/dist/platform/capture/target.js +5 -0
  48. package/dist/platform/capture/targets/studio-mobile.js +15 -0
  49. package/dist/platform/capture/targets/studio-web.js +5 -0
  50. package/dist/platform/diagnostics.js +10 -4
  51. package/dist/platform/domSummary.js +1 -1
  52. package/dist/platform/http.js +23 -7
  53. package/dist/platform/impersonation.js +45 -0
  54. package/dist/platform/jsonArray.js +24 -0
  55. package/dist/platform/responses.js +6 -2
  56. package/dist/platform/schemaReadMemory.js +60 -0
  57. package/dist/platform/secrets.js +9 -0
  58. package/dist/platform/strictArguments.js +68 -12
  59. package/dist/platform/tokenVault.js +187 -4
  60. package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
  61. package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
  62. package/dist/resources/examples/bpm-satinalma.json +376 -0
  63. package/dist/resources/examples/connect-data-convert-verify.json +107 -0
  64. package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
  65. package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
  66. package/dist/resources/examples/connect-data-query-params.json +50 -0
  67. package/dist/resources/examples/connect-data-table-entity.json +147 -0
  68. package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
  69. package/dist/resources/examples/layout-app-shell.json +229 -707
  70. package/dist/resources/examples/mobile-app-shell-drawer.json +244 -0
  71. package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
  72. package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
  73. package/dist/resources/examples/mobile-form-screen.json +365 -0
  74. package/dist/resources/examples/mobile-list-detail-form.json +703 -0
  75. package/dist/resources/examples/page-flex-sections.json +1 -1
  76. package/dist/resources/guides/access.md +796 -0
  77. package/dist/resources/guides/bpm.md +686 -0
  78. package/dist/resources/guides/case.md +153 -0
  79. package/dist/resources/guides/component.md +10 -2
  80. package/dist/resources/guides/decision.md +185 -0
  81. package/dist/resources/guides/expressions.md +14 -5
  82. package/dist/resources/guides/functions.md +1 -1
  83. package/dist/resources/guides/layout.md +55 -58
  84. package/dist/resources/guides/microservice.md +9 -2
  85. package/dist/resources/guides/middleware.md +34 -2
  86. package/dist/resources/guides/mobile-layout.md +193 -0
  87. package/dist/resources/guides/mobile.md +578 -0
  88. package/dist/resources/guides/page.md +221 -92
  89. package/dist/resources/guides/theme.md +8 -2
  90. package/dist/resources/guides/translation.md +1 -1
  91. package/dist/resources/guides/workflow.md +7 -1
  92. package/dist/resources/read.js +41 -0
  93. package/dist/resources/schema-fingerprint.json +4 -4
  94. package/dist/resources/schemas/AccessExplanationDto.json +144 -0
  95. package/dist/resources/schemas/AccessMatrixDto.json +170 -0
  96. package/dist/resources/schemas/AccessPermissionDto.json +57 -0
  97. package/dist/resources/schemas/AccessPolicyDto.json +223 -0
  98. package/dist/resources/schemas/AccessResourceDto.json +86 -0
  99. package/dist/resources/schemas/AppSessionDto.json +53 -0
  100. package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
  101. package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
  102. package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
  103. package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
  104. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
  105. package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
  106. package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
  107. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
  108. package/dist/resources/schemas/DecisionDto.json +302 -0
  109. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
  110. package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
  111. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
  112. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +3 -1
  113. package/dist/resources/schemas/MicroserviceDto.json +2 -2
  114. package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
  115. package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
  116. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
  117. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
  118. package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
  119. package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
  120. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
  121. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
  122. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
  123. package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
  124. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
  125. package/dist/resources/schemas/StartMobileBuildCommand.json +54 -0
  126. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
  127. package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
  128. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
  129. package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +259 -0
  130. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
  131. package/dist/server.js +7 -1
  132. package/dist/tools/accessOperations.js +135 -0
  133. package/dist/tools/accessPolicies.js +170 -0
  134. package/dist/tools/accessRuntime.js +203 -0
  135. package/dist/tools/applications.js +60 -3
  136. package/dist/tools/bpm.js +343 -0
  137. package/dist/tools/bpmGovernance.js +266 -0
  138. package/dist/tools/bpmOperations.js +230 -0
  139. package/dist/tools/bpmReporting.js +154 -0
  140. package/dist/tools/bpmRouting.js +150 -0
  141. package/dist/tools/bpmRuntime.js +396 -0
  142. package/dist/tools/case.js +178 -0
  143. package/dist/tools/caseRuntime.js +89 -0
  144. package/dist/tools/components.js +103 -12
  145. package/dist/tools/connectData.js +449 -0
  146. package/dist/tools/connectors.js +193 -0
  147. package/dist/tools/datasources.js +1 -1
  148. package/dist/tools/decisions.js +206 -0
  149. package/dist/tools/designSchemaPatch.js +22 -16
  150. package/dist/tools/externalComponents.js +25 -4
  151. package/dist/tools/flows.js +79 -6
  152. package/dist/tools/layouts.js +44 -12
  153. package/dist/tools/microservices.js +32 -10
  154. package/dist/tools/mobile.js +221 -0
  155. package/dist/tools/mobileStore.js +268 -0
  156. package/dist/tools/modules.js +48 -0
  157. package/dist/tools/organizationStructure.js +137 -0
  158. package/dist/tools/pages.js +391 -92
  159. package/dist/tools/platformInfo.js +7 -2
  160. package/dist/tools/profileWrite.js +92 -0
  161. package/dist/tools/rows.js +7 -1
  162. package/dist/tools/schemaOps.js +33 -1
  163. package/dist/tools/screenWrite.js +15 -7
  164. package/dist/tools/screens.js +90 -3
  165. package/dist/tools/variables.js +11 -5
  166. package/package.json +2 -2
  167. package/dist/knowledge/boxSections.js +0 -184
@@ -0,0 +1,89 @@
1
+ import { guid, projectParam, environmentParam, pagingParams, readOnly, writes } from './common.js';
2
+ import { identityHeaders } from '../platform/tokenVault.js';
3
+ import { PlatformApiError } from '../platform/errors.js';
4
+ import { assertProcessNotProduction } from './bpm.js';
5
+ import { handle } from '../platform/responses.js';
6
+ import { z } from 'zod';
7
+ const asUserParam = z.string().min(1).optional()
8
+ .describe("Uygulama kullanıcısının kimliği (ham JWT ya da access_session_create'in tokenRefs'teki tok_… referansı). Vaka başlatan ve plan öğesini değiştiren bu kişi olur; verilmezse gateway'in kendi kullanıcısı.");
9
+ const expectFailureParam = z.boolean().optional()
10
+ .describe('true: bu çağrıda hata BEKLENİYOR (kasıtlı negatif test: sentry sağlanmadan enable 422). Ölçüm plansız hata saymaz.');
11
+ const planItemOperations = ['enable', 'start', 'complete', 'disable'];
12
+ const caseInstanceOperations = [...planItemOperations, 'add-discretionary', 'update-case-file'];
13
+ export function registerCaseRuntimeTools(server, platform) {
14
+ const config = platform.config;
15
+ server.registerTool('case_execute', {
16
+ title: 'Vaka başlat',
17
+ description: "Yayındaki vaka tanımından vaka başlatır (POST bpm/cases/{slug}/start): subjectRowId iş satırı, caseFile başlangıç değerleri (tanımdaki varsayılanların üstüne yazılır). Yanıt vaka + planItems + availableActions. process.start izni ister. İnsan görevleri görev kutusuna kind 'case-task' olarak düşer ve process_task_update ile tamamlanır. production hedefi durur (BPM-001).",
18
+ inputSchema: {
19
+ project: projectParam,
20
+ environment: environmentParam,
21
+ slug: z.string().min(1).max(100),
22
+ applicationId: guid.optional(),
23
+ subjectRowId: z.string().max(64).optional(),
24
+ caseFile: z.record(z.unknown()).optional().describe('vaka dosyası öğe id → değer'),
25
+ asUser: asUserParam
26
+ },
27
+ annotations: writes
28
+ }, handle(config, async ({ project, environment, slug, applicationId, subjectRowId, caseFile, asUser }) => {
29
+ assertProcessNotProduction('case_execute', environment, config);
30
+ return platform.tenant('POST', project, `/bpm/cases/${encodeURIComponent(slug)}/start`, {
31
+ environment,
32
+ body: { applicationId, subjectRowId, caseFile },
33
+ headers: identityHeaders(asUser, undefined, undefined)
34
+ });
35
+ }));
36
+ server.registerTool('case_instance_list', {
37
+ title: 'Vakaları listele',
38
+ description: "Vakaları listeler (GET bpm/case-instances; process.view-all ister): definitionId ve state (active | completed | terminated) süzgeci. Tek vakanın plan öğeleri, defteri ve availableActions için case_instance_get.",
39
+ inputSchema: {
40
+ project: projectParam,
41
+ environment: environmentParam,
42
+ definitionId: guid.optional(),
43
+ state: z.enum(['active', 'completed', 'terminated']).optional(),
44
+ ...pagingParams
45
+ },
46
+ annotations: readOnly
47
+ }, handle(config, ({ project, environment, ...query }) => platform.tenant('GET', project, '/bpm/case-instances', { environment, query })));
48
+ server.registerTool('case_instance_get', {
49
+ title: 'Vakayı getir',
50
+ description: "Vakayı getirir (GET bpm/case-instances/{id}): state, caseFile, planItems[] (id — eylemlerdeki planItemId budur —, itemId, type, state, occurrence, taskId), events[] (vaka defteri) ve availableActions[] { action: start | complete | disable | discretionary, itemId, planItemId }. Katılımcı (başlatan, atanan, tamamlayan) ya da process.view-all görür. case_instance_update'ten önce okuyun: planItemId planItems[].id ya da availableActions[].planItemId'dir.",
51
+ inputSchema: { project: projectParam, environment: environmentParam, id: guid, asUser: asUserParam },
52
+ annotations: readOnly
53
+ }, handle(config, ({ project, environment, id, asUser }) => platform.tenant('GET', project, `/bpm/case-instances/${id}`, { environment, headers: identityHeaders(asUser, undefined, undefined) })));
54
+ server.registerTool('case_instance_update', {
55
+ title: 'Vakada plan öğesi eylemi',
56
+ description: "Vaka eylemlerinin tek kapısı: operation enable | start | complete | disable (planItemId ZORUNLU: case_instance_get planItems[].id ya da availableActions[].planItemId — enable availableActions'ta hiç yoktur, kimliği planItems[].id'den okuyun; POST …/plan-items/{planItemId}/{operation}) | add-discretionary (itemDefinitionId: isteğe bağlı plan öğesinin tanımdaki id'si; POST …/discretionary) | update-case-file (itemId ve value ZORUNLU, silmek için value: null; PUT …/case-file — yerleşimi yeniden çalıştırır, ifPart'lar yeniden değerlendirilir). Hatalar: giriş sentry'si sağlanmadan enable 422 CaseSentryNotSatisfied (lint değil, çalışma zamanı: availableActions enable listelemez); yanlış durumdaki öğe ya da kapanmış vaka 409 InstanceStateTransitionNotAllowed; human-task görev ucundan (process_task_update) tamamlanır. production hedefi durur (BPM-001).",
57
+ inputSchema: {
58
+ project: projectParam,
59
+ environment: environmentParam,
60
+ id: guid,
61
+ operation: z.enum(caseInstanceOperations),
62
+ planItemId: guid.optional().describe('enable | start | complete | disable için case_instance_get planItems[].id (ya da availableActions[].planItemId)'),
63
+ itemDefinitionId: z.string().max(100).optional().describe('add-discretionary için tanımdaki plan öğesi id'),
64
+ itemId: z.string().max(100).optional().describe('update-case-file için vaka dosyası öğe id'),
65
+ value: z.unknown().optional().describe('update-case-file için yeni değer (herhangi bir JSON)'),
66
+ asUser: asUserParam,
67
+ expectFailure: expectFailureParam
68
+ },
69
+ annotations: writes
70
+ }, handle(config, async ({ project, environment, id, operation, planItemId, itemDefinitionId, itemId, value, asUser }) => {
71
+ assertProcessNotProduction('case_instance_update', environment, config);
72
+ const headers = identityHeaders(asUser, undefined, undefined);
73
+ if (operation === 'add-discretionary') {
74
+ if (!itemDefinitionId)
75
+ throw new PlatformApiError("case_instance_update: 'add-discretionary' itemDefinitionId ister (istek gönderilmedi).", 400);
76
+ return platform.tenant('POST', project, `/bpm/case-instances/${id}/discretionary`, { environment, body: { itemDefinitionId }, headers });
77
+ }
78
+ if (operation === 'update-case-file') {
79
+ if (!itemId)
80
+ throw new PlatformApiError("case_instance_update: 'update-case-file' itemId ister (istek gönderilmedi).", 400);
81
+ if (value === undefined)
82
+ throw new PlatformApiError("case_instance_update: 'update-case-file' value ister — verilmeyen değer öğeyi siler; silmek istiyorsanız value: null gönderin (istek gönderilmedi).", 400);
83
+ return platform.tenant('PUT', project, `/bpm/case-instances/${id}/case-file`, { environment, body: { itemId, value }, headers });
84
+ }
85
+ if (!planItemId)
86
+ throw new PlatformApiError(`case_instance_update: '${operation}' planItemId ister — case_instance_get planItems[].id ya da availableActions[].planItemId (istek gönderilmedi).`, 400);
87
+ return platform.tenant('POST', project, `/bpm/case-instances/${id}/plan-items/${planItemId}/${operation}`, { environment, headers });
88
+ }));
89
+ }
@@ -1,25 +1,81 @@
1
1
  import { guid, projectParam, environmentParam, readOnly, writes, updates, destructive } from './common.js';
2
- import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, withNormalization } from '../knowledge/normalize.js';
2
+ import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, normalizeDroppableStates, withNormalization } from '../knowledge/normalize.js';
3
3
  import { eventContractsFor, eventPayloadNote } from '../knowledge/componentEvents.js';
4
4
  import { componentPresetDefaults, readProjectTheme } from '../knowledge/themeSchema.js';
5
5
  import { knowledgeFor, knowledgeNote, APPEARANCE_TOKEN_SETS, STATE_FLAG_NOTES, INTERNAL_ROLES_BY_TYPE } from '../knowledge/componentCatalog.js';
6
+ import { MOBILE_STATE_FLAG_NOTES, mobileComponentKnowledge } from '../knowledge/mobileComponentCatalog.js';
7
+ import { mobileComponentEventContracts } from '../knowledge/mobileComponentEvents.js';
6
8
  import { componentUpdateBody, fetchHost, schemaParam, unwrap } from './screens.js';
7
9
  import { PlatformApiError } from '../platform/errors.js';
8
10
  import { handle } from '../platform/responses.js';
11
+ import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
12
+ import { mobileComponentNotes } from '../knowledge/platform/mobileRules.js';
13
+ import { randomUUID } from 'node:crypto';
9
14
  import { z } from 'zod';
10
- const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform; varsayılan web');
15
+ const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform (ComponentType); verilmezse uygulamanın tipi — mobil uygulamada mobile');
11
16
  const kindParam = z.enum(['component', 'widget']).optional()
12
17
  .describe("component: sayfaya konan tekil eleman. widget: kendi şeması olan kapsayıcı (container/modal/drawer)");
13
18
  const widgetTypeParam = z.enum(['container', 'modal', 'drawer']).optional()
14
19
  .describe("kind:'widget' iken zorunlu");
20
+ /**
21
+ * Uç `type` verilmezse WEB kataloğunu döner (`GetComponentsQuery` `Type ?? Web`); mobil uygulamanın
22
+ * paleti, doğrulayıcısı ve widget'ları `type=mobile` satırlarıdır. Profil mobil derse sorgu tipi
23
+ * taşır; web'de sorgu profil öncesiyle aynıdır (G1 kilidi).
24
+ */
15
25
  async function listComponents(platform, project, environment, applicationId, scope) {
16
26
  const path = scope === 'all' ? `/components/${applicationId}/all` : `/components/${applicationId}`;
27
+ const catalogType = scope === 'all' ? 'web' : (await resolveProfile(platform, applicationId)).profile.catalogType;
17
28
  const response = await platform.tenant('GET', project, path, {
18
29
  environment,
19
- query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999 }
30
+ query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999, ...(catalogType === 'mobile' ? { type: 'mobile' } : {}) }
20
31
  });
21
32
  return response?.data ?? [];
22
33
  }
34
+ /**
35
+ * CMP-002 (ARC-081) — runtime widget'ın kökünü yalnız `widget-area` (container) ya da `modal`/`drawer`
36
+ * tipinden tanır (`runtime-compose.ts` `getRuntimeWidgetRootNode`); düz `container` kökle kaydedilen
37
+ * widget her yüzeyde boş çizilir. Tipli kök yoksa düğümler Studio'nun `createWidgetRootNode`'u
38
+ * (`widget.functions.ts`) ile aynı şekilde bir köke sarılır: prop'lar uygulamanın kataloğundaki kök
39
+ * tipinin `definition.defaults`'ı, yükseklik `fixed`, kök bırakılabilir.
40
+ */
41
+ function wrapWidgetRoot(schema, widgetType, components) {
42
+ const rootType = widgetType === 'container' ? 'widget-area' : widgetType;
43
+ // Runtime istenen tipin kökü yoksa öteki tipli köklere de düşer (`legacyRoot()`); tip değiştiren
44
+ // güncellemenin eski kökü ikinci kez sarılmaz.
45
+ const hasRoot = schema.some(node => node?.kind === 'component' && ['widget-area', 'modal', 'drawer'].includes(String(node.type)));
46
+ if (hasRoot)
47
+ return { schema, notes: [] };
48
+ const definition = (components.find(component => component.slug === rootType)?.definition ?? {});
49
+ const desktopBlock = Array.isArray(definition.blocks)
50
+ ? definition.blocks.find(block => block?.breakpoint === 1024)
51
+ : undefined;
52
+ const elementId = `${rootType}${randomUUID().slice(0, 4)}`;
53
+ const root = {
54
+ id: randomUUID(),
55
+ elementId,
56
+ name: widgetType === 'container' ? 'container' : elementId,
57
+ widgetType,
58
+ kind: 'component',
59
+ type: rootType,
60
+ children: schema,
61
+ events: [],
62
+ props: { ...(definition.defaults ?? {}) },
63
+ blocks: desktopBlock ? [{ breakpoint: 1024, size: desktopBlock.size, position: { x: 0, y: 0 } }] : [],
64
+ validations: [],
65
+ appearance: { heightType: 'fixed' },
66
+ states: { isDroppable: true },
67
+ stateBindings: []
68
+ };
69
+ return {
70
+ schema: [root],
71
+ notes: [`CMP-002: widget şemasında '${rootType}' kökü yoktu; ${schema.length} düğüm '${elementId}' köküne sarıldı (Studio'nun kurduğu şekil). Runtime widget'ı yalnız widget-area/modal/drawer kökünden çizer.`]
72
+ };
73
+ }
74
+ /** Uygulamanın kayıtlı bileşen slug'ları (mobil profilin MOB-003 denetimi). */
75
+ export async function fetchCatalogSlugs(platform, project, environment, applicationId) {
76
+ const components = await listComponents(platform, project, environment, applicationId);
77
+ return new Set(components.map(component => String(component.slug ?? '')).filter(slug => slug.length > 0));
78
+ }
23
79
  /**
24
80
  * Yerleşim normalizasyonlarının ikisi de aynı katalog listesinden beslenir; tek okumada
25
81
  * çıkarılır ki yazma yolları fazladan istek atmasın. Uygulamanın kendi sözlüğü okunur
@@ -38,12 +94,17 @@ export async function fetchComponentLayoutRules(platform, project, environment,
38
94
  export function componentLayoutRules(components) {
39
95
  const maxSizes = new Map();
40
96
  const autoHeights = new Map();
97
+ const droppable = new Map();
41
98
  for (const component of components) {
42
99
  const slug = typeof component.slug === 'string' ? component.slug : undefined;
43
100
  if (!slug)
44
101
  continue;
45
102
  if (typeof component.isDefaultAutoHeight === 'boolean')
46
103
  autoHeights.set(slug, component.isDefaultAutoHeight);
104
+ // Kap bilgisi sözlükten gelir; düğümün `states.isDroppable`ı onu izler (Studio paleti de
105
+ // aynı alanı katalogdan yazar). `true` gören tip kap sayılır.
106
+ if (typeof component.isDroppable === 'boolean')
107
+ droppable.set(slug, component.isDroppable);
47
108
  const blocks = (component.definition ?? {}).blocks;
48
109
  if (!Array.isArray(blocks))
49
110
  continue;
@@ -58,7 +119,7 @@ export function componentLayoutRules(components) {
58
119
  });
59
120
  }
60
121
  }
61
- return { maxSizes, autoHeights };
122
+ return { maxSizes, autoHeights, droppable };
62
123
  }
63
124
  /**
64
125
  * Katalog okuması başarısız olsa da yazma isteği gitmeli, ama iki normalizasyonun düşüş davranışı
@@ -69,14 +130,21 @@ export function componentLayoutRules(components) {
69
130
  * varsayılanını (`fixed`, `DesignComponentManagementSchema.cs:24`) kabul etmek demektir; en fazla
70
131
  * sekiz tipte (auth-layout/html/image/layout/qrcode/table/text-editor/video) fazladan yükseklik
71
132
  * üretir, atlamak ise her tipte içerik kırpar.
133
+ * - `states.isDroppable` atlanır — katalog okunamadığında hangi tipin kap olduğu bilinmez ve
134
+ * uydurulmaz; düğüm bugünkü hâliyle yazılır.
72
135
  */
73
136
  export async function applyCatalogLayoutRules(platform, project, environment, applicationId, nodes) {
74
137
  try {
75
138
  const rules = await fetchComponentLayoutRules(platform, project, environment, applicationId);
76
- return { clamped: clampBlockSizes(nodes, rules.maxSizes), heights: normalizeHeightTypes(nodes, rules.autoHeights), sizes: normalizeSizeStrings(nodes) };
139
+ return {
140
+ clamped: clampBlockSizes(nodes, rules.maxSizes),
141
+ heights: normalizeHeightTypes(nodes, rules.autoHeights),
142
+ sizes: normalizeSizeStrings(nodes),
143
+ states: normalizeDroppableStates(nodes, rules.droppable)
144
+ };
77
145
  }
78
146
  catch {
79
- return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes) };
147
+ return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes), states: [] };
80
148
  }
81
149
  }
82
150
  /**
@@ -116,6 +184,7 @@ export function registerComponentTools(server, platform) {
116
184
  }, handle(config, async ({ project, environment, applicationId, scope, includeHidden }) => {
117
185
  const components = await listComponents(platform, project, environment, applicationId, scope);
118
186
  return {
187
+ ...applicationTypeField(await resolveProfile(platform, applicationId)),
119
188
  components: components
120
189
  .filter(component => includeHidden === true || component.isHide !== true)
121
190
  .map(component => ({
@@ -161,6 +230,15 @@ export function registerComponentTools(server, platform) {
161
230
  : [];
162
231
  const componentSlug = typeof component.slug === 'string' ? component.slug : undefined;
163
232
  const knowledge = knowledgeFor(componentSlug);
233
+ // Mobil uygulamada kayıt mobil kataloğun satırıdır (`listComponents` type=mobile); davranış
234
+ // notları web runtime'ından gelir (`knowledge` — mobil şema web sınıfını genişletir), bileşenin
235
+ // mobil farkları `mobileKnowledge`'ta, bütün mobil bileşenlere geçen notlar `mobileNotes`'ta (G4).
236
+ // Web ikizi olmayan bileşende (`app-bar`, `tooltip`…) bilgi yalnız `mobileKnowledge`'tadır; olay
237
+ // yükleri de önce mobil sözlükten okunur (`mobileComponentEvents.ts`).
238
+ const mobile = (await resolveProfile(platform, applicationId)).profile.platform === 'mobile';
239
+ const mobileKnowledge = mobile && componentSlug !== undefined && Object.hasOwn(mobileComponentKnowledge, componentSlug)
240
+ ? mobileComponentKnowledge[componentSlug]
241
+ : undefined;
164
242
  // S-3 — `defaults` HAM katalogdur; Studio'da bırakılan düğüm ise temanın bileşen preseti
165
243
  // kaplanmış katalogdan kurulur (`withThemeComponentDefaults`). Tema okunamazsa (uç düşer,
166
244
  // yetki yoksa) alan yanıta HİÇ girmez: uydurulmuş bir varsayılan yanlış bilgidir.
@@ -177,7 +255,7 @@ export function registerComponentTools(server, platform) {
177
255
  isDroppable: component.isDroppable,
178
256
  props: definition.props,
179
257
  defaults: definition.defaults,
180
- events: eventContractsFor(componentSlug, eventNames),
258
+ events: eventContractsFor(componentSlug, eventNames, mobile ? mobileComponentEventContracts : undefined),
181
259
  eventPayloadNote,
182
260
  ...(knowledge
183
261
  ? {
@@ -188,7 +266,7 @@ export function registerComponentTools(server, platform) {
188
266
  },
189
267
  ...(knowledge.guide ? { guide: knowledge.guide } : {})
190
268
  }
191
- : { knowledgeNote }),
269
+ : mobileKnowledge ? {} : { knowledgeNote }),
192
270
  ...(componentSlug && INTERNAL_ROLES_BY_TYPE[componentSlug]
193
271
  ? {
194
272
  internalRoles: INTERNAL_ROLES_BY_TYPE[componentSlug],
@@ -196,8 +274,9 @@ export function registerComponentTools(server, platform) {
196
274
  }
197
275
  : {}),
198
276
  ...(themeDefaults ? { themeDefaults } : {}),
277
+ ...(mobile ? { platform: 'mobile', ...(mobileKnowledge ? { mobileKnowledge } : {}), mobileNotes: mobileComponentNotes(componentSlug) } : {}),
199
278
  appearanceValues: APPEARANCE_TOKEN_SETS,
200
- stateFlags: STATE_FLAG_NOTES,
279
+ stateFlags: mobile ? { ...STATE_FLAG_NOTES, ...MOBILE_STATE_FLAG_NOTES } : STATE_FLAG_NOTES,
201
280
  validations: definition.validations,
202
281
  sizes: definition.blocks
203
282
  };
@@ -230,21 +309,27 @@ export function registerComponentTools(server, platform) {
230
309
  if (body.kind === 'widget' && !body.widgetType) {
231
310
  throw new PlatformApiError("kind:'widget' için widgetType (container | modal | drawer) zorunludur.");
232
311
  }
312
+ const wrapped = body.kind === 'widget' && body.widgetType && (body.schema ?? []).length > 0
313
+ ? wrapWidgetRoot(body.schema ?? [], body.widgetType, await listComponents(platform, project, environment, applicationId).catch(() => []))
314
+ : { schema: body.schema, notes: [] };
315
+ body.schema = wrapped.schema;
233
316
  const fixed = normalizeComponentDefaults(body.schema);
234
317
  const catalog = (body.schema ?? []).length > 0
235
318
  ? await applyCatalogLayoutRules(platform, project, environment, applicationId, body.schema)
236
319
  : { clamped: [], heights: [], sizes: [] };
320
+ // Mobil uygulamanın widget'ı mobil katalog satırıdır; tip verilmezse uygulamanın tipi.
321
+ const defaultType = body.type ?? (await resolveProfile(platform, applicationId)).profile.catalogType;
237
322
  return platform.tenant('POST', project, `/components/${applicationId}`, {
238
323
  environment,
239
324
  body: {
240
325
  kind: 'component',
241
- type: 'web',
326
+ type: defaultType,
242
327
  categories: [],
243
328
  definition: {},
244
329
  schema: [],
245
330
  ...Object.fromEntries(Object.entries(body).filter(([, value]) => value !== undefined))
246
331
  }
247
- }).then(response => withNormalization(response, [...componentDefaultsNote(fixed), ...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes)]));
332
+ }).then(response => withNormalization(response, [...wrapped.notes, ...componentDefaultsNote(fixed), ...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes)]));
248
333
  }));
249
334
  server.registerTool('component_update', {
250
335
  title: 'Komponent güncelle',
@@ -279,6 +364,12 @@ export function registerComponentTools(server, platform) {
279
364
  ? await fetchHost(platform, 'component', project, environment, applicationId, String(current.id))
280
365
  : current;
281
366
  const overrides = Object.fromEntries(Object.entries(changes).filter(([, value]) => value !== undefined));
367
+ const widgetType = changes.widgetType ?? detailed.widgetType;
368
+ const wrapped = detailed.kind === 'widget' && typeof widgetType === 'string' && changes.schema !== undefined && changes.schema.length > 0
369
+ ? wrapWidgetRoot(changes.schema, widgetType, components)
370
+ : { schema: changes.schema, notes: [] };
371
+ if (overrides.schema !== undefined)
372
+ overrides.schema = wrapped.schema;
282
373
  const fixed = normalizeComponentDefaults(overrides.schema);
283
374
  const rules = componentLayoutRules(components);
284
375
  const clamped = overrides.schema === undefined ? [] : clampBlockSizes(overrides.schema, rules.maxSizes);
@@ -286,7 +377,7 @@ export function registerComponentTools(server, platform) {
286
377
  const sizes = overrides.schema === undefined ? [] : normalizeSizeStrings(overrides.schema);
287
378
  const body = componentUpdateBody({ ...detailed, applicationId }, overrides);
288
379
  await platform.tenant('PUT', project, `/components/${applicationId}/${slug}`, { environment, body });
289
- return withNormalization({ slug, changed: Object.keys(overrides), preserved: { schemaNodes: body.schema.length } }, [...componentDefaultsNote(fixed), ...blockSizeNote(clamped), ...heightTypeNote(heights), ...sizeStringNote(sizes)]);
380
+ return withNormalization({ slug, changed: Object.keys(overrides), preserved: { schemaNodes: body.schema.length } }, [...wrapped.notes, ...componentDefaultsNote(fixed), ...blockSizeNote(clamped), ...heightTypeNote(heights), ...sizeStringNote(sizes)]);
290
381
  }));
291
382
  server.registerTool('component_delete', {
292
383
  title: 'Komponent sil',