@appaflytech/zeyrek-ai-mcp 0.0.41 → 0.0.43
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/dist/knowledge/componentCatalog.js +27 -97
- package/dist/knowledge/componentEvents.js +1 -18
- package/dist/knowledge/mobileComponentCatalog.js +114 -15
- package/dist/knowledge/mobileComponentEvents.js +41 -0
- package/dist/knowledge/motionResolve.js +252 -0
- package/dist/knowledge/normalize.js +87 -59
- package/dist/knowledge/pageDiscover.js +2 -2
- package/dist/knowledge/platform/batchOps.js +70 -0
- package/dist/knowledge/platform/heroTag.js +153 -0
- package/dist/knowledge/platform/lint.js +128 -6
- package/dist/knowledge/platform/mobile.js +1 -1
- package/dist/knowledge/platform/mobileLayoutLint.js +8 -1
- package/dist/knowledge/platform/mobileRules.js +18 -0
- package/dist/knowledge/platform/pageTransition.js +57 -0
- package/dist/knowledge/platform/web.js +1 -1
- package/dist/knowledge/rules.js +52 -1
- package/dist/knowledge/styleResolveNative.js +88 -4
- package/dist/platform/capture/actions.js +4 -1
- package/dist/platform/capture/capture.js +10 -13
- package/dist/platform/capture/persistent-browser.js +130 -0
- package/dist/resources/examples/flow-list-to-form.json +8 -10
- package/dist/resources/examples/flow-load-table.json +1 -1
- package/dist/resources/examples/mobile-list-detail-form.json +4 -3
- package/dist/resources/examples/mobile-scan-code.json +285 -0
- package/dist/resources/guides/component.md +3 -3
- package/dist/resources/guides/expressions.md +2 -2
- package/dist/resources/guides/merge.md +98 -18
- package/dist/resources/guides/microservice.md +2 -2
- package/dist/resources/guides/mobile-layout.md +2 -1
- package/dist/resources/guides/mobile-publish.md +1 -0
- package/dist/resources/guides/mobile-steps.md +67 -0
- package/dist/resources/guides/mobile.md +27 -55
- package/dist/resources/guides/page.md +182 -121
- package/dist/resources/guides/translation.md +26 -0
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/ResolveMergeConflictsCommand.json +30 -1
- package/dist/tools/activities.js +3 -1
- package/dist/tools/applications.js +16 -2
- package/dist/tools/components.js +12 -6
- package/dist/tools/designSchemaPatch.js +18 -13
- package/dist/tools/layouts.js +7 -2
- package/dist/tools/merges.js +29 -9
- package/dist/tools/pages.js +129 -127
- package/dist/tools/platformInfo.js +3 -2
- package/dist/tools/profileWrite.js +2 -2
- package/dist/tools/schemaOps.js +132 -34
- package/dist/tools/screenWrite.js +1 -1
- package/dist/tools/screens.js +3 -3
- package/package.json +2 -2
package/dist/tools/pages.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { guid, projectParam, environmentParam, pagingParams, asUserIdParam, readOnly, writes, updates, destructive, microOps, isBranchName, branchSlug } from './common.js';
|
|
2
|
-
import { orphanedFlowWarnings, orphanedFlowPlan, orphanedFlowMessage, boundEventOps, stripGatewayEventFields, staleSetterWarnings, lostSetterTargets, fillComponentNames, componentNameNote, normalizeComponentDefaults, normalizeSchemaOps, schemaOpValidationErrors, codePropTemplateErrors, addComponentIdErrors, missingBlocksNodes,
|
|
2
|
+
import { orphanedFlowWarnings, orphanedFlowPlan, orphanedFlowMessage, boundEventOps, stripGatewayEventFields, staleSetterWarnings, lostSetterTargets, fillComponentNames, componentNameNote, normalizeComponentDefaults, normalizeSchemaOps, schemaOpValidationErrors, codePropTemplateErrors, addComponentIdErrors, missingBlocksNodes, retiredTypeNodes, assertNoRetiredNodes, validationNote, componentDefaultsNote, replacePropNote, ensurePageContainer, retargetRootAdds, rootAddsNote, flexSizeWarnings, spacingLayerWarnings, reorderSchemaBlocks, reorderNote, nestedRepeaterNodes, nestedRepeaterMessage, stringStyleNodes, stringStyleWarning, inertFlexPropNodes, inertFlexPropWarning, FLEX_LAYOUT_PROP_NAMES, resetPageContainerPosition, pageContainerPositionWarning, verticalGapWarnings, flexIndexOrder, flexIndexOrderNote, withNormalization, parseVariableEntries, PAGE_CONTAINER_ELEMENT_ID, screenEventsNeedPlatform } from '../knowledge/normalize.js';
|
|
3
3
|
import { functionSignature } from '../knowledge/functionGuards.js';
|
|
4
4
|
import { attachFindings } from '../knowledge/policy.js';
|
|
5
5
|
import { fetchHost, pageUpdateBody, schemaParam, eventsParam, unwrap, modeParam, summarize, findNode, flowPath, countSchemaNodes, missingElementIds, readFullSchema } from './screens.js';
|
|
6
6
|
import { fetchComponentEventNames } from './components.js';
|
|
7
|
-
import {
|
|
8
|
-
import { opsParam, writeViewParam, outlineWriteResponse, unknownEventOps, collectTypes,
|
|
7
|
+
import { assertScreenWriteGuards, screenCatalogNotes, assertScreenCatalog } from './screenWrite.js';
|
|
8
|
+
import { opsParam, writeViewParam, outlineWriteResponse, unknownEventOps, collectTypes, simulateLayoutOps, applySkeletonOps, reshapesSkeleton, planEventRemovals, callerSlots, planEmulatedOps, recordsWithEventRemovals, serverOpsInOrder, rejectedOpsMessage } from './schemaOps.js';
|
|
9
9
|
import { formBindingWarnings, formSubmitButtonWarnings } from '../knowledge/coverage.js';
|
|
10
10
|
import { emptyWriteDiff, schemaOpDrops, unwrapProps, withWriteDiff, writeDiff } from '../platform/writeDiff.js';
|
|
11
11
|
import { PlatformApiError } from '../platform/errors.js';
|
|
@@ -30,6 +30,9 @@ import { boxSectionNote, collectIds, ensureBoxSections, expandSectionToggles } f
|
|
|
30
30
|
import { designSnapshotInput } from '../knowledge/designSnapshot.js';
|
|
31
31
|
import { discoverPage } from '../knowledge/pageDiscover.js';
|
|
32
32
|
import { applicationTypeField, resolveProfile, resolveProfileBySlug } from '../knowledge/platform/resolve.js';
|
|
33
|
+
import { batchEnvelopeNote, batchIndexHint, openBatchEnvelopes } from '../knowledge/platform/batchOps.js';
|
|
34
|
+
import { heroTags } from '../knowledge/platform/heroTag.js';
|
|
35
|
+
import { profileLintReadsSavedNodes } from '../knowledge/platform/lint.js';
|
|
33
36
|
import { resolveThemeNative } from '../knowledge/styleResolveNative.js';
|
|
34
37
|
import { boundFlowSteps, pageLayoutWarnings, screenProfileWarnings } from './profileWrite.js';
|
|
35
38
|
import { applyMobileSpacingDefaults, applyMobileSpacingToOps, emptyMobileSpacingFix, mobileSpacingNote } from '../knowledge/platform/mobileSpacing.js';
|
|
@@ -76,7 +79,8 @@ async function fetchPage(platform, project, environment, applicationId, pageId)
|
|
|
76
79
|
* Platformun sayfa micro-op sözlüğü (`PageSchemaMicroOpApplier.KnownOps`). Gateway'in sunucuya
|
|
77
80
|
* ilettiği op'lar yalnız bunlardır; `test/page-micro-op-parity.test.ts` listeyi backend ve
|
|
78
81
|
* `@ng-apps/screen-builder` ile karşılaştırır. `resize_component` gateway adıdır ve sunucuya
|
|
79
|
-
* `set_block` + `set_appearance` + `set_states` olarak çevrilir.
|
|
82
|
+
* `set_block` + `set_appearance` + `set_states` olarak çevrilir. `batch` sözlüktedir ama iletilmez:
|
|
83
|
+
* zarf araç girişinde açılır (PAGE-048).
|
|
80
84
|
*/
|
|
81
85
|
export const SERVER_PAGE_OPS = [
|
|
82
86
|
'replace_prop', 'set_binding', 'set_prop_type', 'add_component', 'remove_component', 'move_component', 'reorder', 'set_block',
|
|
@@ -171,7 +175,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
171
175
|
}));
|
|
172
176
|
server.registerTool('page_runtime_get', {
|
|
173
177
|
title: 'Sayfanın runtime çıktısını getir',
|
|
174
|
-
description: "Çıkan uygulamanın sayfa için aldığı GERÇEK paketi döner (GET /{project}/{application}/p/{slug} — sayfanın ham serve yolu budur; Studio preview ve runtime aynı ucu tüketir): sayfa şeması + layout views'ü + sayfa olayları + flow'lar + değişken anahtarları (variableKeys: middleware değişkenleri, pageVariableKeys/appVariableKeys: state.page/state.app anahtarları) + kullanıcı fonksiyonu imzaları (appFunctions/pageFunctions — bir ifadeye Functions.<ad>(…) yazmadan önce adı ve parametre sırasını buradan alın; gövde taşınmaz, function_get ile okunur). Kurduğun sayfanın SON hâlini doğrulamanın yolu budur (layout-slot yerleşimi dahil — Kural 1f). DİKKAT: sayfaya bağlı middleware'ler bu çağrıda GERÇEKTEN koşar; middleware reddederse yanıt middlewareBlocked ile döner — korumalı sayfada bu beklenen davranıştır ve kendisi bir doğrulamadır. Kompleks projede yanıta 'accessDecision' eklenir (allow | deny | not-enforced | unknown, mode, izin, reason, next): sayfa reddi page.view kararından mı geldi, sıradaki adım ne.",
|
|
178
|
+
description: "Çıkan uygulamanın sayfa için aldığı GERÇEK paketi döner (GET /{project}/{application}/p/{slug} — sayfanın ham serve yolu budur; Studio preview ve runtime aynı ucu tüketir): sayfa şeması + layout views'ü + sayfa olayları + flow'lar + değişken anahtarları (variableKeys: middleware değişkenleri, pageVariableKeys/appVariableKeys: state.page/state.app anahtarları) + kullanıcı fonksiyonu imzaları (appFunctions/pageFunctions — bir ifadeye Functions.<ad>(…) yazmadan önce adı ve parametre sırasını buradan alın; gövde taşınmaz, function_get ile okunur). Kurduğun sayfanın SON hâlini doğrulamanın yolu budur (layout-slot yerleşimi dahil — Kural 1f). DİKKAT: sayfaya bağlı middleware'ler bu çağrıda GERÇEKTEN koşar; middleware reddederse yanıt middlewareBlocked ile döner — korumalı sayfada bu beklenen davranıştır ve kendisi bir doğrulamadır. Kompleks projede yanıta 'accessDecision' eklenir (allow | deny | not-enforced | unknown, mode, izin, reason, next): sayfa reddi page.view kararından mı geldi, sıradaki adım ne. Mobil sayfada heroTag taşıyan düğümler `heroTags`'te listelenir (layout'unkiler dahil; statik etiket metniyle, ifadeye bağlı olan `bound: true` ile): paylaşılan öğe çiftini kurarken iki sayfanın özetini buradan karşılaştırın (platform_guide('page') §Kural 1g-3).",
|
|
175
179
|
inputSchema: {
|
|
176
180
|
project: projectParam,
|
|
177
181
|
environment: environmentParam,
|
|
@@ -224,6 +228,9 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
224
228
|
const nativeTheme = resolveStyles && runtimeApplication.type === 'mobile' ? resolveThemeNative((theme ?? undefined)) : undefined;
|
|
225
229
|
// Mobilde de tema katmanı (componentStyles ← $preset) çizerin tabanıdır (f-16); rapor aynı kaynağı okur.
|
|
226
230
|
const nodeStyleSource = styleSource;
|
|
231
|
+
// Paylaşılan öğe etiketleri (frontend ADR 0022, MOB-030): iki sayfanın özeti karşılaştırılarak çift kurulur.
|
|
232
|
+
// Layout'un düğümleri de cihazda çizilir (başlıktaki logo); listede önce onlar gelir.
|
|
233
|
+
const pageHeroTags = runtimeApplication.type === 'mobile' ? [...heroTags(layout?.views), ...heroTags(body.schema)] : [];
|
|
227
234
|
return {
|
|
228
235
|
...(decision ? { accessDecision: decision } : {}),
|
|
229
236
|
page: { id: body.id, name: body.name, slug: body.slug, browserTitle: body.browserTitle, browserTitleKey: body.browserTitleKey, isHomepage: body.isHomepage },
|
|
@@ -231,6 +238,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
231
238
|
events: body.events ?? [],
|
|
232
239
|
layout: layout ? { id: layout.id, name: layout.name, views: asNodes(layout.views).map(node => summarize(node, nodeStyleSource, nativeTheme)) } : null,
|
|
233
240
|
schema: asNodes(body.schema).map(node => summarize(node, nodeStyleSource, nativeTheme)),
|
|
241
|
+
...(pageHeroTags.length > 0 ? { heroTags: pageHeroTags } : {}),
|
|
234
242
|
...(nativeTheme ? { styleResolver: 'native' } : {}),
|
|
235
243
|
widgets: named(body.widgets),
|
|
236
244
|
flows: named(body.flows),
|
|
@@ -251,7 +259,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
251
259
|
}
|
|
252
260
|
: {}),
|
|
253
261
|
note: nativeTheme
|
|
254
|
-
? "Mobil uygulama: nativeStyle, mobil çizerin düğüme verdiği React Native stilidir — shell kutunun, text içine akan metnin stili (RN'de tipografi miras alınmaz); warnings mobilde çizilmeyen değerlerdir (MOB-002). Tema componentStyles ← $preset katmanı TABANDIR (panel grupları üstüne biner, serbest style son söz); mobil katalogda style prop'u olmadığı için $preset'e yeni başvuru yazılamaz, componentStyles tipin bütün düğümlerine iner."
|
|
262
|
+
? "Mobil uygulama: nativeStyle, mobil çizerin düğüme verdiği React Native stilidir — shell kutunun, text içine akan metnin stili (RN'de tipografi miras alınmaz); warnings mobilde çizilmeyen değerlerdir (MOB-002; hareket alanları MOB-028). bound (yalnız varsa) değeri çalışma anında oluşan, ifadeye bağlı stil alanlarıdır (<grup>.<alan>) — stile girmezler. motion (yalnız hareketli düğümde) motionStyle'ın /dev ve cihazdaki çözümüdür; kanvas ve page_screenshot'ın donuk karesi uygulamaz. Tema componentStyles ← $preset katmanı TABANDIR (panel grupları üstüne biner, serbest style son söz); mobil katalogda style prop'u olmadığı için $preset'e yeni başvuru yazılamaz, componentStyles tipin bütün düğümlerine iner."
|
|
255
263
|
: resolveStyles
|
|
256
264
|
? "schema, layout'taki slot'un İÇİNE yerleşerek çizilir (Kural 1f). resolvedStyle = componentStyles → preset → düğüm stili kaskadı (aibox'ta tipli grupların derlemesi TABAN katmandır); styleLayers hangi katmanların konuştuğunu söyler — styleLayers.componentPreset ise CSS DEĞİL, düğümün hangi bileşen preseti versiyonundan kurulduğunun işaretidir."
|
|
257
265
|
: "schema, layout'taki slot'un İÇİNE yerleşerek çizilir (Kural 1f); tam gövde gerekirse view:'full'. Bir düğümün ekranda GERÇEKTEN aldığı stili görmek için resolveStyles:true."
|
|
@@ -692,98 +700,20 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
692
700
|
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, pageId: guid },
|
|
693
701
|
annotations: readOnly
|
|
694
702
|
}, handle(config, ({ project, environment, applicationId, pageId }) => platform.tenant('GET', project, `/pages/${applicationId}/${pageId}/ai-context`, { environment })));
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
const
|
|
708
|
-
const
|
|
709
|
-
// ARC-143: kuru koşu page_schema_patch'in add_component kapısını (PAGE-009 · 011 · 012 · 013)
|
|
710
|
-
// atlıyordu; ayrılmış adlı komponent validate'ten geçip yamada reddediliyordu.
|
|
711
|
-
assertScreenWriteGuards('page', { schema: opRecords.filter(entry => entry.op === 'add_component').map(entry => entry.component) }, resolved.profile.platform);
|
|
712
|
-
const readPage = () => fetchPage(platform, project, environment, applicationId, pageId);
|
|
713
|
-
const normalized = normalizeSchemaOps(opRecords, await styleTargetTypes(opRecords, readPage));
|
|
714
|
-
const added = opRecords.filter(entry => entry.op === 'add_component').map(entry => entry.component).filter(Boolean);
|
|
715
|
-
// page_schema_patch'in sırası: kimlik ve blocks op başına (PAGE-037), sonra ad (PAGE-009).
|
|
716
|
-
assertAddComponentIds(opRecords);
|
|
717
|
-
assertComponentBlocks(added);
|
|
718
|
-
assertComponentNames('page', added);
|
|
719
|
-
const validationIssues = [
|
|
720
|
-
...schemaOpValidationErrors(opRecords).map(issue => `PAGE-016 — ${issue}`),
|
|
721
|
-
...codePropTemplateErrors(opRecords).map(issue => `PAGE-032 — ${issue}`)
|
|
722
|
-
];
|
|
723
|
-
const spacing = await mobileSpacingForOps(resolved.profile.platform, opRecords, () => fetchPage(platform, project, environment, applicationId, pageId));
|
|
724
|
-
const ordering = resolved.profile.layout.orderBy === 'block-position'
|
|
725
|
-
? await orderByIndex(opRecords, () => fetchPage(platform, project, environment, applicationId, pageId))
|
|
726
|
-
: { ops: opRecords, moved: [], warnings: [] };
|
|
727
|
-
const writesStyle = resolved.profile.platform !== 'web' && opRecords.some(entry => (entry.op === 'replace_prop' || entry.op === 'set_binding') && entry.prop === 'style');
|
|
728
|
-
const profileWarnings = await screenProfileWarnings(platform, resolved, project, environment, applicationId, {
|
|
729
|
-
kind: 'page',
|
|
730
|
-
ops: opRecords,
|
|
731
|
-
savedNodes: writesStyle ? await fetchPage(platform, project, environment, applicationId, pageId).then(page => page.schema, () => undefined) : undefined
|
|
732
|
-
});
|
|
733
|
-
// page_schema_patch'in Connect Data duvarı kuru koşuda da koşar: patch'in reddedeceği op burada görünür.
|
|
734
|
-
const connectedProps = opRecords.some(entry => ['set_binding', 'set_prop_type', 'replace_prop', 'set_connect_data', 'remove_connect_data'].includes(String(entry.op)))
|
|
735
|
-
? await fetchPage(platform, project, environment, applicationId, pageId).then(page => connectedPropKeys(page.schema), () => null)
|
|
736
|
-
: null;
|
|
737
|
-
const connectDataRejections = opRecords.flatMap((entry, index) => connectDataOpIssues(entry, connectedProps).map(issue => ({
|
|
738
|
-
index,
|
|
739
|
-
op: String(entry.op ?? ''),
|
|
740
|
-
target: typeof entry.target === 'string' ? entry.target : null,
|
|
741
|
-
code: issue.code,
|
|
742
|
-
message: issue.message
|
|
743
|
-
})));
|
|
744
|
-
// Yazmadaki gibi katalog kuralları GİDEN listeye: kuru koşu kırpılmamış boyutu doğrulayıp
|
|
745
|
-
// yazmanın geçireceği gövdeye hata veriyor, notu da vermiyordu (Y-13 C).
|
|
746
|
-
const catalogNotes = await screenCatalogNotes(platform, project, environment, applicationId, ordering.ops.filter(entry => entry.op === 'add_component').map(entry => entry.component));
|
|
747
|
-
const response = ((await platform.tenant('POST', project, `/pages/${applicationId}/${pageId}/schema/validate`, {
|
|
748
|
-
environment,
|
|
749
|
-
body: { ops: [...allOps.filter(entry => entry.op === 'resize_component').flatMap(resizeServerOps), ...ordering.ops] }
|
|
750
|
-
})) ?? {});
|
|
751
|
-
const skeletonWarnings = await simulatedPageLayoutWarnings(platform, resolved, project, environment, applicationId, () => fetchPage(platform, project, environment, applicationId, pageId), opRecords, 'audit');
|
|
752
|
-
if (validationIssues.length > 0)
|
|
753
|
-
response.validationWarnings = validationIssues;
|
|
754
|
-
if (ordering.warnings.length > 0 || profileWarnings.length > 0 || skeletonWarnings.length > 0)
|
|
755
|
-
response.layoutWarnings = [...ordering.warnings, ...profileWarnings, ...skeletonWarnings];
|
|
756
|
-
if (connectDataRejections.length > 0)
|
|
757
|
-
response.rejectedOps = connectDataRejections;
|
|
758
|
-
Object.assign(response, applicationTypeField(resolved));
|
|
759
|
-
return withNormalization(response, [
|
|
760
|
-
...componentNameNote(normalized.names),
|
|
761
|
-
...componentDefaultsNote(normalized.components),
|
|
762
|
-
...validationNote(normalized.validations),
|
|
763
|
-
...catalogNotes,
|
|
764
|
-
...replacePropNote(normalized.props),
|
|
765
|
-
...flexIndexOrderNote(ordering.moved),
|
|
766
|
-
...mobileSpacingNote(spacing)
|
|
767
|
-
]);
|
|
768
|
-
}));
|
|
769
|
-
server.registerTool('page_schema_patch', {
|
|
770
|
-
title: 'Sayfa şemasına patch uygula',
|
|
771
|
-
description: "Micro-op'ları doğrulama duvarından geçirip TEK PATCH ile kaydeder; açık studio canvas'ları SignalR ile canlı güncellenir. İstek atomiktir: bir op reddedilirse hiçbiri yazılmaz. baseVersion (page_schema_get çıktısındaki version ya da önceki yamanın newVersion'ı) verilirse sayfa o sürümden beri değişmişse 409 döner ve hiçbir op uygulanmaz (stale plan koruması); verilmezse gateway yalnız bu çağrıda zaten okuduğu sayfanın sürümünü gönderir. Yanıttaki appliedPatch, her op'un şemada tam olarak hangi JSON Pointer'a dokunduğunu söyler; gövdesi VARSAYILAN OLARAK iskelettir (eklenen düğüm id/type/children'a iner) — tam gövde için view:'full'. Op'un gerçekten kaydedilip kaydedilmediğini gövde değil silentlyDropped söyler. Gateway ön kontrolleri (PAGE-006/008/016/032, set_prop_type gövdesi, move_component size) op başına toplanır: düşen HER op tek hata yanıtında rejectedOps[] ({ index, op, target, code, message }) ile listelenir ve hiçbir op gönderilmez — hepsini düzeltip listeyi bir kez yeniden gönderin.",
|
|
772
|
-
inputSchema: {
|
|
773
|
-
project: projectParam,
|
|
774
|
-
environment: environmentParam,
|
|
775
|
-
applicationId: guid,
|
|
776
|
-
pageId: guid,
|
|
777
|
-
ops: opsParam.optional(),
|
|
778
|
-
operations: opsParam.optional().describe("'ops' ile aynı alan (eşanlamlı) — entity/microservice/workflow patch'leriyle aynı adı kullanabilmeniz için"),
|
|
779
|
-
baseVersion: z.string().optional().describe("page_schema_get çıktısındaki version ya da önceki page_schema_patch yanıtındaki newVersion; sayfa o sürümden beri değiştiyse 409 döner ve hiçbir op uygulanmaz"),
|
|
780
|
-
expectedUpdatedAt: z.string().optional().describe("Eski koruma: page_schema_get çıktısındaki updatedAt; eşleşmezse patch uygulanmaz. baseVersion tercih edilir"),
|
|
781
|
-
allowFlowDeletion: z.boolean().optional().describe("true: bu yama bir akışı referanssız bırakacaksa yine de uygulanır. Varsayılan false — platform referanssız akışı KALICI siler ve gateway isteği önden reddeder (G-21). Silinen akışlar yanıtta deletedFlows ile listelenir."),
|
|
782
|
-
view: writeViewParam
|
|
783
|
-
},
|
|
784
|
-
annotations: updates
|
|
785
|
-
}, handle(config, async ({ project, environment, applicationId, pageId, ops, operations, baseVersion, expectedUpdatedAt, allowFlowDeletion, view }) => {
|
|
786
|
-
const allOps = microOps('page_schema_patch', ops, operations).map(op => op);
|
|
703
|
+
/**
|
|
704
|
+
* Sayfa şemasına yazımın PLANI — `page_schema_patch` ve `page_schema_validate` aynısını koşar: ön kontroller, onarım,
|
|
705
|
+
* öykünülen op'ların çevrilmesi, platforma gidecek liste, uyarılar. Kuru koşu yazımla AYNI kararı verir (yazımın
|
|
706
|
+
* reddedeceği yamayı aynı mesajla reddeder) ve platforma AYNI gövdeyi doğrulatır; fark yalnız gönderilen istekte.
|
|
707
|
+
*
|
|
708
|
+
* İki işleyici ayrı yazılmıştı ve ayrışmıştı (TOOL-059, ölçüldü 2026-10-10, gerçek uç): kuru koşu
|
|
709
|
+
* `remove_component page_container`'a `valid: true` diyor, yazım aynı op'u PAGE-006 ile reddediyordu; kuru koşu
|
|
710
|
+
* PAGE-034 · PAGE-008 · MOVE-SIZE kapılarını, akış silme planını (G-21), yama sonrası iç içe tekrarlayıcıyı (PAGE-013),
|
|
711
|
+
* kök eklemenin taşınmasını ve `resize_component` planını da koşmuyordu. Emsal: ARC-143, `page-meta.test.ts`
|
|
712
|
+
* "validate = yazma". Regresyon: `test/page-dry-run-parity.test.ts`.
|
|
713
|
+
*/
|
|
714
|
+
const planPageWrite = async (tool, { project, environment, applicationId, pageId, ops, operations, expectedUpdatedAt, allowFlowDeletion }) => {
|
|
715
|
+
const opened = openBatchEnvelopes(tool, microOps(tool, ops, operations).map(op => op));
|
|
716
|
+
const allOps = opened.ops;
|
|
787
717
|
const removeEventOps = allOps.filter(entry => entry.op === 'remove_event');
|
|
788
718
|
const resizeOps = allOps.filter(entry => entry.op === 'resize_component');
|
|
789
719
|
const propTypeOps = allOps.filter(entry => entry.op === 'set_prop_type');
|
|
@@ -826,14 +756,16 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
826
756
|
const toggles = expandSectionToggles(opRecords, schema, taken);
|
|
827
757
|
sectionNotes = boxSectionNote([...created, ...toggles.created], toggles.removed);
|
|
828
758
|
}
|
|
829
|
-
const normalized = normalizeSchemaOps(opRecords
|
|
759
|
+
const normalized = normalizeSchemaOps(opRecords);
|
|
830
760
|
for (const entry of opRecords)
|
|
831
761
|
reject('PAGE-016', entry, schemaOpValidationErrors([entry]));
|
|
832
762
|
for (const entry of opRecords)
|
|
833
763
|
reject('PAGE-032', entry, codePropTemplateErrors([entry]));
|
|
834
764
|
for (const entry of opRecords)
|
|
835
765
|
reject('PAGE-037', entry, [...addComponentIdErrors([entry]), ...(entry.op === 'add_component' ? missingBlocksNodes([entry.component]) : [])]);
|
|
836
|
-
|
|
766
|
+
for (const entry of opRecords)
|
|
767
|
+
reject('PAGE-051', entry, entry.op === 'add_component' ? retiredTypeNodes([entry.component]) : []);
|
|
768
|
+
const touchesConnection = propTypeOps.length > 0 || opRecords.some(entry => entry.op === 'set_binding' || entry.op === 'replace_prop' || entry.op === 'remove_connect_data');
|
|
837
769
|
let connectedProps = null;
|
|
838
770
|
if (touchesConnection) {
|
|
839
771
|
try {
|
|
@@ -843,7 +775,8 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
843
775
|
connectedProps = null;
|
|
844
776
|
}
|
|
845
777
|
}
|
|
846
|
-
|
|
778
|
+
// `set_prop_type` ayrı listededir; bağlı prop'u ezen yazımı (CD-005) o da yapar.
|
|
779
|
+
for (const entry of [...opRecords, ...propTypeOps]) {
|
|
847
780
|
for (const issue of connectDataOpIssues(entry, connectedProps))
|
|
848
781
|
reject(issue.code, entry, [issue.message]);
|
|
849
782
|
}
|
|
@@ -864,7 +797,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
864
797
|
reject('PAGE-008', entry, unknownEventOps([entry], typesByElementId, eventsBySlug));
|
|
865
798
|
}
|
|
866
799
|
if (rejected.length > 0)
|
|
867
|
-
throw new PlatformApiError(rejectedOpsMessage(rejected), 400);
|
|
800
|
+
throw new PlatformApiError(rejectedOpsMessage(rejected, batchIndexHint(opened)), 400);
|
|
868
801
|
stripGatewayEventFields(opRecords);
|
|
869
802
|
const wantsRootAdd = opRecords.some(entry => entry.op === 'add_component' && (entry.parent === undefined || entry.parent === null || entry.parent === 'root'));
|
|
870
803
|
let retargeted = [];
|
|
@@ -882,16 +815,17 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
882
815
|
? await orderByIndex(opRecords, readPage)
|
|
883
816
|
: { ops: opRecords, moved: [], warnings: [] };
|
|
884
817
|
const sentOps = ordering.ops;
|
|
818
|
+
// Bu noktadan sonra `opRecords` yeni op almaz (bölüm anahtarı yukarıda eklendi): çağıranın sırası sabittir.
|
|
819
|
+
const slots = callerSlots(allOps, opRecords);
|
|
885
820
|
// Akış silen op'lar yamadan ÖNCE hesaplanır: uyarı sonradan geldiğinde akış zaten kalıcı
|
|
886
821
|
// silinmiş oluyordu ve "önce yedekle" tavsiyesi uygulanamıyordu (09-05 koşusu, G-21).
|
|
887
822
|
let deletedFlows = [];
|
|
888
823
|
// remove_event opRecords'ta değil, ayrı listede durur; koşul yalnız opRecords'a baktığı sürece
|
|
889
824
|
// yalnız olay kaldıran bir yama bu korumayı hiç tetiklemiyordu (2026-09-14).
|
|
890
|
-
|
|
891
|
-
if ([...opRecords, ...removeEventOps].some(entry => ['remove_component', 'set_event', 'remove_event', 'batch'].includes(String(entry.op)))) {
|
|
825
|
+
if ([...opRecords, ...removeEventOps].some(entry => ['remove_component', 'set_event', 'remove_event'].includes(String(entry.op)))) {
|
|
892
826
|
try {
|
|
893
827
|
const page = await readPage();
|
|
894
|
-
deletedFlows = orphanedFlowPlan(page.schema, page.events,
|
|
828
|
+
deletedFlows = orphanedFlowPlan(page.schema, page.events, recordsWithEventRemovals(slots, opRecords));
|
|
895
829
|
}
|
|
896
830
|
catch {
|
|
897
831
|
deletedFlows = [];
|
|
@@ -942,7 +876,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
942
876
|
const touched = simulateLayoutOps(simulated, sentOps);
|
|
943
877
|
// PAGE-013 op'lar UYGULANDIKTAN SONRAKİ ağaca bakar: tek başına eklenen düğüm masum
|
|
944
878
|
// görünür, iç içeliği ancak hedef parent zinciri belli olunca anlarsın.
|
|
945
|
-
nestedAfterOps = nestedRepeaterNodes(simulated);
|
|
879
|
+
nestedAfterOps = nestedRepeaterNodes(simulated, resolved.profile.platform);
|
|
946
880
|
layoutWarnings = [
|
|
947
881
|
...(blocksMeaningful ? pageContainerPositionWarning(page.schema) : []),
|
|
948
882
|
...(blocksMeaningful ? verticalGapWarnings(simulated, 'PAGE-010 (uyarı)', touched) : []),
|
|
@@ -959,25 +893,100 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
959
893
|
if (nestedAfterOps.length > 0)
|
|
960
894
|
throw new PlatformApiError(nestedRepeaterMessage(nestedAfterOps, resolved.profile.platform), 400);
|
|
961
895
|
const removedEvents = planEventRemovals(removeEventOps);
|
|
962
|
-
|
|
963
|
-
const propTypes = propTypeOps.length > 0 ?
|
|
964
|
-
const serverOps =
|
|
965
|
-
const writesStyle = resolved.profile.platform !== 'web' && opRecords.some(entry => (entry.op === 'replace_prop' || entry.op === 'set_binding') && entry.prop === 'style');
|
|
896
|
+
// Öykünülen op'lar ağacın o andaki hâline göre planlanır ve çağıranın yazdığı yerde gider (PAGE-050).
|
|
897
|
+
const { resized, propTypes } = planEmulatedOps(resizeOps.length > 0 || propTypeOps.length > 0 ? (await readPage()).schema ?? [] : [], slots, opRecords);
|
|
898
|
+
const serverOps = serverOpsInOrder(slots, { sent: sentOps, resized: resized.groups, propTypes: propTypes.serverOps });
|
|
966
899
|
const profileWarnings = await screenProfileWarnings(platform, resolved, project, environment, applicationId, {
|
|
967
900
|
kind: 'page',
|
|
968
901
|
ops: [...opRecords, ...propTypeOps],
|
|
969
|
-
|
|
902
|
+
// Kayıtlı ağaç: `style` yazımında hedefin tipi, `heroTag` yazımında sayfanın öteki etiketleri (MOB-030) için.
|
|
903
|
+
savedNodes: resolved.profile.platform !== 'web' && profileLintReadsSavedNodes(opRecords) ? await readPage().then(page => page.schema, () => undefined) : undefined,
|
|
970
904
|
steps: await boundFlowSteps(platform, resolved, project, environment, 'page', applicationId, pageId, opRecords)
|
|
971
905
|
});
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
906
|
+
// Kuru koşu hiçbir şey yazmaz: iskelet bulgularının tamamını döner; yazım yalnız bu yamayla YENİ geleni.
|
|
907
|
+
const skeletonWarnings = tool === 'page_schema_validate'
|
|
908
|
+
? await simulatedPageLayoutWarnings(platform, resolved, project, environment, applicationId, readPage, sentOps, 'audit')
|
|
909
|
+
: reshapesSkeleton(opRecords)
|
|
910
|
+
? await simulatedPageLayoutWarnings(platform, resolved, project, environment, applicationId, readPage, sentOps, 'new')
|
|
911
|
+
: [];
|
|
975
912
|
layoutWarnings = [...ordering.warnings, ...layoutWarnings, ...profileWarnings, ...skeletonWarnings];
|
|
913
|
+
return {
|
|
914
|
+
opRecords,
|
|
915
|
+
sentOps,
|
|
916
|
+
serverOps,
|
|
917
|
+
resolved,
|
|
918
|
+
removedEvents,
|
|
919
|
+
resized,
|
|
920
|
+
propTypes,
|
|
921
|
+
deletedFlows,
|
|
922
|
+
formWarnings,
|
|
923
|
+
flowWarnings,
|
|
924
|
+
flowsBeforePatch,
|
|
925
|
+
layoutWarnings,
|
|
926
|
+
readVersion: () => (typeof cachedPage?.version === 'string' ? cachedPage.version : undefined),
|
|
927
|
+
notes: [
|
|
928
|
+
...batchEnvelopeNote(opened),
|
|
929
|
+
...rootAddsNote(retargeted, PAGE_CONTAINER_ELEMENT_ID),
|
|
930
|
+
...componentNameNote(normalized.names),
|
|
931
|
+
...sectionNotes,
|
|
932
|
+
...componentDefaultsNote(normalized.components),
|
|
933
|
+
...validationNote(normalized.validations),
|
|
934
|
+
...catalogNotes,
|
|
935
|
+
...replacePropNote(normalized.props),
|
|
936
|
+
...flexIndexOrderNote(ordering.moved),
|
|
937
|
+
...mobileSpacingNote(spacing)
|
|
938
|
+
]
|
|
939
|
+
};
|
|
940
|
+
};
|
|
941
|
+
server.registerTool('page_schema_validate', {
|
|
942
|
+
title: 'Sayfa şemasını doğrula (kuru çalıştırma)',
|
|
943
|
+
description: "Micro-op'ları kaydetmeden şemaya uygular ve doğrulama hatalarını (suggestions ile) döndürür; page_schema_patch öncesi planı test etmek için. page_schema_patch'in PLANINI koşar (PAGE-049): aynı ön kontroller — yazımın reddedeceği yamayı aynı mesajla, istek göndermeden reddeder — aynı onarım ve platforma aynı gövde; yazımın döneceği uyarılar (layoutWarnings, formWarnings, flowWarnings) burada da görünür.",
|
|
944
|
+
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, pageId: guid, ops: opsParam.optional(), operations: opsParam.optional().describe("'ops' ile aynı alan (eşanlamlı) — entity/microservice/workflow patch'leriyle aynı adı kullanabilmeniz için"), allowFlowDeletion: z.boolean().optional().describe('page_schema_patch\'e vereceğiniz değer: true ise akışı referanssız bırakan yama kuru koşuda da reddedilmez. Varsayılan false — yazım onu reddeder, kuru koşu da (G-21).') },
|
|
945
|
+
annotations: readOnly
|
|
946
|
+
}, handle(config, async ({ project, environment, applicationId, pageId, ops, operations, allowFlowDeletion }) => {
|
|
947
|
+
const plan = await planPageWrite('page_schema_validate', { project, environment, applicationId, pageId, ops, operations, allowFlowDeletion });
|
|
948
|
+
const response = ((await platform.tenant('POST', project, `/pages/${applicationId}/${pageId}/schema/validate`, {
|
|
949
|
+
environment,
|
|
950
|
+
body: { ops: plan.serverOps }
|
|
951
|
+
})) ?? {});
|
|
952
|
+
// Yazımın yanıtında dönecek uyarılar kuru koşuda da görünür: plan aynı, yalnız istek farklı.
|
|
953
|
+
if (plan.deletedFlows.length > 0)
|
|
954
|
+
response.deletedFlows = plan.deletedFlows;
|
|
955
|
+
if (plan.resized.warnings.length > 0)
|
|
956
|
+
response.resizeWarnings = plan.resized.warnings;
|
|
957
|
+
if (plan.formWarnings.length > 0)
|
|
958
|
+
response.formWarnings = plan.formWarnings;
|
|
959
|
+
if (plan.flowWarnings.length > 0)
|
|
960
|
+
response.flowWarnings = plan.flowWarnings;
|
|
961
|
+
if (plan.layoutWarnings.length > 0)
|
|
962
|
+
response.layoutWarnings = plan.layoutWarnings;
|
|
963
|
+
Object.assign(response, applicationTypeField(plan.resolved));
|
|
964
|
+
return withNormalization(response, plan.notes);
|
|
965
|
+
}));
|
|
966
|
+
server.registerTool('page_schema_patch', {
|
|
967
|
+
title: 'Sayfa şemasına patch uygula',
|
|
968
|
+
description: "Micro-op'ları doğrulama duvarından geçirip TEK PATCH ile kaydeder; açık studio canvas'ları SignalR ile canlı güncellenir. İstek atomiktir: bir op reddedilirse hiçbiri yazılmaz. baseVersion (page_schema_get çıktısındaki version ya da önceki yamanın newVersion'ı) verilirse sayfa o sürümden beri değişmişse 409 döner ve hiçbir op uygulanmaz (stale plan koruması); verilmezse gateway yalnız bu çağrıda zaten okuduğu sayfanın sürümünü gönderir. Yanıttaki appliedPatch, her op'un şemada tam olarak hangi JSON Pointer'a dokunduğunu söyler; gövdesi VARSAYILAN OLARAK iskelettir (eklenen düğüm id/type/children'a iner) — tam gövde için view:'full'. Op'un gerçekten kaydedilip kaydedilmediğini gövde değil silentlyDropped söyler. Gateway ön kontrolleri (PAGE-006/008/016/032/037/051, set_prop_type gövdesi, move_component size) op başına toplanır: düşen HER op tek hata yanıtında rejectedOps[] ({ index, op, target, code, message }) ile listelenir ve hiçbir op gönderilmez — hepsini düzeltip listeyi bir kez yeniden gönderin.",
|
|
969
|
+
inputSchema: {
|
|
970
|
+
project: projectParam,
|
|
971
|
+
environment: environmentParam,
|
|
972
|
+
applicationId: guid,
|
|
973
|
+
pageId: guid,
|
|
974
|
+
ops: opsParam.optional(),
|
|
975
|
+
operations: opsParam.optional().describe("'ops' ile aynı alan (eşanlamlı) — entity/microservice/workflow patch'leriyle aynı adı kullanabilmeniz için"),
|
|
976
|
+
baseVersion: z.string().optional().describe("page_schema_get çıktısındaki version ya da önceki page_schema_patch yanıtındaki newVersion; sayfa o sürümden beri değiştiyse 409 döner ve hiçbir op uygulanmaz"),
|
|
977
|
+
expectedUpdatedAt: z.string().optional().describe("Eski koruma: page_schema_get çıktısındaki updatedAt; eşleşmezse patch uygulanmaz. baseVersion tercih edilir"),
|
|
978
|
+
allowFlowDeletion: z.boolean().optional().describe("true: bu yama bir akışı referanssız bırakacaksa yine de uygulanır. Varsayılan false — platform referanssız akışı KALICI siler ve gateway isteği önden reddeder (G-21). Silinen akışlar yanıtta deletedFlows ile listelenir."),
|
|
979
|
+
view: writeViewParam
|
|
980
|
+
},
|
|
981
|
+
annotations: updates
|
|
982
|
+
}, handle(config, async ({ project, environment, applicationId, pageId, ops, operations, baseVersion, expectedUpdatedAt, allowFlowDeletion, view }) => {
|
|
983
|
+
const plan = await planPageWrite('page_schema_patch', { project, environment, applicationId, pageId, ops, operations, expectedUpdatedAt, allowFlowDeletion });
|
|
984
|
+
const { opRecords, sentOps, serverOps, resolved, removedEvents, resized, propTypes, deletedFlows, formWarnings, flowWarnings, flowsBeforePatch, layoutWarnings } = plan;
|
|
976
985
|
// Tek istek, tek sürüm: öykünülen op'lar 2026-09-14'e kadar ayrı GET + tam PUT çiftleriydi ve
|
|
977
986
|
// yamadan ÖNCE yazılıyordu — PATCH reddedilse bile kalıcıydılar. Artık hepsi aynı atomik PATCH'te.
|
|
978
987
|
// baseVersion yalnız biliniyorsa gider (ajanın verdiği ya da bu çağrıda zaten okunan sayfanınki):
|
|
979
988
|
// sürümü öğrenmek için ayrı GET atılmaz, platform satırı her yamada kilitler.
|
|
980
|
-
const sentVersion = baseVersion ?? (
|
|
989
|
+
const sentVersion = baseVersion ?? plan.readVersion();
|
|
981
990
|
const response = ((await platform.tenant('PATCH', project, `/pages/${applicationId}/${pageId}/schema`, {
|
|
982
991
|
environment,
|
|
983
992
|
body: { ops: serverOps, baseVersion: sentVersion }
|
|
@@ -1049,17 +1058,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
1049
1058
|
}
|
|
1050
1059
|
}
|
|
1051
1060
|
Object.assign(response, applicationTypeField(resolved));
|
|
1052
|
-
return withWriteDiff(withNormalization(response,
|
|
1053
|
-
...rootAddsNote(retargeted, PAGE_CONTAINER_ELEMENT_ID),
|
|
1054
|
-
...componentNameNote(normalized.names),
|
|
1055
|
-
...sectionNotes,
|
|
1056
|
-
...componentDefaultsNote(normalized.components),
|
|
1057
|
-
...validationNote(normalized.validations),
|
|
1058
|
-
...catalogNotes,
|
|
1059
|
-
...replacePropNote(normalized.props),
|
|
1060
|
-
...flexIndexOrderNote(ordering.moved),
|
|
1061
|
-
...mobileSpacingNote(spacing)
|
|
1062
|
-
]), opDrops);
|
|
1061
|
+
return withWriteDiff(withNormalization(response, plan.notes), opDrops);
|
|
1063
1062
|
}));
|
|
1064
1063
|
server.registerTool('page_discover', {
|
|
1065
1064
|
title: 'Tasarım ekranından sayfa iskeleti öner',
|
|
@@ -1166,6 +1165,9 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
1166
1165
|
summary.layoutWarnings = updateWarnings;
|
|
1167
1166
|
return withNormalization(summary, schema === undefined ? [] : [...container.fixes, ...skeletonNotes, ...componentNameNote(named), ...reset, ...componentDefaultsNote(fixed), ...catalogNotes, ...reorderNote(moved), ...mobileSpacingNote(spacing)]);
|
|
1168
1167
|
}
|
|
1168
|
+
// PAGE-051 yalnız gerçekten OLUŞTURAN dalda: `ifExists: 'update'` var olan sayfada page_update gibi
|
|
1169
|
+
// davranır ve kayıtlı emekli düğüm yazılabilir kalmalıdır.
|
|
1170
|
+
assertNoRetiredNodes(container.schema);
|
|
1169
1171
|
if (templateRoot && layoutId === undefined)
|
|
1170
1172
|
skeletonNotes = shellLessPageSkeleton(templateRoot);
|
|
1171
1173
|
const response = await platform.tenant('POST', project, `/pages/${applicationId}`, {
|
|
@@ -1343,7 +1345,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
1343
1345
|
*/
|
|
1344
1346
|
async function mobileSpacingForOps(platformName, ops, readSaved) {
|
|
1345
1347
|
const fix = emptyMobileSpacingFix();
|
|
1346
|
-
if (platformName !== 'mobile' || !ops.some(entry => entry.op === 'add_component'
|
|
1348
|
+
if (platformName !== 'mobile' || !ops.some(entry => entry.op === 'add_component'))
|
|
1347
1349
|
return fix;
|
|
1348
1350
|
const saved = await readSaved().then(page => page.schema, () => undefined);
|
|
1349
1351
|
if (saved !== undefined)
|
|
@@ -66,8 +66,9 @@ const guideRouting = {
|
|
|
66
66
|
entity: "alan tipleri, ilişkiler, hazır entity'ler",
|
|
67
67
|
page: 'sayfa/flow işleri; prop\'u veri kaynağına bağlama (connectData, Kural 1c-3); flex düzen prop grubu ve boyut modları (Kural 1f-2)',
|
|
68
68
|
layout: 'yerleşim kabuğu: tek slot, views, dar ekranda yığılma, widthType fill/fixed/auto',
|
|
69
|
-
mobile: "mobil UYGULAMA (type:'mobile'): kurulum sırası (mobile_app_create), flex-only yerleşim, tipli stil, sekmeler (properties.mobile.tabs) ve çekmece,
|
|
70
|
-
'mobile-
|
|
69
|
+
mobile: "mobil UYGULAMA (type:'mobile'): kurulum sırası (mobile_app_create), flex-only yerleşim, tipli stil, sekmeler (properties.mobile.tabs) ve çekmece, sayfa mount/focus olayları, MOB-* bulguları, page_screenshot device",
|
|
70
|
+
'mobile-steps': "mobil uygulamada cihaza dokunan akış adımları (redirect, alert, confirm, download, storage, setcookie, share, haptic, location, notification-*, permission, open-settings, back, ad-show, scan-code): mobildeki davranış, args sözleşmesi, Steps.<adım> sonucu; bildirim, izin, reklam ve konum tarifleri",
|
|
71
|
+
'mobile-publish': "mobil uygulamanın mağaza yayını: mobile_store_* / mobile_build_* akışı, ön kontrol P-01…P-14 (push kimlikleri, izinler, reklam ve kod tarama dahil), derleme hata kodları, insanın Studio'da yaptıkları",
|
|
71
72
|
'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ü',
|
|
72
73
|
component: 'komponent modeli, olay sözleşmeleri, appearance boyut sözlüğü (widthString/heightString)',
|
|
73
74
|
html: 'hazır komponent yetmediğinde tek seferlik kaçış kapısı (Mustache, fireEvent, script kuralları)',
|
|
@@ -48,8 +48,8 @@ async function pageShell(platform, project, environment, applicationId, layoutId
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
|
-
* `set_event` ile bağlanan akışların adımları (MOB-005). Akış gövdeleri şemada değil ayrı uçtadır;
|
|
52
|
-
*
|
|
51
|
+
* `set_event` ile bağlanan akışların adımları (MOB-005). Akış gövdeleri şemada değil ayrı uçtadır; okunamazsa bulgu
|
|
52
|
+
* üretilmez, yazım yine geçer. `ops` araç girişinde açılmış listedir (PAGE-048): `batch` zarfı buraya ulaşmaz.
|
|
53
53
|
*/
|
|
54
54
|
export async function boundFlowSteps(platform, resolved, project, environment, host, applicationId, hostId, ops) {
|
|
55
55
|
if (resolved.profile.platform === 'web')
|