@appaflytech/zeyrek-ai-mcp 0.0.30 → 0.0.32
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.
- package/.env.example +0 -15
- package/README.md +5 -5
- package/dist/config.js +0 -37
- package/dist/index.js +0 -2
- package/dist/knowledge/backendConstraints.js +1 -18
- package/dist/knowledge/boxSections.js +184 -0
- package/dist/knowledge/componentCatalog.js +232 -562
- package/dist/knowledge/componentEvents.js +21 -141
- package/dist/knowledge/layoutSummary.js +2 -140
- package/dist/knowledge/normalize.js +67 -236
- package/dist/knowledge/outlines.js +0 -36
- package/dist/knowledge/policy.js +4 -18
- package/dist/knowledge/reservedTables.js +0 -79
- package/dist/knowledge/rules.js +21 -319
- package/dist/knowledge/schemaGuard.js +0 -11
- package/dist/knowledge/styleResolve.js +38 -55
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/observability/trace.js +3 -6
- package/dist/platform/diagnostics.js +4 -10
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/errors.js +10 -162
- package/dist/platform/http.js +8 -29
- package/dist/platform/responses.js +5 -39
- package/dist/platform/{capture/capture.js → screenshot.js} +519 -105
- package/dist/platform/secrets.js +1 -17
- package/dist/platform/strictArguments.js +12 -68
- package/dist/platform/tokenVault.js +4 -187
- package/dist/resources/examples/layout-app-shell.json +707 -229
- package/dist/resources/examples/page-detail-profile.json +1 -2
- package/dist/resources/examples/page-dynamic-form.json +2 -3
- package/dist/resources/examples/page-flex-sections.json +1 -1
- package/dist/resources/examples/page-html-embed.json +1 -1
- package/dist/resources/examples/workflow-basic.json +2 -8
- package/dist/resources/guides/component.md +4 -91
- package/dist/resources/guides/entity.md +8 -50
- package/dist/resources/guides/expressions.md +5 -14
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/getting-started.md +1 -38
- package/dist/resources/guides/layout.md +58 -55
- package/dist/resources/guides/microservice.md +2 -81
- package/dist/resources/guides/middleware.md +2 -44
- package/dist/resources/guides/page.md +75 -454
- package/dist/resources/guides/theme.md +2 -8
- package/dist/resources/guides/translation.md +1 -1
- package/dist/resources/guides/workflow.md +1 -58
- package/dist/resources/rules.js +5 -11
- package/dist/resources/schema-fingerprint.json +5 -7
- package/dist/resources/schemas/CreateEntityCommand.json +0 -118
- package/dist/resources/schemas/CreateMicroserviceCommand.json +1 -13
- package/dist/resources/schemas/CreateQueryCommand.json +0 -4
- package/dist/resources/schemas/CreateWorkflowCommand.json +1 -143
- package/dist/resources/schemas/DataJobDto.json +1 -6
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -21
- package/dist/resources/schemas/MicroserviceDto.json +3 -15
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +1 -10
- package/dist/resources/schemas/PreviewWorkflowCommand.json +1 -22
- package/dist/resources/schemas/StepDto.json +1 -22
- package/dist/resources/schemas/UpdateEntityCommand.json +0 -118
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +1 -13
- package/dist/resources/schemas/UpdateQueryCommand.json +0 -4
- package/dist/resources/schemas/UpdateViewCommand.json +2 -0
- package/dist/resources/schemas/UpdateWorkflowCommand.json +1 -143
- package/dist/server.js +1 -27
- package/dist/tools/access.js +2 -369
- package/dist/tools/applications.js +3 -60
- package/dist/tools/common.js +0 -7
- package/dist/tools/components.js +14 -118
- package/dist/tools/datasources.js +3 -3
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +2 -2
- package/dist/tools/designSchemaPatch.js +18 -34
- package/dist/tools/dtos.js +5 -36
- package/dist/tools/entities.js +12 -79
- package/dist/tools/externalComponents.js +5 -26
- package/dist/tools/flows.js +14 -122
- package/dist/tools/folders.js +1 -1
- package/dist/tools/imports.js +2 -5
- package/dist/tools/layouts.js +17 -50
- package/dist/tools/merges.js +1 -1
- package/dist/tools/microservices.js +25 -77
- package/dist/tools/pages.js +112 -465
- package/dist/tools/platformInfo.js +8 -27
- package/dist/tools/projects.js +9 -71
- package/dist/tools/rows.js +13 -69
- package/dist/tools/schemaOps.js +1 -61
- package/dist/tools/screenWrite.js +8 -37
- package/dist/tools/screens.js +5 -95
- package/dist/tools/templates.js +1 -26
- package/dist/tools/translations.js +1 -1
- package/dist/tools/variables.js +5 -11
- package/dist/tools/workflows.js +5 -10
- package/package.json +2 -2
- package/dist/knowledge/access.js +0 -802
- package/dist/knowledge/case.js +0 -41
- package/dist/knowledge/connectDataBind.js +0 -819
- package/dist/knowledge/connectDataDefinition.js +0 -341
- package/dist/knowledge/connectDataExecute.js +0 -93
- package/dist/knowledge/connectDataRules.js +0 -128
- package/dist/knowledge/decision.js +0 -121
- package/dist/knowledge/expressionPrelude.js +0 -59
- package/dist/knowledge/microserviceParameters.js +0 -58
- package/dist/knowledge/mining.js +0 -94
- package/dist/knowledge/mobileComponentCatalog.js +0 -859
- package/dist/knowledge/mobileComponentEvents.js +0 -239
- package/dist/knowledge/platform/lint.js +0 -385
- package/dist/knowledge/platform/mobile.js +0 -142
- package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
- package/dist/knowledge/platform/mobileRules.js +0 -231
- package/dist/knowledge/platform/mobileSpacing.js +0 -82
- package/dist/knowledge/platform/mobileTabs.js +0 -108
- package/dist/knowledge/platform/nativeBoxModel.js +0 -44
- package/dist/knowledge/platform/profile.js +0 -25
- package/dist/knowledge/platform/resolve.js +0 -122
- package/dist/knowledge/platform/web.js +0 -39
- package/dist/knowledge/process.js +0 -510
- package/dist/knowledge/rowFilter.js +0 -43
- package/dist/knowledge/styleResolveNative.js +0 -527
- package/dist/platform/argumentAliases.js +0 -128
- package/dist/platform/bodyFile.js +0 -103
- package/dist/platform/capture/actions.js +0 -333
- package/dist/platform/capture/browser.js +0 -1
- package/dist/platform/capture/console-log.js +0 -122
- package/dist/platform/capture/index.js +0 -11
- package/dist/platform/capture/readiness.js +0 -103
- package/dist/platform/capture/summary.js +0 -77
- package/dist/platform/capture/target.js +0 -5
- package/dist/platform/capture/targets/studio-mobile.js +0 -15
- package/dist/platform/capture/targets/studio-web.js +0 -5
- package/dist/platform/impersonation.js +0 -45
- package/dist/platform/jsonArray.js +0 -24
- package/dist/platform/schemaReadMemory.js +0 -60
- package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
- package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
- package/dist/resources/examples/bpm-satinalma.json +0 -376
- package/dist/resources/examples/connect-data-convert-verify.json +0 -107
- package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
- package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
- package/dist/resources/examples/connect-data-query-params.json +0 -50
- package/dist/resources/examples/connect-data-table-entity.json +0 -147
- package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
- package/dist/resources/examples/mobile-app-shell-drawer.json +0 -243
- package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
- package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
- package/dist/resources/examples/mobile-form-screen.json +0 -365
- package/dist/resources/examples/mobile-list-detail-form.json +0 -672
- package/dist/resources/guides/access.md +0 -796
- package/dist/resources/guides/bpm.md +0 -686
- package/dist/resources/guides/case.md +0 -153
- package/dist/resources/guides/decision.md +0 -185
- package/dist/resources/guides/mobile-layout.md +0 -193
- package/dist/resources/guides/mobile.md +0 -495
- package/dist/resources/read.js +0 -41
- package/dist/resources/schemas/AccessExplanationDto.json +0 -144
- package/dist/resources/schemas/AccessMatrixDto.json +0 -170
- package/dist/resources/schemas/AccessPermissionDto.json +0 -57
- package/dist/resources/schemas/AccessPolicyDto.json +0 -223
- package/dist/resources/schemas/AccessResourceDto.json +0 -86
- package/dist/resources/schemas/AppSessionDto.json +0 -53
- package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
- package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
- package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
- package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
- package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
- package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
- package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
- package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
- package/dist/resources/schemas/DecisionDto.json +0 -302
- package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
- package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
- package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
- package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
- package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
- package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
- package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
- package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
- package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
- package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
- package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
- package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
- package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
- package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
- package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
- package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
- package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
- package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
- package/dist/tools/accessOperations.js +0 -135
- package/dist/tools/accessPolicies.js +0 -170
- package/dist/tools/accessRuntime.js +0 -203
- package/dist/tools/bpm.js +0 -343
- package/dist/tools/bpmGovernance.js +0 -266
- package/dist/tools/bpmOperations.js +0 -230
- package/dist/tools/bpmReporting.js +0 -154
- package/dist/tools/bpmRouting.js +0 -150
- package/dist/tools/bpmRuntime.js +0 -396
- package/dist/tools/case.js +0 -178
- package/dist/tools/caseRuntime.js +0 -89
- package/dist/tools/connectData.js +0 -449
- package/dist/tools/connectors.js +0 -193
- package/dist/tools/decisions.js +0 -206
- package/dist/tools/mobile.js +0 -221
- package/dist/tools/modules.js +0 -48
- package/dist/tools/organizationStructure.js +0 -137
- package/dist/tools/profileWrite.js +0 -92
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { listKnowledgeFiles, readKnowledgeFile } from '../resources/knowledge.js';
|
|
2
|
-
import { readToolResource } from '../resources/read.js';
|
|
3
2
|
import { splitGuideSections } from '../knowledge/guideSections.js';
|
|
4
3
|
import { PlatformApiError } from '../platform/errors.js';
|
|
5
4
|
import { logCapabilityGap } from '../observability/trace.js';
|
|
@@ -64,10 +63,8 @@ const guideRouting = {
|
|
|
64
63
|
microservice: 'kaynak seçimi (table > query), selectFields disiplini',
|
|
65
64
|
microfunction: 'kendi runtime\'ında koşan Node/Python fonksiyonu: protokol, yayın döngüsü, step kullanımı',
|
|
66
65
|
entity: "alan tipleri, ilişkiler, hazır entity'ler",
|
|
67
|
-
page: 'sayfa/flow işleri;
|
|
68
|
-
layout: 'yerleşim kabuğu: tek slot, views,
|
|
69
|
-
mobile: "mobil UYGULAMA (type:'mobile'): kurulum sırası (mobile_app_create), flex-only yerleşim, tipli stil, sekmeler (properties.mobile.tabs) ve çekmece, adım sözlüğü, MOB-* bulguları, page_screenshot device",
|
|
70
|
-
'mobile-layout': 'mobil ekranın mizanpajı — tek dil: güvenli alan, tek kaydırıcı, 16 dp kenar, gap ritmi, saydam/yüzeyli grup, genişlik, yarıçap/yazı ölçeği; MOB-015…021 reçeteleri ve layoutReport hiza ölçümü',
|
|
66
|
+
page: 'sayfa/flow işleri; flex düzen prop grubu ve boyut modları (Kural 1f-2)',
|
|
67
|
+
layout: 'yerleşim kabuğu: tek slot, views, mobil yığılma, widthType fill/fixed/auto',
|
|
71
68
|
component: 'komponent modeli, olay sözleşmeleri, appearance boyut sözlüğü (widthString/heightString)',
|
|
72
69
|
html: 'hazır komponent yetmediğinde tek seferlik kaçış kapısı (Mustache, fireEvent, script kuralları)',
|
|
73
70
|
'external-component': 'kalıcı ihtiyaçta kendi komponentini yazıp yayınlama',
|
|
@@ -76,10 +73,7 @@ const guideRouting = {
|
|
|
76
73
|
expressions: 'ifade fonksiyon/bağlam sözlüğü (system.*, file.*, Page.*, state.*, Steps…)',
|
|
77
74
|
functions: "fonksiyonlar, iki kaynak tek biçim: source:'studio' tarayıcıda Functions.<ad>() (kapsam uygulama/sayfa, UI flow 'function' adımı), source:'workflow' sunucuda çıplak ad; parametre/varsayılan/required, tuzaklar; GÖVDE GÜNCELLEME function_update (yalnız değişen alanı gönder, patch aracı yok)",
|
|
78
75
|
translation: 'sayfa/içerik çevirileri (çoklu dil)',
|
|
79
|
-
|
|
80
|
-
merge: "dal aç, dalda çalış, development'a merge et; çakışma çözümü ve apply kapıları",
|
|
81
|
-
bpm: 'süreç motoru: tanım modeli, düğümler, atama sözlüğü, bölge olayları, kutu ve görev eylemleri, bağlayıcı/belge/imza/kanallar (süreç ≠ workflow)',
|
|
82
|
-
decision: 'DMN karar tabloları: model, isabet politikaları, FEEL alt kümesi, DRD, süreçte decision düğümü, DMN XML'
|
|
76
|
+
merge: "dal aç, dalda çalış, development'a merge et; çakışma çözümü ve apply kapıları"
|
|
83
77
|
};
|
|
84
78
|
// page.md 123 KB; section'sız dönerse yanıt tool çıktı sınırını aşıyor ve rehber MCP kanalından
|
|
85
79
|
// HİÇ okunamıyor (27/05 E-1, 09-04 koşusu). Eşik ÖLÇÜLEN kopma noktasından türetilir, "bugün
|
|
@@ -98,8 +92,7 @@ export function registerPlatformTools(server, platform) {
|
|
|
98
92
|
'Modülün iş kuralları rehberini döner. Bir modülde İLK yazma işleminden önce ilgili rehberi okuyun:',
|
|
99
93
|
...guides.map(name => `- ${name}${guideRouting[name] ? `: ${guideRouting[name]}` : ''}`),
|
|
100
94
|
"Büyük rehberler (page ~120 KB) section'sız çağrıda TAM METİN DÖNMEZ: giriş + bölüm listesi (outline) döner, truncated: true olur. Gövdeyi section ile bölüm bölüm alın.",
|
|
101
|
-
|
|
102
|
-
"Örnek gövdeler ve kural katalogları (ngapps://examples/<ad>, ngapps://rules/<ad>) istemci MCP resource okuyamıyorsa da bu araçla okunur: platform_guide({ resource: 'ngapps://rules/connect-data' }) — guide verilmez; dizin için 'ngapps://examples/index'."
|
|
95
|
+
'Örnek gövdeler için ngapps://examples kaynaklarına bakın.'
|
|
103
96
|
].join('\n');
|
|
104
97
|
server.registerTool('platform_whoami', {
|
|
105
98
|
title: 'Oturum bilgisi',
|
|
@@ -111,23 +104,13 @@ export function registerPlatformTools(server, platform) {
|
|
|
111
104
|
title: 'Platform rehberi oku',
|
|
112
105
|
description: guideDescription,
|
|
113
106
|
inputSchema: {
|
|
114
|
-
guide: (guides.length > 0 ? z.enum(guides) : z.string())
|
|
115
|
-
.describe('Rehber adı; bilinmeyen ad verilirse mevcut rehberler listelenir
|
|
116
|
-
resource: z.string().regex(/^ngapps:\/\//).optional()
|
|
117
|
-
.describe("guide yerine bir ngapps:// kaynağı okur (examples ve rules): 'ngapps://examples/connect-data-table-entity', 'ngapps://rules/connect-data', dizinler '…/index'. Resource okuyamayan istemcinin rehberdeki ngapps:// yönlendirmelerini izleme yolu budur (38/M-14)."),
|
|
107
|
+
guide: (guides.length > 0 ? z.enum(guides) : z.string())
|
|
108
|
+
.describe('Rehber adı; bilinmeyen ad verilirse mevcut rehberler listelenir'),
|
|
118
109
|
section: z.string().optional()
|
|
119
110
|
.describe("Yalnız bu bölümü döner (yanıttaki 'sections' listesinden bir slug). Verilmezse rehber tam döner; ancak tool yanıt sınırını aşan büyük rehberlerde (page) yalnız giriş + outline döner")
|
|
120
111
|
},
|
|
121
112
|
annotations: readOnly
|
|
122
|
-
}, handle(config, async ({ guide, section
|
|
123
|
-
if (resource !== undefined) {
|
|
124
|
-
if (guide !== undefined || section !== undefined)
|
|
125
|
-
throw new PlatformApiError("platform_guide: resource ile guide/section birlikte verilemez — biri ngapps:// kaynağını, diğeri rehber bölümünü okur.", 400);
|
|
126
|
-
const read = readToolResource(resource);
|
|
127
|
-
return 'error' in read ? read : { resource: read.uri, mimeType: read.mimeType, content: read.text };
|
|
128
|
-
}
|
|
129
|
-
if (guide === undefined)
|
|
130
|
-
throw new PlatformApiError("platform_guide: 'guide' (rehber adı) ya da 'resource' (ngapps:// kaynağı) verin.", 400);
|
|
113
|
+
}, handle(config, async ({ guide, section }) => {
|
|
131
114
|
const available = listKnowledgeFiles('guides').map(file => file.replace(/\.md$/, ''));
|
|
132
115
|
if (!available.includes(guide)) {
|
|
133
116
|
return { error: `'${guide}' diye bir rehber yok.`, available };
|
|
@@ -171,7 +154,6 @@ export function registerPlatformTools(server, platform) {
|
|
|
171
154
|
title: 'Kabiliyet boşluğu bildir',
|
|
172
155
|
description: "Yapmak İSTEDİĞİNİZ ama platform desteklemediği için yapamadığınız her noktada BUNU ÇAĞIRIN — tasarımı sessizce küçültmeyin. Bu çağrı platforma gitmez, yalnızca günlüğe 'KABİLİYET BOŞLUĞU' bloğu yazar; hata günlüğünde görünmeyen bu kayıtlar ürün yol haritasının girdisidir. Önce rehbere bakıp (platform_guide; hazır komponent yetmiyorsa tek seferlik için 'html' kaçış kapısı, kalıcı bir ihtiyaç içinse 'external-component' — kendi komponentinizi yazıp yayınlayabilirsiniz) gerçekten desteklenmediğinden emin olun: desteklenen bir şeyi 'yok' diye bildirmek yanlış yol haritası üretir.",
|
|
173
156
|
inputSchema: {
|
|
174
|
-
project: z.string().min(1).optional().describe("Boşluğun görüldüğü proje (ad ya da slug); kayda yazılır. Bu çağrı platforma gitmez, proje yalnız bağlamdır"),
|
|
175
157
|
goal: z.string().min(1).optional().describe('Ne yapmak istediniz — kullanıcıya görünen sonuç olarak yazın ("randevu listesini hasta adına göre süzmek"). Eşanlamlı kabul edilir: title · summary · what.'),
|
|
176
158
|
blocker: z.string().min(1).optional().describe('Neden yapamadınız — hangi kabiliyetin eksik olduğu ("uçta X yok", "komponentte Y prop\'u yok"). Eşanlamlı kabul edilir: reason · problem · missing · description.'),
|
|
177
159
|
severity: z.string().optional().describe("YOL HARİTASINDAKİ SIRAYI BU ALAN BELİRLER, doldurun. blocker: özellik hiç yapılamadı · workaround: daha kötü bir yolla yapıldı · cosmetic: yalnız görsel/ergonomik kayıp. Eşanlamlılar çevrilir (critical/high/blocking→blocker, medium/major→workaround, low/minor/nit→cosmetic). TANINMAYAN değer reddedilir; verilmezse kayıt düşer ama yanıt 'incomplete' ile uyarır ve bildirim orta kovaya yazılır."),
|
|
@@ -189,10 +171,9 @@ export function registerPlatformTools(server, platform) {
|
|
|
189
171
|
annotations: readOnly
|
|
190
172
|
}, handle(config, async (input) => {
|
|
191
173
|
const gap = normalizeGapReport(input);
|
|
192
|
-
logCapabilityGap({ goal: gap.goal, blocker: gap.blocker, severity: gap.severity, module: gap.module, attempted: gap.attempted, workaround: gap.workaround
|
|
174
|
+
logCapabilityGap({ goal: gap.goal, blocker: gap.blocker, severity: gap.severity, module: gap.module, attempted: gap.attempted, workaround: gap.workaround });
|
|
193
175
|
return {
|
|
194
176
|
recorded: true,
|
|
195
|
-
...(input.project ? { project: input.project } : {}),
|
|
196
177
|
severity: gap.severity,
|
|
197
178
|
module: gap.module ?? null,
|
|
198
179
|
...(Object.keys(gap.normalizedFrom).length > 0 ? { normalizedFrom: gap.normalizedFrom } : {}),
|
package/dist/tools/projects.js
CHANGED
|
@@ -70,32 +70,6 @@ function rows(payload) {
|
|
|
70
70
|
const data = payload?.data;
|
|
71
71
|
return Array.isArray(data) ? data : [];
|
|
72
72
|
}
|
|
73
|
-
/**
|
|
74
|
-
* 2026-09-15'ten eski backend'lerde `GET /p/{slug}` (`GetOrganizationProjectBySlugQuery`)
|
|
75
|
-
* `OrganizationProjectDto.Map`'i yayın sürümü vermeden çağırıyordu: `organizationSchema.latestVersion` null
|
|
76
|
-
* gelir, prune onu düşürür ve "latestVersion yoksa yayınlı şema yok" okuması yanlış olurdu (TB-67, backend'de
|
|
77
|
-
* çözüldü). Slug yanıtı sürümü taşıyorsa olduğu gibi döner; taşımıyorsa (eski build) abonelik bloğu id ucundan
|
|
78
|
-
* (`GetOrganizationProjectQuery`) alınır. İd ucu düşerse (o uç `RequirePermission` taşımaz, Organization.API onu
|
|
79
|
-
* yalnız super-admin'e açar) slug yanıtı döner ve söylenir.
|
|
80
|
-
*/
|
|
81
|
-
async function withPublishedSchemaVersion(platform, payload) {
|
|
82
|
-
const data = payload?.data;
|
|
83
|
-
if (!data || typeof data.id !== 'string' || data.accessModel !== 'complex')
|
|
84
|
-
return payload;
|
|
85
|
-
const latestVersion = data.organizationSchema?.latestVersion;
|
|
86
|
-
if (latestVersion !== undefined && latestVersion !== null)
|
|
87
|
-
return payload;
|
|
88
|
-
try {
|
|
89
|
-
const byId = await platform.org('GET', `/projects/${data.id}`);
|
|
90
|
-
const organizationSchema = byId?.data?.organizationSchema;
|
|
91
|
-
return organizationSchema && typeof organizationSchema === 'object'
|
|
92
|
-
? { ...payload, data: { ...data, organizationSchema } }
|
|
93
|
-
: payload;
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
return withNormalization(payload, ["organizationSchema.latestVersion doğrulanamadı (slug ucu GET /p/{slug} sürüm taşımaz, GET /projects/{id} okunamadı): yokluğu 'yayınlı şema yok' demek DEĞİLDİR — organization_schema_get ile doğrulayın (TB-67)."]);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
73
|
const applicationInput = z.object({
|
|
100
74
|
slug: z.string().min(1),
|
|
101
75
|
name: z.string().min(1),
|
|
@@ -150,35 +124,32 @@ export function registerProjectTools(server, platform) {
|
|
|
150
124
|
const config = platform.config;
|
|
151
125
|
server.registerTool('project_list', {
|
|
152
126
|
title: 'Projeleri listele',
|
|
153
|
-
description:
|
|
127
|
+
description: 'Organizasyondaki projeleri arar ve sayfalı listeler.',
|
|
154
128
|
inputSchema: { searchTerm: z.string().optional(), ...pagingParams },
|
|
155
129
|
annotations: readOnly
|
|
156
130
|
}, handle(config, args => platform.org('GET', '/projects', { query: args })));
|
|
157
131
|
server.registerTool('project_get', {
|
|
158
132
|
title: 'Proje getir',
|
|
159
|
-
description: "Tek projeyi id ya da slug ile getirir; environment listesi de yanıttadır
|
|
133
|
+
description: "Tek projeyi id ya da slug ile getirir; environment listesi de yanıttadır. Yanıttaki 'localization' bloğu gateway'in eklediği türetilmiş alandır: platform dil alanlarını null olduklarında serileştirmede düşürüyor, blok bunu görünür kılar ve runtime'ın çevirileri çözüp çözemeyeceğini söyler.",
|
|
160
134
|
inputSchema: { id: guid.optional(), slug: z.string().optional().describe('id verilmediyse zorunlu') },
|
|
161
135
|
annotations: readOnly
|
|
162
136
|
}, handle(config, async (args) => {
|
|
163
137
|
if (!args.id && !args.slug) {
|
|
164
138
|
throw new Error("'id' ya da 'slug' parametrelerinden biri zorunlu.");
|
|
165
139
|
}
|
|
166
|
-
|
|
167
|
-
return withLocalization(await platform.org('GET', `/projects/${args.id}`));
|
|
168
|
-
return withLocalization(await withPublishedSchemaVersion(platform, await platform.org('GET', `/p/${args.slug}`)));
|
|
140
|
+
return withLocalization(await platform.org('GET', args.id ? `/projects/${args.id}` : `/p/${args.slug}`));
|
|
169
141
|
}));
|
|
170
142
|
server.registerTool('project_create', {
|
|
171
143
|
title: 'Proje oluştur',
|
|
172
144
|
description: "Yeni proje oluşturur. templateOptions verilmezse 'application' zorunludur (ilk application projeyle birlikte açılır). LoaderImage bu tool'da desteklenmez. " + constraintSummary('CreateOrganizationProjectCommand') + ` Gateway POST'tan önce project_list ile slug'ı arar; doluysa istek gitmez ve 409 anlamlı mesajla döner. DİL: create ucu artık languages/defaultLanguage alanlarını kendisi taşır ve gövdeyle birlikte gider. Vermezseniz gateway varsayılan [${SEED_LANGUAGES.join(', ')}] + '${SEED_DEFAULT_LANGUAGE}' tohumunu koyar ve bunu gatewayNormalized ile bildirir — dilsiz projede yazılan çeviriler runtime'da ham anahtar olarak çizilir (S-15). templateOptions verildiğinde TOHUM atlanır (template kendi dil ayarını taşır); açıkça verdiğiniz diller o yolda da gönderilir.`,
|
|
173
145
|
inputSchema: {
|
|
174
146
|
name: z.string().min(1),
|
|
175
|
-
slug: z.string().min(1).describe(
|
|
147
|
+
slug: z.string().min(1).describe('Organizasyonda tekil; veritabanı adı zeyrek_<org>_<slug> bundan türer ve sonradan değiştirmek bütün runtime rotalarını kırar'),
|
|
176
148
|
theme: themeInput.optional().describe("Tema nesnesi (ya da JSON metni) — Studio tema panelinin yazdığı kayıtla aynı şekil: mode · palette · paletteDark · fontFamily · typeScale · shadow · presets · componentPresets. Verilmezse proje platformun varsayılan temasıyla (accent #0052CC, Inter 14px) doğar. Kurulmuş bir projenin temasını DEĞİŞTİRMEK için theme_update: kısmi günceller, şema/lint'ten geçirir ve hangi CSS değişkeninin değiştiğini söyler"),
|
|
177
149
|
languages: z.array(z.string().min(1)).min(1).optional().describe(`Proje dilleri (ISO 639-1; 'tr-TR' gibi bölgeli değer kabul edilir ve 'tr'ye indirgenir, indirgeme gatewayNormalized ile bildirilir). Verilmezse gateway [${SEED_LANGUAGES.join(', ')}] tohumlar — projenin dilsiz doğmasına ve çevirilerin sessizce çözülmemesine izin verilmez`),
|
|
178
150
|
defaultLanguage: z.string().min(1).optional().describe(`languages içinde olmalı (indirgenmiş hâliyle karşılaştırılır); yalnız defaultLanguage verirseniz languages onunla kurulur. İkisi de yoksa '${SEED_DEFAULT_LANGUAGE}'`),
|
|
179
151
|
application: applicationInput.optional(),
|
|
180
|
-
templateOptions: templateOptionsInput.optional().describe('Verilirse proje template\'ten kurulur (asenkron); sonucu project_list ile izleyin')
|
|
181
|
-
accessModel: z.enum(['simple', 'complex']).optional().describe("Proje türü; varsayılan 'simple' (bugünkü davranış: kimlik ve yetkiyi uygulamanın kendi middleware'i kurar). 'complex': proje organizasyonun YAYINLI SON rol şemasının kopyasıyla doğar (yayın yoksa organization_units/organization_positions boştur — ORG-002), platform yönetimli uygulama oturumu ve karar motoru devrededir, yeni ortamların zorlama modu 'enforce'tur; şema tablolarına genel satır yazımı kapalıdır (ORG-001). templateOptions ile verilirse yok sayılır — template kaynak projenin türünü taşır")
|
|
152
|
+
templateOptions: templateOptionsInput.optional().describe('Verilirse proje template\'ten kurulur (asenkron); sonucu project_list ile izleyin')
|
|
182
153
|
},
|
|
183
154
|
annotations: writes
|
|
184
155
|
}, handle(config, async (args) => {
|
|
@@ -188,7 +159,7 @@ export function registerProjectTools(server, platform) {
|
|
|
188
159
|
if (!languages.codes.includes(defaultLanguage.code)) {
|
|
189
160
|
throw new PlatformApiError(`project_create: defaultLanguage '${defaultLanguage.code}' languages listesinde (${languages.codes.join(', ')}) yok — platform bunu 422 ile reddeder (PRJ-002). Kodu listeye ekleyin ya da listedeki bir kodu varsayılan yapın.`, 422);
|
|
190
161
|
}
|
|
191
|
-
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'project', args, { operation: 'create' })
|
|
162
|
+
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'project', args, { operation: 'create' }));
|
|
192
163
|
// PRJ-001: slug çakışması 2026-09-08 öncesi build'de 500 'DatabaseNameAlreadyExistsException'
|
|
193
164
|
// dönüyordu (3. koşu S-1); arama ucu düşerse ön kontrol atlanır, karar platforma kalır.
|
|
194
165
|
const existing = rows(await platform.org('GET', '/projects', { query: { searchTerm: args.slug, pageLength: 200 } }).catch(() => undefined))
|
|
@@ -218,14 +189,6 @@ export function registerProjectTools(server, platform) {
|
|
|
218
189
|
form.set('TemplateOptions.TemplateReceiveUpdates', String(args.templateOptions.templateReceiveUpdates));
|
|
219
190
|
}
|
|
220
191
|
}
|
|
221
|
-
// Template yolunda platform kaynak projenin türünü kullanır ve istemcinin gönderdiğini yok
|
|
222
|
-
// sayar (05 §2); göndermek "complex istedim" yanılgısı üretirdi, gönderilmez ve söylenir.
|
|
223
|
-
if (args.accessModel && args.templateOptions) {
|
|
224
|
-
notes.push(`accessModel '${args.accessModel}' gönderilmedi: template yolunda proje türü template'in kaynak projesinden gelir. Sonucu project_get accessModel alanından doğrulayın.`);
|
|
225
|
-
}
|
|
226
|
-
else if (args.accessModel) {
|
|
227
|
-
form.set('AccessModel', args.accessModel);
|
|
228
|
-
}
|
|
229
192
|
// Dil artık create ucunun kendi alanı (CreateOrganizationProjectCommand.Languages /
|
|
230
193
|
// DefaultLanguage); ayrı bir PUT'a gerek yok. Template yolunda yalnız TOHUM atlanır: template
|
|
231
194
|
// kendi dil ayarını getiriyor ve uydurulmuş bir varsayılanla onu ezmek yanlış olur — çağıranın
|
|
@@ -240,29 +203,7 @@ export function registerProjectTools(server, platform) {
|
|
|
240
203
|
notes.push(`Proje dilleri gateway tarafından varsayılanla kuruldu: languages [${languages.codes.join(', ')}], defaultLanguage '${defaultLanguage.code}'. Dilsiz projede yazılan çeviriler runtime'da ham anahtar olarak çizilir (S-15). Başka dil istiyorsanız project_update ile değiştirin.`);
|
|
241
204
|
}
|
|
242
205
|
}
|
|
243
|
-
|
|
244
|
-
const schema = (created?.data ?? {});
|
|
245
|
-
if (schema.accessModel === 'complex') {
|
|
246
|
-
// Oluşturma yanıtı 2026-09-15'ten beri sürümü taşır (TB-67 backend'de çözüldü); daha eski build'lerde
|
|
247
|
-
// OrganizationProjectDto.Map sürümsüz çağrılıp alan null gelir — "yayın yok" demeden önce id ucu bir kez okunur.
|
|
248
|
-
let latestVersion = schema.organizationSchema?.latestVersion;
|
|
249
|
-
let versionUnknown = false;
|
|
250
|
-
if ((latestVersion === undefined || latestVersion === null) && typeof schema.id === 'string') {
|
|
251
|
-
try {
|
|
252
|
-
const byId = await platform.org('GET', `/projects/${schema.id}`);
|
|
253
|
-
latestVersion = byId?.data?.organizationSchema?.latestVersion;
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
versionUnknown = true;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
notes.push(versionUnknown
|
|
260
|
-
? "Kompleks proje açıldı; organizasyonun yayınlı şema sürümü doğrulanamadı (oluşturma yanıtında latestVersion yok, GET /projects/{id} okunamadı). Organizasyon tablolarının dolu doğup doğmadığını organization_schema_get ve row_list('organization_units') ile doğrulayın (ORG-002, TB-67)."
|
|
261
|
-
: latestVersion === undefined || latestVersion === null
|
|
262
|
-
? "Kompleks proje açıldı ama organizasyonda YAYINLI şema yok: organization_units / organization_positions tabloları boş doğdu (ORG-002). Şema yönetim konsolunda yayınlanınca abone projeye senkronla gelir; durumu organization_schema_get ve project_get organizationSchema ile izleyin."
|
|
263
|
-
: `Kompleks proje organizasyon şemasının ${String(latestVersion)}. sürümüne abone doğdu; kopya her ortama senkronla yazılır (asenkron — project_get organizationSchema.appliedVersion dolunca tamamdır). Şema tablolarına row_* yazımı kapalıdır (ORG-001); ağacı row_list ile okuyun.`);
|
|
264
|
-
}
|
|
265
|
-
return attachFindings(withNormalization(created, notes), findings);
|
|
206
|
+
return attachFindings(withNormalization(await platform.org('POST', '/projects', { form }), notes), findings);
|
|
266
207
|
}));
|
|
267
208
|
server.registerTool('project_update', {
|
|
268
209
|
title: 'Proje güncelle',
|
|
@@ -273,12 +214,11 @@ export function registerProjectTools(server, platform) {
|
|
|
273
214
|
slug: z.string().optional(),
|
|
274
215
|
theme: themeInput.optional().describe("Tema nesnesi (ya da JSON metni); verilen kayıt mevcut temanın YERİNE geçer — bir alanı değiştirmek için theme_update kullanın (kısmi birleştirir, lint'ten geçirir). VERİLMEZSE mevcut tema korunur — gateway projeden okuyup gövdeye geri koyar, çünkü platform Theme alanı gövdede yokken temayı siler ve silinen tema bütün ortamların runtime'ına iner (S-1). Temayı gerçekten temizlemek için theme: {} verin"),
|
|
275
216
|
languages: z.array(languageCode).min(1).optional().describe("ISO 639-1 iki harfli kod listesi (proje dilleri, platformun 184 kodluk sözlüğünden — PRJ-002). Runtime çevirileri YALNIZ bu kodlarla çözer; liste kurulmadan yazılan çeviriler 200 döner ama ekrana ham anahtar basılır (S-15). Yeni proje bu liste BOŞ doğar — çeviri kullanacaksanız burayı kurmak ilk adımdır"),
|
|
276
|
-
defaultLanguage: languageCode.optional().describe("languages içinde olmalı — proje dilleri hiç kurulmadıysa (ilk kurulumda) tek başına verilebilir. Runtime kayıtlı dil seçimi yokken buna düşer; boşsa aktif dil hiç seçilmez ve ilk açılışta bütün etiketler ham anahtar çizilir")
|
|
277
|
-
revealReasonMinLength: z.number().int().min(0).max(1000).optional().describe("Gerekçeli açmada (access_reveal) kabul edilen en kısa gerekçe; 0 kuralı kapatır. VERİLMEZSE mevcut değer korunur. Runtime reveal yolunda (access_reveal) yalnız kompleks projede etkilidir, Studio ızgara reveal'inde HER projede zorlanır; daha kısa gerekçe 400 RevealReasonTooShort alır ve denetim defterine REVEAL-DENIED düşer (TB-98)")
|
|
217
|
+
defaultLanguage: languageCode.optional().describe("languages içinde olmalı — proje dilleri hiç kurulmadıysa (ilk kurulumda) tek başına verilebilir. Runtime kayıtlı dil seçimi yokken buna düşer; boşsa aktif dil hiç seçilmez ve ilk açılışta bütün etiketler ham anahtar çizilir")
|
|
278
218
|
},
|
|
279
219
|
annotations: updates
|
|
280
220
|
}, handle(config, async (args) => {
|
|
281
|
-
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'project', args, { operation: 'update' })
|
|
221
|
+
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'project', args, { operation: 'update' }));
|
|
282
222
|
// Çağıranın hatası okumadan ÖNCE döner: bozuk tema metni için projeyi çekmenin anlamı yok.
|
|
283
223
|
const requestedTheme = themeField(args.theme, 'project_update');
|
|
284
224
|
// Platform gövdede slug yoksa onu ADDAN yeniden üretiyor. Yalnız dil ayarını değiştiren bir
|
|
@@ -302,8 +242,6 @@ export function registerProjectTools(server, platform) {
|
|
|
302
242
|
languages?.codes.forEach(code => form.append('Languages', code));
|
|
303
243
|
if (defaultLanguage)
|
|
304
244
|
form.set('DefaultLanguage', defaultLanguage.code);
|
|
305
|
-
if (args.revealReasonMinLength !== undefined)
|
|
306
|
-
form.set('RevealReasonMinLength', String(args.revealReasonMinLength));
|
|
307
245
|
const payload = await platform.org('PUT', `/projects/${args.id}`, { form });
|
|
308
246
|
const notes = [
|
|
309
247
|
...(languages?.notes ?? []),
|
package/dist/tools/rows.js
CHANGED
|
@@ -3,19 +3,16 @@ import { guid, entityRef, resolveEntityId, withResolved, projectParam, environme
|
|
|
3
3
|
import { unmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
|
|
4
4
|
import { withNormalization } from '../knowledge/normalize.js';
|
|
5
5
|
import { RefResolver } from '../platform/refs.js';
|
|
6
|
-
import { attachFindings,
|
|
7
|
-
import {
|
|
8
|
-
import { filterOperatorError, policyRules } from '../knowledge/rules.js';
|
|
6
|
+
import { attachFindings, evaluatePolicy, enforcePolicy } from '../knowledge/policy.js';
|
|
7
|
+
import { policyRules } from '../knowledge/rules.js';
|
|
9
8
|
import { languageHeader } from '../knowledge/languageCodes.js';
|
|
10
9
|
import { handle } from '../platform/responses.js';
|
|
11
10
|
import { uploadFile } from './files.js';
|
|
12
11
|
import { PlatformApiError } from '../platform/errors.js';
|
|
13
12
|
import { secretKeyPattern } from '../platform/secrets.js';
|
|
14
13
|
import { csvRows } from '../platform/csv.js';
|
|
15
|
-
import { rowFilterSchema } from '../knowledge/rowFilter.js';
|
|
16
14
|
import { readFile, stat, writeFile } from 'node:fs/promises';
|
|
17
15
|
import { extname, resolve } from 'node:path';
|
|
18
|
-
import { jsonArray } from '../platform/jsonArray.js';
|
|
19
16
|
import { z } from 'zod';
|
|
20
17
|
const rowValues = z.record(z.unknown()).describe("Alan SLUG'ı → değer sözlüğü; anahtarlar entity_get çıktısındaki field SLUG'larıdır (name değil — name kullanmak 'Please enter a valid value' hatası verir)");
|
|
21
18
|
/**
|
|
@@ -38,17 +35,6 @@ function derivedRowFindings(rows) {
|
|
|
38
35
|
guide: 'ngapps://guides/entity'
|
|
39
36
|
}];
|
|
40
37
|
}
|
|
41
|
-
/**
|
|
42
|
-
* ORG-001'in çözüm sonrası yarısı. Backend yalnız entity id'sine bakar (`SystemManagedEntityIds`); ön
|
|
43
|
-
* denetim GUID'i, öneksiz slug'ı ve yerleşik datasource önekini istek gitmeden tanır, başka adla yazılmış
|
|
44
|
-
* önek ise ancak çözülen id'yle anlaşılır. Dış datasource'taki aynı adlı tablo (`ik/user_positions`) başka
|
|
45
|
-
* bir id'ye çözüldüğü için geçer. Ön denetim zaten eşleştiyse bulgu ikinci kez yazılmaz.
|
|
46
|
-
*/
|
|
47
|
-
function resolvedSystemEntityFindings(config, entityId, resolvedEntityId, operation) {
|
|
48
|
-
if (config.policyMode === 'off' || systemManagedEntity(entityId))
|
|
49
|
-
return [];
|
|
50
|
-
return enforcePolicy(applyPolicyMode(config, systemEntityWriteFindings(resolvedEntityId, operation)), false);
|
|
51
|
-
}
|
|
52
38
|
const bulkBatchSize = 1000;
|
|
53
39
|
const maxPathBytes = 50 * 1024 * 1024;
|
|
54
40
|
const maxPathRows = 100_000;
|
|
@@ -171,8 +157,8 @@ const templateFormatNotes = {
|
|
|
171
157
|
csv: 'csv şablonda ipucu satırı ve `#zeyrek` satırı yoktur; başlıklar alan adıdır.',
|
|
172
158
|
json: 'JSON şablon `{ meta, data }` gövdesidir; `meta` analizde atlanır, satırlar `data`dadır ve anahtarları alan slug\'ıdır.'
|
|
173
159
|
};
|
|
174
|
-
const rowFiltersParam =
|
|
175
|
-
.describe(
|
|
160
|
+
const rowFiltersParam = z.array(z.record(z.unknown())).optional()
|
|
161
|
+
.describe('Platform Filter dizisi; biçim için row_list\'i filtresiz çağırıp Studio\'daki bir filtreyi referans alın');
|
|
176
162
|
const exportScopeParam = z.object({
|
|
177
163
|
kind: z.enum(['view', 'all', 'selected']).describe("'view' filtre + sıralama ile, 'all' tüm satırlar, 'selected' rowIds listesi"),
|
|
178
164
|
filters: rowFiltersParam,
|
|
@@ -230,7 +216,7 @@ export function registerRowTools(server, platform) {
|
|
|
230
216
|
project: projectParam,
|
|
231
217
|
environment: environmentParam,
|
|
232
218
|
entityId: entityRef,
|
|
233
|
-
selectedFields: z.array(z.string()).optional().describe('Dönen satırlar bu alan adlarına indirgenir, id her zaman dahildir; platform tam satırı hesapladığı için kırpma gateway tarafında yapılır
|
|
219
|
+
selectedFields: z.array(z.string()).optional().describe('Dönen satırlar bu alan adlarına indirgenir, id her zaman dahildir; platform tam satırı hesapladığı için kırpma gateway tarafında yapılır'),
|
|
234
220
|
filters: rowFiltersParam,
|
|
235
221
|
language: languageParam,
|
|
236
222
|
includeTranslations: includeTranslationsParam,
|
|
@@ -238,32 +224,26 @@ export function registerRowTools(server, platform) {
|
|
|
238
224
|
},
|
|
239
225
|
annotations: readOnly
|
|
240
226
|
}, handle(config, async ({ project, environment, entityId, language, ...body }) => {
|
|
241
|
-
const operatorError = filterOperatorError('row_list', body.filters);
|
|
242
|
-
if (operatorError)
|
|
243
|
-
throw new PlatformApiError(operatorError, 400);
|
|
244
227
|
const notes = [];
|
|
245
228
|
const headers = languageHeader(language, notes);
|
|
246
229
|
const resolver = new RefResolver(platform, project, environment);
|
|
247
230
|
const resolvedEntityId = await resolveEntityId(resolver, entityId);
|
|
248
|
-
// PROT-001 / PROT-002: korumalı alanda metin araması ve sıralama platformda 400'dür; entity
|
|
249
|
-
// yalnız riskli bir işleç ya da sıralama varsa okunur.
|
|
250
|
-
const protectionFindings = enforcePolicy(applyPolicyMode(config, await protectedFilterFindings(platform, resolver, entityId, body)), false);
|
|
251
231
|
const payload = await platform.tenant('POST', project, `/entities/${resolvedEntityId}/row/list`, { environment, body, headers });
|
|
252
232
|
const wanted = body.selectedFields ?? [];
|
|
253
233
|
const rows = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload.data : undefined;
|
|
254
234
|
if (!wanted.length || !Array.isArray(rows))
|
|
255
|
-
return
|
|
235
|
+
return withNormalization(withResolved(payload, resolver.resolved), notes);
|
|
256
236
|
/**
|
|
257
237
|
* 'localizations' keep listesine girmezse includeTranslations'ın getirdiği çeviriler tam da
|
|
258
238
|
* onları isteyen çağrıda kırpılırdı: iki parametre birlikte verildiğinde sessizce boşa çıkar.
|
|
259
239
|
*/
|
|
260
240
|
const keep = new Set([...wanted.map(field => field.toLowerCase()), 'id', ...(body.includeTranslations ? ['localizations'] : [])]);
|
|
261
|
-
return
|
|
241
|
+
return withNormalization(withResolved({
|
|
262
242
|
...payload,
|
|
263
243
|
data: rows.map(row => row && typeof row === 'object' && !Array.isArray(row)
|
|
264
244
|
? Object.fromEntries(Object.entries(row).filter(([key]) => keep.has(key.toLowerCase())))
|
|
265
245
|
: row)
|
|
266
|
-
}, resolver.resolved), notes)
|
|
246
|
+
}, resolver.resolved), notes);
|
|
267
247
|
}));
|
|
268
248
|
server.registerTool('row_get', {
|
|
269
249
|
title: 'Satır getir',
|
|
@@ -306,17 +286,17 @@ export function registerRowTools(server, platform) {
|
|
|
306
286
|
const wantedLocalizations = localizations && Object.keys(localizations).length > 0 ? localizations : undefined;
|
|
307
287
|
const fileRows = path ? await readRowsFromPath('row_create', path) : undefined;
|
|
308
288
|
const bulkRows = rows ?? fileRows;
|
|
309
|
-
const
|
|
289
|
+
const shapeFindings = enforcePolicy(evaluatePolicy(config, policyRules, 'row', bulkRows ? { rows: bulkRows } : { row }, { operation: 'create' }));
|
|
310
290
|
const resolver = new RefResolver(platform, project, environment);
|
|
311
|
-
const resolvedEntityId = await resolveEntityId(resolver, entityId);
|
|
312
|
-
const shapeFindings = [...inputFindings, ...resolvedSystemEntityFindings(config, entityId, resolvedEntityId, 'create')];
|
|
313
291
|
if (bulkRows) {
|
|
292
|
+
const bulkEntityId = await resolveEntityId(resolver, entityId);
|
|
314
293
|
const bulkDrift = unmappedMembers('CreateBulkRowCommand', { rows: bulkRows, ...(rowContext ? { rowContext } : {}), ...(relationsByName ? { relationsByName } : {}) });
|
|
315
|
-
const outcome = await writeInBatches(platform, 'POST', project, environment, headers,
|
|
294
|
+
const outcome = await writeInBatches(platform, 'POST', project, environment, headers, bulkEntityId, bulkRows, rowContext, relationsByName);
|
|
316
295
|
if (fileRows)
|
|
317
296
|
notes.push(`${path} okundu: ${fileRows.length} satır, ${Math.ceil(fileRows.length / bulkBatchSize)} parti.`);
|
|
318
297
|
return attachFindings(withUnmappedMembers(withNormalization(withResolved(outcome, resolver.resolved), notes), bulkDrift), [...shapeFindings, ...(fileRows ? [] : derivedRowFindings(bulkRows))]);
|
|
319
298
|
}
|
|
299
|
+
const resolvedEntityId = await resolveEntityId(resolver, entityId);
|
|
320
300
|
const body = { row, ...(wantedLocalizations ? { localizations: wantedLocalizations } : {}), ...(rowContext ? { rowContext } : {}) };
|
|
321
301
|
const drift = unmappedMembers('CreateRowCommand', body);
|
|
322
302
|
const response = await platform.tenantWithHeaders('POST', project, `/entities/${resolvedEntityId}/row`, { environment, headers, body });
|
|
@@ -374,11 +354,10 @@ export function registerRowTools(server, platform) {
|
|
|
374
354
|
const notes = [];
|
|
375
355
|
const fileRows = path ? await readRowsFromPath('row_update', path) : undefined;
|
|
376
356
|
const bulkRows = rows ?? fileRows;
|
|
377
|
-
const
|
|
357
|
+
const shapeFindings = enforcePolicy(evaluatePolicy(config, policyRules, 'row', bulkRows ? { rows: bulkRows } : { row }, { operation: 'update' }));
|
|
378
358
|
const headers = languageHeader(language, notes);
|
|
379
359
|
const resolver = new RefResolver(platform, project, environment);
|
|
380
360
|
const resolvedEntityId = await resolveEntityId(resolver, entityId);
|
|
381
|
-
const shapeFindings = [...inputFindings, ...resolvedSystemEntityFindings(config, entityId, resolvedEntityId, 'update')];
|
|
382
361
|
if (bulkRows) {
|
|
383
362
|
const bulkDrift = unmappedMembers('UpdateBulkRowCommand', { rows: bulkRows, ...(rowContext ? { rowContext } : {}), ...(relationsByName ? { relationsByName } : {}) });
|
|
384
363
|
const outcome = await writeInBatches(platform, 'PUT', project, environment, headers, resolvedEntityId, bulkRows, rowContext, relationsByName);
|
|
@@ -390,36 +369,6 @@ export function registerRowTools(server, platform) {
|
|
|
390
369
|
const drift = unmappedMembers('UpdateRowCommand', body);
|
|
391
370
|
return attachFindings(withUnmappedMembers(withNormalization(withResolved(await platform.tenant('PUT', project, `/entities/${resolvedEntityId}/row`, { environment, headers, body }), resolver.resolved), notes), drift), shapeFindings);
|
|
392
371
|
}));
|
|
393
|
-
server.registerTool('row_reassign', {
|
|
394
|
-
title: 'Satırların sahibini değiştir',
|
|
395
|
-
description: "Satırların SAHİPLİK alanlarını (sys_owner_unit_id · sys_owner_user_id) değiştirir (POST /{project}/entities/{entityId}/row/reassign). Bu alanlar row_update ile YAZILMAZ: gövdede görülürse istek 400 OwnershipFieldNotWritable alır (eskiden sessizce düşüyordu, S2-7). Hedef satırlar 'rowIds' ile ya da 'filter' ile seçilir; en az biri zorunlu. En az bir hedef sahip verilmelidir: ownerUnitId birime, ownerUserId kişiye devreder — yalnız ownerUserId verilirse birim de o kişinin aktif birincil pozisyonundan türetilir (pozisyonu yoksa satırın birimi olduğu gibi kalır). Her satıra REASSIGN denetim kaydı düşer (eski sahip → yeni sahip). KİMLİK: bu uç öteki row_* araçları gibi bir STUDIO ucudur ve gateway'in platform kimliğiyle koşar — uygulama jetonu (asUser) burada geçmez, 401 alır. Uygulama KULLANICISININ kapsamıyla devretmek (ve 'entity.reassign' kapsamını gerçekten ölçmek) için aynı işi yapan sistem operasyonunu kullanın: systemOperation 'entity.row.reassign' olan bir uç açıp microservice_execute { asUser } ile çağırın. Kapsam kuralı orada işler: çağıran yalnız 'entity.reassign' grant'inin satır kapsamındaki satırları devredebilir; kapsamı unit ya da unit-tree olan çağıran için SAHİPSİZ satırlar (sys_owner_unit_id NULL) da kapsam içi sayılır — şubesi kapanan kayıtlara başka türlü kimse ulaşamazdı (06 §A).",
|
|
396
|
-
inputSchema: {
|
|
397
|
-
project: projectParam,
|
|
398
|
-
environment: environmentParam,
|
|
399
|
-
entityId: entityRef,
|
|
400
|
-
rowIds: z.array(z.string().min(1)).optional().describe("Devredilecek satırların birincil anahtar değerleri; 'filter' ile birlikte verilmez"),
|
|
401
|
-
filter: rowFiltersParam.describe("Devredilecek satırları seçen Platform Filter dizisi (row_list ile aynı biçim); 'rowIds' ile birlikte verilmez"),
|
|
402
|
-
ownerUnitId: guid.optional().describe("Yeni sahip birim (organization_tree_get); verilmezse ownerUserId'nin birimi yazılır"),
|
|
403
|
-
ownerUserId: guid.optional().describe('Yeni sahip kullanıcı (user_list); verilmezse satırın kullanıcı sahibi olduğu gibi kalır')
|
|
404
|
-
},
|
|
405
|
-
annotations: updates
|
|
406
|
-
}, handle(config, async ({ project, environment, entityId, rowIds, filter, ownerUnitId, ownerUserId }) => {
|
|
407
|
-
if (rowIds?.length && filter?.length)
|
|
408
|
-
throw new Error("row_reassign: 'rowIds' ve 'filter' birlikte verilmez — satırları ya id listesiyle ya filtreyle seçin.");
|
|
409
|
-
if (!rowIds?.length && !filter?.length)
|
|
410
|
-
throw new Error("row_reassign: hedef satır seçilmedi — 'rowIds' ya da 'filter' verin.");
|
|
411
|
-
if (!ownerUnitId && !ownerUserId)
|
|
412
|
-
throw new Error("row_reassign: hedef sahip verilmedi — 'ownerUnitId' ve/veya 'ownerUserId' verin.");
|
|
413
|
-
const resolver = new RefResolver(platform, project, environment);
|
|
414
|
-
const resolvedEntityId = await resolveEntityId(resolver, entityId);
|
|
415
|
-
const body = {
|
|
416
|
-
...(rowIds?.length ? { rowIds } : {}),
|
|
417
|
-
...(filter?.length ? { filter } : {}),
|
|
418
|
-
...(ownerUnitId ? { ownerUnitId } : {}),
|
|
419
|
-
...(ownerUserId ? { ownerUserId } : {})
|
|
420
|
-
};
|
|
421
|
-
return withResolved(await platform.tenant('POST', project, `/entities/${resolvedEntityId}/row/reassign`, { environment, body }), resolver.resolved);
|
|
422
|
-
}));
|
|
423
372
|
server.registerTool('row_export', {
|
|
424
373
|
title: 'Satırları dışa aktar',
|
|
425
374
|
description: "Bir tablonun satırlarını xlsx / csv / json dosyasına yazar ve dosyayı projenin SÜRÜCÜSÜNE ('Dışa aktarmalar' klasörü) koyar; yanıt yalnız fileId ve sayılardır — dosya içeriği ajanın bağlamına HİÇ girmez, içeriği görmek için file_download kullanın. Kapsam üç şekildedir: 'view' (filtre + sıralama), 'all', 'selected' (rowIds). 5.000 satırın üstünde platform işi arka plana alır ve 202 ile jobId döner; import_status { jobId } ile izlenir, biten işin dosyası result.reportFileId'dedir. CSV UTF-8 BOM'lu yazılır; ayraç ve ondalık bir yerel ayar profilinden gelir (tr-TR `;` · `1,5`, en-US `,` · `1.5`): dışa aktarmada projenin dili seçer, şablonda 'locale' ile seçilir. 'reimportable: true' dosyaya id sütununu ve _zeyrek meta sayfasını ekler: dosya düzenlenip import_analyze → import_plan { mode: 'upsert', keyField: 'id' } ile geri yüklenebilir (Akış C). 'template: true' tablo satırı yazmaz: tablonun alanlarından İKİ SENTETİK örnek satırlı bir şablon üretir ve değiştirilmeden geri yüklenebilir. 'template: true, inline: true' şablonun şeklini (sütunlar, anahtar önerisi, iki satır) yanıta da koyar — toplu yazımdan önce dosyanın nasıl görünmesi gerektiğini indirmeden görmenin yolu budur; satır satır row_create yerine şablon başlıklarıyla CSV → file_upload { text } → import_analyze → import_plan → import_run, reçete platform_guide('entity') §'Dışa aktarma ve geri yükleme'.",
|
|
@@ -451,9 +400,6 @@ export function registerRowTools(server, platform) {
|
|
|
451
400
|
if ((scope?.rowIds?.length ?? 0) > maxSelectedRowIds) {
|
|
452
401
|
throw new PlatformApiError(`row_export: ${scope?.rowIds?.length} satır id'si, ${maxSelectedRowIds} sınırının üstünde. Bu kadar satırı seçerek değil filtreyle verin: scope { kind: 'view', filters: [...] }.`);
|
|
453
402
|
}
|
|
454
|
-
const operatorError = filterOperatorError('row_export', scope?.filters);
|
|
455
|
-
if (operatorError)
|
|
456
|
-
throw new PlatformApiError(operatorError, 400);
|
|
457
403
|
const resolvedFormat = format ?? 'xlsx';
|
|
458
404
|
const notes = [];
|
|
459
405
|
const resolver = new RefResolver(platform, project, environment);
|
|
@@ -575,10 +521,8 @@ export function registerRowTools(server, platform) {
|
|
|
575
521
|
throw new Error("'id' ve 'ids' birlikte verilemez.");
|
|
576
522
|
if (!id && !ids)
|
|
577
523
|
throw new Error("'id' ya da 'ids' parametrelerinden biri zorunlu.");
|
|
578
|
-
enforcePolicy(evaluatePolicy(config, policyRules, 'row', { entityId }, { operation: 'delete' }), false);
|
|
579
524
|
const resolver = new RefResolver(platform, project, environment);
|
|
580
525
|
const resolvedEntityId = await resolveEntityId(resolver, entityId);
|
|
581
|
-
resolvedSystemEntityFindings(config, entityId, resolvedEntityId, 'delete');
|
|
582
526
|
if (ids)
|
|
583
527
|
return withResolved(await platform.tenant('POST', project, `/entities/${resolvedEntityId}/row/bulk/delete`, { environment, body: { rowIds: ids } }), resolver.resolved);
|
|
584
528
|
return withResolved(await platform.tenant('DELETE', project, `/entities/${resolvedEntityId}/row/${encodeURIComponent(String(id))}`, { environment }), resolver.resolved);
|
package/dist/tools/schemaOps.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { isFlexContainer, schemaOpValidationErrors, FLEX_LAYOUT_PROP_NAMES, PAGE_CONTAINER_ELEMENT_ID } from '../knowledge/normalize.js';
|
|
2
2
|
import { findNode, outlineAppliedPatch } from './screens.js';
|
|
3
3
|
import { setPropTypeErrors } from '../knowledge/propTypes.js';
|
|
4
|
-
import { connectDataOpIssues } from '../knowledge/connectDataDefinition.js';
|
|
5
4
|
import { PlatformApiError } from '../platform/errors.js';
|
|
6
|
-
import { jsonArray } from '../platform/jsonArray.js';
|
|
7
5
|
import { z } from 'zod';
|
|
8
6
|
/*
|
|
9
7
|
* Şema micro-op'larının gateway tarafı: sayfa (`page_schema_patch`), layout (`layout_schema_patch`)
|
|
@@ -26,7 +24,7 @@ export function outlineWriteResponse(response) {
|
|
|
26
24
|
if (Array.isArray(container.appliedPatch))
|
|
27
25
|
container.appliedPatch = outlineAppliedPatch(container.appliedPatch);
|
|
28
26
|
}
|
|
29
|
-
export const opsParam =
|
|
27
|
+
export const opsParam = z.array(z.record(z.unknown())).describe("Micro-op listesi. Op sözlüğü: replace_prop {target, prop, value} (value ham değer, code sarmalı {type: 'code', ref: '{{ … }}'} ya da translation sarmalı {type: 'translation', ref: '<çeviri anahtarı>'} — prop tipini değiştirmek için komponenti silip yeniden EKLEMEYİN, ona yazan setter'ların hedefi silinir (FLOW-018); platform replace_prop'ta expression alanını OKUMAZ — gateway onu code sarmalına çevirir) | set_binding {target, prop, expression: '{{ Page.variables.x }}'} | add_component {parent (üst elementId ya da 'root'), index?, component} | remove_component {target} | move_component {target, parent, index?, position: {x, y}} (index ÇİZİM sırası değildir, runtime çocukları blocks.position'a göre (y, sonra x) çizer. page_schema_patch'te flex kapta gateway index'i görünen sıraya çevirir ve kardeş konumlarını yeniden yazar; ızgara kapta sırayı position.y verir, sona eklemeyen index PAGE-033 uyarısıdır. layout_schema_patch ve component_schema_patch bu çeviriyi YAPMAZ: orada sırayı position.y ile verin) | set_event {target, event, eventValue, replaceBoundFlows?} (olayın BÜTÜN bağlarını bu tek akışa indirir; olayda başka akış bağlıysa gateway PAGE-034 ile reddeder — bilerek değiştirmek için replaceBoundFlows: true) | add_event {target, event, eventValue} (olaya bir akış DAHA bağlar; bağlı akışların hepsi paralel ve birbirinden bağımsız koşar, sıra garantisi yoktur — sıra gerekiyorsa flow-trigger. Aynı akış iki kez 422 duplicate-event. Mobil runtime yalnız İLK akışı koşar) | remove_event {target, event, eventValue?} (olayı diziden çıkarır; target: 'page' sayfa düzeyi olaylar. Olaya birden fazla akış bağlıysa eventValue ile hangisi olduğunu verin, yoksa 422 ambiguous-event. set_event ile eventValue: null olay SİLMEZ, değersiz ölü kayıt bırakır. Olmayan olay 422 missing-event) | set_validations {target, validations: [{type, message, value, isActive}]} (komponentin validation listesini TAMAMEN değiştirir; boş dizi hepsini siler) | set_appearance {target, appearance: {heightType?, widthType?, tooltip?, background?, …}} (kurulu düğümün appearance'ına YALNIZ verilen alanları yazar, gerisini korur; null alanı temizler; bilinmeyen alan unknown-appearance-field ile reddedilir. GÖRÜNÜRLÜK appearance'ta DEĞİLDİR: gizlemek için replace_prop {target, prop: 'isHidden', value: true}, koşul için set_binding {prop: 'isHidden'} — add_component gövdesindeki appearance.isHidden'ı gateway props.isHidden'a taşır) | resize_component {target, size?: {w,h}, appearance?: {widthType,widthString,heightType,heightString}, states?: {isWrapper,isScrollable,isSticky,isDroppable,isFloating,isQuickStack}, breakpoint?: 1024} (gateway adı: platforma set_block {target, breakpoint, size} + set_appearance {target, appearance} + set_states {target, states} olarak gider — o üç op'u doğrudan da gönderebilirsiniz. move_component'e konan size reddedilir. Izgarada blocks[].size, flex'te appearance geçerlidir; ebeveynin düzeni yazılanı etkisiz kılıyorsa PAGE-019 uyarısı çıkar. states bir PROP DEĞİL düğüm alanıdır ve replace_prop onu yazamaz — düğümü silmeden isWrapper bayrağını değiştirmenin yolu budur). set_prop_type {target, prop, propType: 'static'|'code'|'translation', ref?, data?} (replace_prop sarmalıyla aynı sonucu verir ve mevcut data'yı tasarım yedeği olarak taşır. Bu op prop'un TİPİNİ yerinde değiştirir. Taşıyıcı alan tipe göre: static → data, code ve translation → ref (runtime data'yı her turda ezer, anahtar yalnız ref'te yaşar). Eksik taşıyıcı istek gönderilmeden reddedilir; page_schema_validate aynı kararı verir) | reorder {parent ('root' ya da elementId), order: [çocuk elementId'lerinin TAMAMI, yeni sırada]} (yalnız DİZİ sırasını değiştirir; çizim sırası blocks.position'dır — görünen sırayı değiştirmek için konumları set_block/move_component ile de yazın) | set_state_binding {target, binding: {name, expression, targets}} (ada göre ekler/değiştirir) | remove_state_binding {target, name} | batch {gestureId?, label?, ops: [...]} (iç içe batch yok). target = elementId. İstek atomiktir: tek op reddedilirse hiçbiri yazılmaz.");
|
|
30
28
|
/**
|
|
31
29
|
* PAGE-008 — `set_event` uydurma bir olay adıyla 200 döner ve bağ SESSİZCE ölü kalır: motor olayı
|
|
32
30
|
* komponentin yaydığı adla eşleştirir, eşleşme yoksa akış hiç çalışmaz. Kontrol yalnız hedefin
|
|
@@ -69,29 +67,6 @@ export function collectTypes(nodes, into) {
|
|
|
69
67
|
collectTypes(node.children, into);
|
|
70
68
|
}
|
|
71
69
|
}
|
|
72
|
-
/**
|
|
73
|
-
* TB-129 — `replace_prop` yalnız elementId taşır; stil anahtarı çevirisinin komponent TİPİNE
|
|
74
|
-
* bakabilmesi için hedeflerin tipi okunan ağaçtan çıkarılır. Harita YALNIZ `style` prop'u yazan
|
|
75
|
-
* bir op varsa kurulur: başka türlü fazladan bir okuma maliyeti doğardı.
|
|
76
|
-
*/
|
|
77
|
-
export function styleTargetTypesFrom(ops, nodes) {
|
|
78
|
-
if (!ops.some(entry => entry.op === 'replace_prop' && String(entry.prop ?? '') === 'style'))
|
|
79
|
-
return undefined;
|
|
80
|
-
const types = new Map();
|
|
81
|
-
collectTypes(nodes, types);
|
|
82
|
-
return types;
|
|
83
|
-
}
|
|
84
|
-
/** Aynı harita, ağacı tembel okuyan yazma yolu için; okuma düşerse çeviri eski davranışa döner. */
|
|
85
|
-
export async function styleTargetTypes(ops, readHost) {
|
|
86
|
-
if (!ops.some(entry => entry.op === 'replace_prop' && String(entry.prop ?? '') === 'style'))
|
|
87
|
-
return undefined;
|
|
88
|
-
try {
|
|
89
|
-
return styleTargetTypesFrom(ops, (await readHost()).schema);
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return undefined;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
70
|
export function removeNodeFromTree(nodes, target, parent) {
|
|
96
71
|
for (let index = 0; index < nodes.length; index++) {
|
|
97
72
|
if (nodes[index].elementId === target)
|
|
@@ -297,44 +272,9 @@ export function assertOpBodies(opRecords, propTypeOps) {
|
|
|
297
272
|
if (sizedMoves.length > 0) {
|
|
298
273
|
throw new PlatformApiError(`move_component yalnız 'position' uygular; gövdeye konan 'size' platformda SESSİZCE düşer (ölçüldü 2026-09-04, appliedPatch'te yalnız /blocks/0/position görünür). Boyut için resize_component kullanın: { op: 'resize_component', target: '<elementId>', size: { w, h } } — flex kapsayıcı içindeyse 'appearance'. Etkilenen hedefler: ${sizedMoves.map(entry => entry.target).join(' · ')}`, 400);
|
|
299
274
|
}
|
|
300
|
-
const connectDataIssues = opRecords.flatMap(entry => connectDataOpIssues(entry).map(issue => `${issue.code} — ${issue.message}`));
|
|
301
|
-
if (connectDataIssues.length > 0)
|
|
302
|
-
throw new PlatformApiError(`Connect Data op gövdesi geçersiz (istek gönderilmedi): ${connectDataIssues.join(' · ')}`, 400);
|
|
303
275
|
const validationIssues = schemaOpValidationErrors(opRecords);
|
|
304
276
|
if (validationIssues.length > 0) {
|
|
305
277
|
throw new PlatformApiError(`PAGE-016 — validation gövdesi eksik (istek gönderilmedi): ${validationIssues.join(' · ')}. `
|
|
306
278
|
+ "Çalışan biçim dört alanı da taşır: { type: 'required'|'email'|'regex'|'max-length'|'min-length'|'max-value'|'min-value'|'value-options', message: '<kullanıcıya görünen metin>', value: <eşik/desen/true>, isActive: true }.", 400);
|
|
307
279
|
}
|
|
308
280
|
}
|
|
309
|
-
/** İskelet kurallarının okuduğu prop'lar (düzen grubu dışında). */
|
|
310
|
-
const SKELETON_PROPS = new Set(['edges', 'horizontal', 'refreshable', 'stickyHeader', 'isHidden']);
|
|
311
|
-
/** Yama iskeleti değiştirebilir mi: yalnız o zaman kabuk okunur ve fark hesaplanır. */
|
|
312
|
-
export function reshapesSkeleton(ops) {
|
|
313
|
-
return ops.some(entry => ['add_component', 'move_component', 'remove_component', 'set_appearance', 'set_states'].includes(String(entry.op))
|
|
314
|
-
|| ((entry.op === 'replace_prop' || entry.op === 'set_binding') && (FLEX_LAYOUT_PROP_NAMES.has(String(entry.prop ?? '')) || SKELETON_PROPS.has(String(entry.prop ?? '')))));
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* `simulateLayoutOps`'un uygulamadığı ama iskeleti değiştiren op'lar: silme, görünüm, durum bayrakları ve
|
|
318
|
-
* iskelet prop'ları. Uygulanmasa yama "sabit boy verilen scroll-view"ü gerekçesiz, silinen app-bar'ı ikinci
|
|
319
|
-
* sayardı.
|
|
320
|
-
*/
|
|
321
|
-
export function applySkeletonOps(tree, ops) {
|
|
322
|
-
for (const entry of ops) {
|
|
323
|
-
const target = String(entry.target ?? '');
|
|
324
|
-
if (entry.op === 'remove_component')
|
|
325
|
-
removeNodeFromTree(tree, target);
|
|
326
|
-
if (entry.op === 'set_appearance' || entry.op === 'set_states') {
|
|
327
|
-
const node = findNode(tree, target);
|
|
328
|
-
const field = entry.op === 'set_appearance' ? 'appearance' : 'states';
|
|
329
|
-
const patch = entry[field];
|
|
330
|
-
if (node && patch && typeof patch === 'object')
|
|
331
|
-
node[field] = { ...node[field], ...patch };
|
|
332
|
-
}
|
|
333
|
-
if ((entry.op === 'replace_prop' || entry.op === 'set_binding') && SKELETON_PROPS.has(String(entry.prop ?? ''))) {
|
|
334
|
-
const node = findNode(tree, target);
|
|
335
|
-
const value = entry.op === 'set_binding' ? { type: 'code', ref: entry.expression } : entry.value;
|
|
336
|
-
if (node)
|
|
337
|
-
node.props = { ...node.props, [String(entry.prop)]: value && typeof value === 'object' ? value : { type: 'static', data: value } };
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|