@appaflytech/zeyrek-ai-mcp 0.0.35 → 0.0.37
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 +15 -0
- package/README.md +5 -5
- package/dist/config.js +37 -0
- package/dist/index.js +2 -0
- package/dist/knowledge/access.js +802 -0
- package/dist/knowledge/backendConstraints.js +18 -1
- package/dist/knowledge/case.js +41 -0
- package/dist/knowledge/componentCatalog.js +655 -424
- package/dist/knowledge/componentEvents.js +140 -23
- package/dist/knowledge/connectDataBind.js +843 -0
- package/dist/knowledge/connectDataDefinition.js +344 -0
- package/dist/knowledge/connectDataExecute.js +93 -0
- package/dist/knowledge/connectDataRules.js +128 -0
- package/dist/knowledge/decision.js +121 -0
- package/dist/knowledge/expressionPrelude.js +59 -0
- package/dist/knowledge/layoutSummary.js +140 -2
- package/dist/knowledge/microserviceParameters.js +58 -0
- package/dist/knowledge/mining.js +94 -0
- package/dist/knowledge/mobileComponentCatalog.js +864 -0
- package/dist/knowledge/mobileComponentEvents.js +239 -0
- package/dist/knowledge/mobileStore.js +321 -0
- package/dist/knowledge/normalize.js +235 -84
- package/dist/knowledge/outlines.js +36 -0
- package/dist/knowledge/platform/lint.js +385 -0
- package/dist/knowledge/platform/mobile.js +142 -0
- package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
- package/dist/knowledge/platform/mobileRules.js +231 -0
- package/dist/knowledge/platform/mobileSpacing.js +82 -0
- package/dist/knowledge/platform/mobileTabs.js +108 -0
- package/dist/knowledge/platform/nativeBoxModel.js +44 -0
- package/dist/knowledge/platform/profile.js +25 -0
- package/dist/knowledge/platform/resolve.js +122 -0
- package/dist/knowledge/platform/web.js +39 -0
- package/dist/knowledge/policy.js +18 -4
- package/dist/knowledge/process.js +510 -0
- package/dist/knowledge/reservedTables.js +79 -0
- package/dist/knowledge/rowFilter.js +43 -0
- package/dist/knowledge/rules.js +423 -37
- package/dist/knowledge/schemaGuard.js +11 -0
- package/dist/knowledge/styleResolve.js +53 -19
- package/dist/knowledge/styleResolveNative.js +527 -0
- package/dist/knowledge/themeResolve.js +4 -4
- package/dist/knowledge/themeSchema.js +1 -2
- package/dist/observability/trace.js +6 -3
- package/dist/platform/argumentAliases.js +128 -0
- package/dist/platform/bodyFile.js +103 -0
- package/dist/platform/capture/actions.js +398 -0
- package/dist/platform/capture/browser.js +1 -0
- package/dist/platform/capture/capture.js +683 -0
- package/dist/platform/capture/console-log.js +122 -0
- package/dist/platform/capture/index.js +11 -0
- package/dist/platform/capture/readiness.js +103 -0
- package/dist/platform/capture/summary.js +77 -0
- package/dist/platform/capture/target.js +5 -0
- package/dist/platform/capture/targets/studio-mobile.js +15 -0
- package/dist/platform/capture/targets/studio-web.js +5 -0
- package/dist/platform/diagnostics.js +10 -4
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/errors.js +163 -10
- package/dist/platform/http.js +29 -8
- package/dist/platform/impersonation.js +45 -0
- package/dist/platform/jsonArray.js +24 -0
- package/dist/platform/responses.js +39 -5
- package/dist/platform/schemaReadMemory.js +60 -0
- package/dist/platform/secrets.js +19 -1
- package/dist/platform/strictArguments.js +68 -12
- package/dist/platform/tokenVault.js +187 -4
- package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
- package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
- package/dist/resources/examples/bpm-satinalma.json +376 -0
- package/dist/resources/examples/connect-data-convert-verify.json +107 -0
- package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
- package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
- package/dist/resources/examples/connect-data-query-params.json +50 -0
- package/dist/resources/examples/connect-data-table-entity.json +147 -0
- package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
- package/dist/resources/examples/middleware-authenticate.json +1 -1
- package/dist/resources/examples/mobile-app-shell-drawer.json +244 -0
- package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
- package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
- package/dist/resources/examples/mobile-form-screen.json +365 -0
- package/dist/resources/examples/mobile-list-detail-form.json +703 -0
- package/dist/resources/examples/page-detail-profile.json +2 -1
- package/dist/resources/examples/page-dynamic-form.json +3 -2
- 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 +8 -2
- package/dist/resources/guides/access.md +810 -0
- package/dist/resources/guides/bpm.md +691 -0
- package/dist/resources/guides/case.md +153 -0
- package/dist/resources/guides/component.md +93 -6
- package/dist/resources/guides/decision.md +185 -0
- package/dist/resources/guides/entity.md +50 -8
- package/dist/resources/guides/expressions.md +14 -5
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/getting-started.md +38 -1
- package/dist/resources/guides/layout.md +11 -7
- package/dist/resources/guides/merge.md +37 -3
- package/dist/resources/guides/microservice.md +87 -2
- package/dist/resources/guides/middleware.md +68 -4
- package/dist/resources/guides/mobile-layout.md +193 -0
- package/dist/resources/guides/mobile-publish.md +124 -0
- package/dist/resources/guides/mobile.md +549 -0
- package/dist/resources/guides/page.md +463 -83
- package/dist/resources/guides/theme.md +8 -3
- package/dist/resources/guides/translation.md +1 -1
- package/dist/resources/guides/workflow.md +58 -1
- package/dist/resources/read.js +41 -0
- package/dist/resources/rules.js +11 -5
- package/dist/resources/schema-fingerprint.json +7 -5
- package/dist/resources/schemas/AccessExplanationDto.json +144 -0
- package/dist/resources/schemas/AccessMatrixDto.json +170 -0
- package/dist/resources/schemas/AccessPermissionDto.json +57 -0
- package/dist/resources/schemas/AccessPolicyDto.json +223 -0
- package/dist/resources/schemas/AccessResourceDto.json +86 -0
- package/dist/resources/schemas/AppSessionDto.json +53 -0
- package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
- package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
- package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
- package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
- package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
- package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
- package/dist/resources/schemas/CreateEntityCommand.json +118 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
- package/dist/resources/schemas/CreateQueryCommand.json +4 -0
- package/dist/resources/schemas/CreateWorkflowCommand.json +146 -1
- package/dist/resources/schemas/DataJobDto.json +6 -1
- package/dist/resources/schemas/DecisionDto.json +302 -0
- package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
- package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
- package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +25 -1
- package/dist/resources/schemas/MicroserviceDto.json +15 -3
- package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
- package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
- package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
- package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +10 -1
- package/dist/resources/schemas/PreviewWorkflowCommand.json +25 -1
- package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
- package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
- package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
- package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
- package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
- package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
- package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
- package/dist/resources/schemas/StartMobileBuildCommand.json +54 -0
- package/dist/resources/schemas/StepDto.json +25 -1
- package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +118 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
- package/dist/resources/schemas/UpdateQueryCommand.json +4 -0
- package/dist/resources/schemas/UpdateViewCommand.json +0 -2
- package/dist/resources/schemas/UpdateWorkflowCommand.json +146 -1
- package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +274 -0
- package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
- package/dist/server.js +31 -1
- package/dist/tools/access.js +369 -2
- package/dist/tools/accessOperations.js +135 -0
- package/dist/tools/accessPolicies.js +170 -0
- package/dist/tools/accessRuntime.js +203 -0
- package/dist/tools/applications.js +60 -3
- package/dist/tools/bpm.js +343 -0
- package/dist/tools/bpmGovernance.js +266 -0
- package/dist/tools/bpmOperations.js +230 -0
- package/dist/tools/bpmReporting.js +154 -0
- package/dist/tools/bpmRouting.js +150 -0
- package/dist/tools/bpmRuntime.js +396 -0
- package/dist/tools/case.js +178 -0
- package/dist/tools/caseRuntime.js +89 -0
- package/dist/tools/common.js +10 -1
- package/dist/tools/components.js +118 -14
- package/dist/tools/connectData.js +450 -0
- package/dist/tools/connectors.js +193 -0
- package/dist/tools/datasources.js +3 -3
- package/dist/tools/decisions.js +206 -0
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +38 -3
- package/dist/tools/designSchemaPatch.js +34 -9
- package/dist/tools/dtos.js +36 -5
- package/dist/tools/entities.js +79 -12
- package/dist/tools/externalComponents.js +26 -5
- package/dist/tools/flows.js +119 -17
- package/dist/tools/folders.js +1 -1
- package/dist/tools/imports.js +5 -2
- package/dist/tools/layouts.js +50 -17
- package/dist/tools/merges.js +2 -2
- package/dist/tools/microservices.js +77 -25
- package/dist/tools/mobile.js +280 -0
- package/dist/tools/mobileStore.js +556 -0
- package/dist/tools/modules.js +48 -0
- package/dist/tools/organizationStructure.js +137 -0
- package/dist/tools/pages.js +465 -98
- package/dist/tools/platformInfo.js +28 -8
- package/dist/tools/profileWrite.js +92 -0
- package/dist/tools/projects.js +71 -9
- package/dist/tools/rows.js +69 -13
- package/dist/tools/schemaOps.js +61 -1
- package/dist/tools/screenWrite.js +36 -7
- package/dist/tools/screens.js +95 -5
- package/dist/tools/templates.js +26 -1
- package/dist/tools/translations.js +1 -1
- package/dist/tools/variables.js +11 -5
- package/dist/tools/workflows.js +10 -5
- package/package.json +2 -2
- package/dist/platform/screenshot.js +0 -1162
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MOBİLE ÖZGÜ olay yükleri. Mobil komponentlerin ÇOĞU web şemasını genişletir ve
|
|
3
|
+
* olayları web sözleşmesindedir (`componentEvents.ts`) — bu dosya yalnız web'de
|
|
4
|
+
* karşılığı OLMAYAN komponentler içindir (`app-bar` gibi kabuk komponentleri).
|
|
5
|
+
*
|
|
6
|
+
* Okuyucu önce buraya, sonra web sözlüğüne bakar; parity testi
|
|
7
|
+
* (`test/mobile-component-parity.test.ts`) her mobil olayın iki sözlükten
|
|
8
|
+
* birinde karşılanmasını zorunlu tutar.
|
|
9
|
+
*/
|
|
10
|
+
const NO_DATA = { payload: {} };
|
|
11
|
+
export const mobileComponentEventContracts = {
|
|
12
|
+
'choice-chips': {
|
|
13
|
+
change: {
|
|
14
|
+
payload: {
|
|
15
|
+
value: 'string | number | boolean | Array — seçenek ÖZGÜN tipinde (değeri `34` yazılmış seçenek sayı yayar). `multiple` açıkken seçili değerlerin DİZİSİ (`[34, "a"]`); tek kipte seçili çipe yeniden dokunmak boş metin (`""`) yayar. Devre dışı seçenek olay yaymaz.'
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
// Web ikizinin yükü metindir (`e.currentTarget.value`); mobil seçeneği ÖZGÜN tipinde yayar (f-06, `optionEmitValues`).
|
|
20
|
+
// İki platformda aynı koşul için karşılaştırmayı metne çevirin: `String(self.value) === '34'`.
|
|
21
|
+
radio: {
|
|
22
|
+
change: {
|
|
23
|
+
payload: {
|
|
24
|
+
value: 'string | number | boolean — seçilen seçeneğin ÖZGÜN değeri (değeri `34` yazılmış seçenek sayı yayar; web aynı seçimi `"34"` metni olarak yayar)'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
checkboxgroup: {
|
|
29
|
+
change: {
|
|
30
|
+
payload: {
|
|
31
|
+
value: 'Array — seçili seçeneklerin ÖZGÜN değerleri (`["su", 9]`; web metin dizisi yayar). Seçeneklerde olmayan eski değer metin kalır'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
tooltip: {
|
|
36
|
+
open: NO_DATA
|
|
37
|
+
},
|
|
38
|
+
calendar: {
|
|
39
|
+
mount: NO_DATA,
|
|
40
|
+
change: {
|
|
41
|
+
payload: {
|
|
42
|
+
value: "string 'yyyy-MM-ddT00:00:00' | null — seçilen gün (aralıkta başlangıç); web datepicker'ın biçimi: yerel duvar saati, gece yarısı, dilim eki yok",
|
|
43
|
+
endValue: "string 'yyyy-MM-ddT00:00:00' | null — YALNIZ mode: 'range'; ilk basışta null, ikinci basışta bitiş günü"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
stack: {
|
|
48
|
+
mount: NO_DATA
|
|
49
|
+
},
|
|
50
|
+
'list-item': {
|
|
51
|
+
click: NO_DATA
|
|
52
|
+
},
|
|
53
|
+
fab: {
|
|
54
|
+
click: NO_DATA
|
|
55
|
+
},
|
|
56
|
+
'photo-viewer': {
|
|
57
|
+
change: { payload: { index: 'number — gösterilen fotoğrafın sırası (0 tabanlı); makine index prop\'una yazar' } },
|
|
58
|
+
close: { payload: {}, reads: 'kapat düğmesi ya da geri; makine isOpen\'ı kapatır' },
|
|
59
|
+
share: { payload: { row: 'gösterilen satırın tamamı (images dizisindeki nesne)', index: 'number — satırın sırası' }, reads: 'Paylaş düğmesi yalnız bu olay bir akışa bağlıysa çizilir; paylaşmak akışın işidir' },
|
|
60
|
+
delete: { payload: { row: 'gösterilen satırın tamamı', index: 'number — satırın sırası' }, reads: 'Sil düğmesi yalnız bu olay bir akışa bağlıysa çizilir; satırı silmek ve listeyi yenilemek akışın işidir' }
|
|
61
|
+
},
|
|
62
|
+
timer: {
|
|
63
|
+
mount: NO_DATA,
|
|
64
|
+
tick: { payload: { value: 'number — gösterilen saniye (geri sayımda kalan, kronometrede geçen); makine value prop\'una yazar' } },
|
|
65
|
+
finish: { payload: { isRunning: 'false — geri sayım 0\'a indi; makine isRunning\'i kapatır' } }
|
|
66
|
+
},
|
|
67
|
+
audio: {
|
|
68
|
+
mount: NO_DATA,
|
|
69
|
+
play: { payload: { isPlaying: "true — çalma başladı (denetim ya da akış); makine isPlaying'i yazar" } },
|
|
70
|
+
pause: { payload: { isPlaying: "false — çalma durdu (denetim, akış, bitiş ya da tarayıcının otomatik oynatma reddi); makine isPlaying'i yazar" } },
|
|
71
|
+
ended: { payload: { isPlaying: "false — ses sona vardı (loop kapalıyken, pause'tan sonra); makine isPlaying'i kapatır" } }
|
|
72
|
+
},
|
|
73
|
+
lottie: {
|
|
74
|
+
mount: NO_DATA,
|
|
75
|
+
finish: { payload: { isPlaying: "false — döngüsüz animasyon bitti; makine isPlaying'i kapatır, yeniden true yazmak baştan oynatır" } }
|
|
76
|
+
},
|
|
77
|
+
webview: {
|
|
78
|
+
mount: NO_DATA,
|
|
79
|
+
load: { payload: {}, reads: "her tamamlanan yüklemede yayılır (izin verilen gezinmeden sonra da); cihazda yüklenemeyen sayfada yayılmaz (yerine error), web'de tarayıcı engellenen çerçevede de yayar" },
|
|
80
|
+
navigate: { payload: { url: "string — sayfanın gitmek istediği adres; makine url prop'una yazar (self.url). allowNavigation kapalıyken (varsayılan) gezinme engellenir; adres yalnız kullanıcının dokunduğu bağlantıda sistemde açılır" } },
|
|
81
|
+
message: {
|
|
82
|
+
payload: { data: "string — sayfanın window.ReactNativeWebView.postMessage(metin) ile yolladığı metin, olduğu gibi; makine data prop'una yazar (self.data)" },
|
|
83
|
+
reads: "iki yönlü köprü: sayfa window.ngApps.emit(name, data) çağırırsa yük olayın params'ında gelir — akış event.name ve event.data okur (self.data yazılmaz)"
|
|
84
|
+
},
|
|
85
|
+
error: { payload: {}, reads: "cihazda sayfa yüklenemeyince (ağ hatası) yayılır, görünüm yer tutucu çizer; web'de pratikte gelmez (iframe gibi)" }
|
|
86
|
+
},
|
|
87
|
+
html: {
|
|
88
|
+
mount: NO_DATA,
|
|
89
|
+
message: {
|
|
90
|
+
payload: {},
|
|
91
|
+
reads: "belgenin window.ngApps.emit(name, data) çağrısı; yük olayın params'ındadır — akış event.name (ileti adı) ve event.data (veri) okur. actions satırının akışı ise fireEvent(key, data) ile koşar: event.name = key, event.data = veri"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
map: {
|
|
95
|
+
mount: NO_DATA,
|
|
96
|
+
markerClick: { payload: { markerId: "string — dokunulan işaretçinin `id`si (boşsa listedeki sırası); makine markerId prop'una yazar (self.markerId). Başlığı ya da açıklaması olan işaretçide balon da açılır" } },
|
|
97
|
+
regionChange: {
|
|
98
|
+
payload: {
|
|
99
|
+
latitude: 'number — kullanıcının bıraktığı merkezin enlemi (6 basamak)',
|
|
100
|
+
longitude: 'number — merkezin boylamı (6 basamak, −180…180)',
|
|
101
|
+
zoom: 'number — web harita ölçeği (2 basamak, 1–19)'
|
|
102
|
+
},
|
|
103
|
+
reads: "yalnız kullanıcının sürüklemesi ya da yakınlaştırması bitince yayılır; akışın yazdığı görünüm ve kutu boyu değişimi yaymaz. Makine üç prop'u da yazar (self.latitude, self.longitude, self.zoom)"
|
|
104
|
+
},
|
|
105
|
+
press: {
|
|
106
|
+
payload: {
|
|
107
|
+
latitude: 'number — yerin enlemi: tek işaretçi varsa o işaretçi, yoksa görünümün merkezi',
|
|
108
|
+
longitude: 'number — yerin boylamı',
|
|
109
|
+
mapsUrl: "string — yeri cihazın harita uygulamasında açan adres (iOS Apple Haritalar https://maps.apple.com/?ll=…&q=<ad>, Android geo:<lat>,<lng>?q=…(<ad>), web Google Haritalar araması)"
|
|
110
|
+
},
|
|
111
|
+
reads: "işaretçi dışına dokunuşta yayılır (interactive: false önizlemede bütün yüzey). Makine YALNIZ mapsUrl'i düğüme yazar (self.mapsUrl) — koordinat yazılsaydı harita kayardı; koordinat event.data'dadır. Tarif: redirect isRaw: true, path: '<harita>.mapsUrl'"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
markdown: {
|
|
115
|
+
mount: NO_DATA,
|
|
116
|
+
linkClick: {
|
|
117
|
+
payload: {
|
|
118
|
+
href: "string — dokunulan bağlantının ham adresi; şema süzülmeden gelir (dışarıda yalnız http(s), mailto, tel açılır)"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
'app-bar': {
|
|
123
|
+
clickBack: NO_DATA,
|
|
124
|
+
clickMenu: NO_DATA,
|
|
125
|
+
clickAction: { payload: { key: 'string (eylemin key alanı; yoksa dizideki sırası)' } }
|
|
126
|
+
},
|
|
127
|
+
'safe-area': {
|
|
128
|
+
mount: NO_DATA
|
|
129
|
+
},
|
|
130
|
+
// Web `container` yalnız `mount` yayar; `click` mobile-only (plans/mobil-plantcare-acigi f-04, K1).
|
|
131
|
+
container: {
|
|
132
|
+
click: NO_DATA
|
|
133
|
+
},
|
|
134
|
+
// Arama varyantının "Vazgeç"i (plans/mobil-plantcare-acigi f-05): değer temizlenir, klavye kapanır.
|
|
135
|
+
textinput: {
|
|
136
|
+
cancel: NO_DATA
|
|
137
|
+
},
|
|
138
|
+
'scroll-view': {
|
|
139
|
+
mount: NO_DATA,
|
|
140
|
+
scrollEnd: NO_DATA,
|
|
141
|
+
refresh: NO_DATA,
|
|
142
|
+
scroll: {
|
|
143
|
+
payload: {
|
|
144
|
+
y: 'number — dikey kaydırma konumu (yatay kaydırıcıda x)',
|
|
145
|
+
contentHeight: 'number — içeriğin boyu (yatayda contentWidth)',
|
|
146
|
+
viewportHeight: 'number — görünen alanın boyu (yatayda viewportWidth)'
|
|
147
|
+
},
|
|
148
|
+
reads: '100 ms seyreltmeli; yalnız bu olaya akış bağlıyken yayılır. Düğüme scrollY (scrollX) de yazılır'
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
'grouped-list': {
|
|
152
|
+
mount: NO_DATA,
|
|
153
|
+
change: {
|
|
154
|
+
payload: {
|
|
155
|
+
selectedIndex: 'number — dokunulan öğenin rows içindeki DÜZ indeksi (bölüm içi değil); aynı öğeye yeniden dokununca yayılmaz. Makine selectedIndex\'i yazar, akışta tıklanan satır <liste>.selectedItem'
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
itemPress: {
|
|
159
|
+
payload: {
|
|
160
|
+
index: 'number (öğenin rows içindeki düz indeksi, 0 tabanlı)',
|
|
161
|
+
row: 'object (öğenin satır verisi)'
|
|
162
|
+
},
|
|
163
|
+
reads: 'yalnız itemPressable açıkken; önce change { selectedIndex } yayılır. Öğe şablonu basılabilir bir bileşense (list-item, button) dokunuş onun click\'ine gider, itemPress yayılmaz'
|
|
164
|
+
},
|
|
165
|
+
swipe: {
|
|
166
|
+
payload: {
|
|
167
|
+
key: 'string (kaydırma eyleminin key alanı)',
|
|
168
|
+
index: 'number (öğenin rows içindeki düz indeksi, 0 tabanlı)',
|
|
169
|
+
row: 'object (öğenin satır verisi)'
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
sectionPress: {
|
|
173
|
+
payload: {
|
|
174
|
+
key: 'string — bölüm anahtarı (tarih değerinde yerel gün YYYY-AA-GG)',
|
|
175
|
+
title: 'string — bölüm başlığı (anahtar; boş alanlı satırların bölümünde otherSectionTitle)',
|
|
176
|
+
count: 'number — bölümdeki öğe sayısı',
|
|
177
|
+
items: 'object[] — bölümdeki satırların verisi'
|
|
178
|
+
},
|
|
179
|
+
reads: 'bölüm başlığına dokununca; yük başlık şablonunun Section ifadesiyle aynı nesnedir'
|
|
180
|
+
},
|
|
181
|
+
selectionChange: {
|
|
182
|
+
payload: {
|
|
183
|
+
selectedIndices: 'number[] — seçili satırların rows içindeki DÜZ indeksleri, sıralı',
|
|
184
|
+
count: 'number — seçili satır sayısı'
|
|
185
|
+
},
|
|
186
|
+
reads: 'yalnız selectionMode: multiple (ya da longPressSelects ile açılınca); akış event.data.selectedIndices / event.data.count okur, düğümün selectedIndices/selectedItems değeri de yazılır'
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
eventcalendar: {
|
|
190
|
+
mount: NO_DATA,
|
|
191
|
+
dateClick: {
|
|
192
|
+
payload: { date: "string 'yyyy-MM-dd'", rows: 'object[] — o güne düşen kaynak satırlar (mobil)' },
|
|
193
|
+
reads: "self'e yazılmaz — event.data ile oku; ay ve hafta görünümünde güne dokununca"
|
|
194
|
+
},
|
|
195
|
+
eventClick: {
|
|
196
|
+
payload: { id: 'string', title: 'string', row: 'kaynak satırın TAMAMI' },
|
|
197
|
+
reads: "self'e yazılmaz — event.data ile oku; gün çizelgesinde bloğa dokununca"
|
|
198
|
+
},
|
|
199
|
+
monthChange: {
|
|
200
|
+
payload: {
|
|
201
|
+
month: 'number (1-TABANLI)',
|
|
202
|
+
year: 'number',
|
|
203
|
+
view: "'month' | 'week' | 'day'",
|
|
204
|
+
start: "string 'yyyy-MM-dd' (görünen ilk gün)",
|
|
205
|
+
end: "string 'yyyy-MM-dd' (görünen son gün)"
|
|
206
|
+
},
|
|
207
|
+
reads: "self'e yazılmaz — event.data ile oku; oklar, yatay kaydırma ve Bugün ile her görünümde"
|
|
208
|
+
},
|
|
209
|
+
viewChange: {
|
|
210
|
+
payload: { view: "'month' | 'week' | 'day'", start: "string 'yyyy-MM-dd'", end: "string 'yyyy-MM-dd'" },
|
|
211
|
+
reads: "self'e yazılmaz — event.data ile oku; görünüm düğmesiyle"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
'floating-container': {
|
|
215
|
+
mount: NO_DATA
|
|
216
|
+
},
|
|
217
|
+
repeater: {
|
|
218
|
+
swipe: {
|
|
219
|
+
payload: {
|
|
220
|
+
key: 'string (kaydırma eyleminin key alanı)',
|
|
221
|
+
index: 'number (satırın sırası, 0 tabanlı)',
|
|
222
|
+
row: 'object (satırın verisi)'
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
itemPress: {
|
|
226
|
+
payload: {
|
|
227
|
+
index: 'number (satırın sırası, 0 tabanlı)',
|
|
228
|
+
row: 'object (satırın verisi)'
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
selectionChange: {
|
|
232
|
+
payload: {
|
|
233
|
+
selectedIndices: 'number[] — seçili satırların rows içindeki DÜZ indeksleri, sıralı',
|
|
234
|
+
count: 'number — seçili satır sayısı'
|
|
235
|
+
},
|
|
236
|
+
reads: 'yalnız selectionMode: multiple (ya da longPressSelects ile açılınca); akış event.data.selectedIndices / event.data.count okur, düğümün selectedIndices/selectedItems değeri de yazılır'
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
export const PACKAGE_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9]*(\.[a-zA-Z][a-zA-Z0-9_]*)+$/;
|
|
2
|
+
export const SCHEME_PATTERN = /^[a-z][a-z0-9+.-]{2,}$/;
|
|
3
|
+
export const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
4
|
+
export const LOCALE_PATTERN = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})?$/;
|
|
5
|
+
export const COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
6
|
+
export const PERMISSION_KEY_PATTERN = /^[a-z][A-Za-z0-9]*$/;
|
|
7
|
+
export const RESERVED_SCHEME = 'zeyrek';
|
|
8
|
+
export const MAX_BUILD_NUMBER = 2_100_000_000;
|
|
9
|
+
export const DISPLAY_NAME_MAX_LENGTH = 30;
|
|
10
|
+
export const PERMISSION_TEXT_MAX_LENGTH = 500;
|
|
11
|
+
export const KEYWORDS_MAX_LENGTH = 100;
|
|
12
|
+
export const COPYRIGHT_MAX_LENGTH = 200;
|
|
13
|
+
export const ORIENTATIONS = ['portrait', 'landscape', 'default'];
|
|
14
|
+
export const USER_INTERFACE_STYLES = ['automatic', 'light', 'dark'];
|
|
15
|
+
export const SPLASH_RESIZE_MODES = ['contain', 'cover'];
|
|
16
|
+
export const RELEASE_STATUSES = ['draft', 'completed'];
|
|
17
|
+
/** İznin mağaza derlemesindeki kipi (kök ADR 0010): kullanıma göre · her zaman · hiç. Anahtarları backend doğrular. */
|
|
18
|
+
export const PERMISSION_MODES = ['auto', 'on', 'off'];
|
|
19
|
+
export const LISTING_LIMITS = {
|
|
20
|
+
title: 30,
|
|
21
|
+
subtitle: 30,
|
|
22
|
+
shortDescription: 80,
|
|
23
|
+
description: 4000,
|
|
24
|
+
promoText: 170,
|
|
25
|
+
releaseNotes: 4000
|
|
26
|
+
};
|
|
27
|
+
export const URL_FIELDS = ['support', 'marketing', 'privacyPolicy', 'privacyChoices'];
|
|
28
|
+
/** İlk derlemenin kilitlediği alanlar (`MobileStoreSettings.FieldsLockedByFirstBuild`) */
|
|
29
|
+
export const LOCKABLE_FIELDS = ['bundleIdentifier', 'androidPackage', 'scheme', 'iosBuildNumber', 'androidVersionCode'];
|
|
30
|
+
export const JAVA_KEYWORDS = new Set([
|
|
31
|
+
'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'default',
|
|
32
|
+
'do', 'double', 'else', 'enum', 'extends', 'final', 'finally', 'float', 'for', 'goto', 'if', 'implements', 'import',
|
|
33
|
+
'instanceof', 'int', 'interface', 'long', 'native', 'new', 'package', 'private', 'protected', 'public', 'return',
|
|
34
|
+
'short', 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'try',
|
|
35
|
+
'void', 'volatile', 'while', 'true', 'false', 'null'
|
|
36
|
+
]);
|
|
37
|
+
/**
|
|
38
|
+
* Mağaza görseli yuvası (`mobile-store/{appId}/assets`) — kaynak backend `MobileStoreAssetKind.cs` ve
|
|
39
|
+
* `MobileStoreAssetValidator.cs`; Studio kopyası `store-assets.validation.ts`. Parite:
|
|
40
|
+
* `test/mobile-store-assets.test.ts` (plans/mobil-yayin-mcp g-01).
|
|
41
|
+
*/
|
|
42
|
+
export const ASSET_KINDS = ['icon', 'adaptiveForeground', 'adaptiveBackground', 'adaptiveMonochrome', 'splash', 'featureGraphic', 'screenshot', 'promo'];
|
|
43
|
+
/** Derlemeye giren görseller dilsizdir (`MobileStoreAssetValidator.BuildKinds`); PNG zorunlu */
|
|
44
|
+
export const BUILD_ASSET_KINDS = ['icon', 'adaptiveForeground', 'adaptiveBackground', 'adaptiveMonochrome', 'splash'];
|
|
45
|
+
export const DEVICE_CLASSES = ['iphone69', 'ipad13', 'phone', 'tablet7', 'tablet10'];
|
|
46
|
+
export const MAX_ASSET_BYTES = 10_485_760;
|
|
47
|
+
export const MAX_IMAGES_PER_SLOT = 10;
|
|
48
|
+
/**
|
|
49
|
+
* Cihaz sınıfı → `page_screenshot` `device` argümanı. Çıktı = width·scale × height·scale ve mağazanın
|
|
50
|
+
* kabul ettiği ölçüdür; Studio "Önizlemeden üret" aynı tabloyu kullanır (`screenshot-capture.ts`
|
|
51
|
+
* `CAPTURE_TARGETS`). iPhone 6.9" ve iPad 13" alfa kanalı kabul etmez: kare JPEG çekilir.
|
|
52
|
+
*/
|
|
53
|
+
export const SCREENSHOT_CAPTURE_DEVICES = {
|
|
54
|
+
iphone69: { width: 440, height: 956, scale: 3 },
|
|
55
|
+
ipad13: { width: 1032, height: 1376, scale: 2 },
|
|
56
|
+
phone: { width: 360, height: 720, scale: 3 },
|
|
57
|
+
tablet7: { width: 600, height: 960, scale: 2 },
|
|
58
|
+
tablet10: { width: 800, height: 1280, scale: 2 }
|
|
59
|
+
};
|
|
60
|
+
/** Beyan anahtarları (`MobileStoreSettings.*Declaration`); iOS appPrivacy, ötekiler Android */
|
|
61
|
+
export const DECLARATION_KEYS = ['appPrivacy', 'dataSafety', 'contentRating', 'targetAudience', 'appAccess'];
|
|
62
|
+
/**
|
|
63
|
+
* Yuva kuralının istek gitmeden denetlenen kısmı (`MobileStoreAssetValidator`): derleme görseli dil
|
|
64
|
+
* almaz, ekran görüntüsü cihaz sınıfı ister, öteki türler cihaz sınıfı almaz. Ölçü/biçim/alfa
|
|
65
|
+
* denetimi dosyanın içeriğine bakar ve backend'de kalır (422 gövdesi ajana olduğu gibi döner).
|
|
66
|
+
*/
|
|
67
|
+
export function assetSlotProblem(kind, locale, deviceClass) {
|
|
68
|
+
if (BUILD_ASSET_KINDS.includes(kind) && locale !== undefined) {
|
|
69
|
+
return `'${kind}' derlemeye giren görseldir ve dilsizdir — locale verilmez`;
|
|
70
|
+
}
|
|
71
|
+
if (kind === 'screenshot' && deviceClass === undefined) {
|
|
72
|
+
return `'screenshot' cihaz sınıfı ister — deviceClass: ${DEVICE_CLASSES.join(' | ')}`;
|
|
73
|
+
}
|
|
74
|
+
if (kind !== 'screenshot' && deviceClass !== undefined) {
|
|
75
|
+
return `deviceClass yalnız 'screenshot' içindir — '${kind}' için verilmez`;
|
|
76
|
+
}
|
|
77
|
+
if (locale !== undefined && !LOCALE_PATTERN.test(locale)) {
|
|
78
|
+
return `locale '${locale}' biçimsiz — ${LOCALE_PATTERN.source} ('tr', 'en-US')`;
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
83
|
+
const text = (value) => typeof value === 'string' ? value : '';
|
|
84
|
+
const isBlank = (value) => text(value).trim().length === 0;
|
|
85
|
+
/** Backend `EmailAddress()` (ASP.NET Core uyumlu): tek `@`, başta ve sonda değil */
|
|
86
|
+
const isEmail = (value) => {
|
|
87
|
+
const index = value.indexOf('@');
|
|
88
|
+
return index > 0 && index !== value.length - 1 && index === value.lastIndexOf('@');
|
|
89
|
+
};
|
|
90
|
+
/** .NET `Uri.TryCreate(Absolute)` + `https` + host; `https:host` (çift eğik çizgisiz) reddedilir */
|
|
91
|
+
const isHttpsUrl = (value) => {
|
|
92
|
+
if (!/^https:\/\//i.test(value.trim()))
|
|
93
|
+
return false;
|
|
94
|
+
try {
|
|
95
|
+
const url = new URL(value);
|
|
96
|
+
return url.protocol === 'https:' && url.hostname.length > 0;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
/** Biçim hataları: backend `PUT`'u 422 ile reddedecek her alan (alan yolu = backend `errorFields` anahtarı). */
|
|
103
|
+
export function storeSettingsFormatErrors(settings) {
|
|
104
|
+
const errors = [];
|
|
105
|
+
const add = (field, message) => errors.push({ field, message });
|
|
106
|
+
const displayName = settings.displayName;
|
|
107
|
+
if (isBlank(displayName))
|
|
108
|
+
add('displayName', 'boş olamaz');
|
|
109
|
+
else if (text(displayName).length > DISPLAY_NAME_MAX_LENGTH)
|
|
110
|
+
add('displayName', `en çok ${DISPLAY_NAME_MAX_LENGTH} karakter`);
|
|
111
|
+
for (const field of ['bundleIdentifier', 'androidPackage']) {
|
|
112
|
+
const value = text(settings[field]);
|
|
113
|
+
if (isBlank(value))
|
|
114
|
+
add(field, 'boş olamaz');
|
|
115
|
+
else if (!PACKAGE_NAME_PATTERN.test(value))
|
|
116
|
+
add(field, `ters alan adı biçiminde olmalı (ör. com.firma.uygulama): ${PACKAGE_NAME_PATTERN.source}`);
|
|
117
|
+
}
|
|
118
|
+
const keyword = text(settings.androidPackage).split('.').find(segment => JAVA_KEYWORDS.has(segment));
|
|
119
|
+
if (keyword)
|
|
120
|
+
add('androidPackage', `'${keyword}' segmenti Java anahtar sözcüğü — Android paket adında kullanılamaz`);
|
|
121
|
+
const scheme = text(settings.scheme);
|
|
122
|
+
if (isBlank(scheme))
|
|
123
|
+
add('scheme', 'boş olamaz');
|
|
124
|
+
else if (!SCHEME_PATTERN.test(scheme))
|
|
125
|
+
add('scheme', `küçük harfle başlar, en az 3 karakter, yalnız a-z 0-9 + . -: ${SCHEME_PATTERN.source}`);
|
|
126
|
+
else if (scheme === RESERVED_SCHEME)
|
|
127
|
+
add('scheme', `'${RESERVED_SCHEME}' oynatıcı uygulamanın şeması — mağaza derlemesi alamaz`);
|
|
128
|
+
const version = text(settings.version);
|
|
129
|
+
if (isBlank(version))
|
|
130
|
+
add('version', 'boş olamaz');
|
|
131
|
+
else if (!VERSION_PATTERN.test(version))
|
|
132
|
+
add('version', 'MAJOR.MINOR.PATCH biçiminde olmalı, öndeki sıfır yok (ör. 1.2.0)');
|
|
133
|
+
for (const field of ['iosBuildNumber', 'androidVersionCode']) {
|
|
134
|
+
const value = settings[field];
|
|
135
|
+
if (value !== undefined && value !== null && (typeof value !== 'number' || !Number.isInteger(value) || value < 0 || value > MAX_BUILD_NUMBER)) {
|
|
136
|
+
add(field, `0 … ${MAX_BUILD_NUMBER} arası tam sayı`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const choices = [
|
|
140
|
+
['orientation', ORIENTATIONS],
|
|
141
|
+
['userInterfaceStyle', USER_INTERFACE_STYLES],
|
|
142
|
+
['splashResizeMode', SPLASH_RESIZE_MODES]
|
|
143
|
+
];
|
|
144
|
+
for (const [field, allowed] of choices) {
|
|
145
|
+
if (!allowed.includes(text(settings[field])))
|
|
146
|
+
add(field, `kabul edilen değerler: ${allowed.join(' | ')}`);
|
|
147
|
+
}
|
|
148
|
+
for (const field of ['adaptiveIconBackground', 'splashBackgroundColor']) {
|
|
149
|
+
if (!COLOR_PATTERN.test(text(settings[field])))
|
|
150
|
+
add(field, '#RRGGBB biçiminde renk olmalı');
|
|
151
|
+
}
|
|
152
|
+
for (const [key, value] of Object.entries(isObject(settings.permissions) ? settings.permissions : {})) {
|
|
153
|
+
if (!PERMISSION_KEY_PATTERN.test(key))
|
|
154
|
+
add(`permissions.${key}`, `modül anahtarı ${PERMISSION_KEY_PATTERN.source} biçiminde olmalı (ör. camera)`);
|
|
155
|
+
else if (value !== null && (isBlank(value) || text(value).length > PERMISSION_TEXT_MAX_LENGTH))
|
|
156
|
+
add(`permissions.${key}`, `null ya da 1–${PERMISSION_TEXT_MAX_LENGTH} karakter izin açıklaması`);
|
|
157
|
+
}
|
|
158
|
+
for (const [key, value] of Object.entries(isObject(settings.permissionModes) ? settings.permissionModes : {})) {
|
|
159
|
+
if (!PERMISSION_KEY_PATTERN.test(key))
|
|
160
|
+
add(`permissionModes.${key}`, `izin anahtarı ${PERMISSION_KEY_PATTERN.source} biçiminde olmalı; anahtarlar: mobile_store_get { detail: ['permissions'] }`);
|
|
161
|
+
else if (!PERMISSION_MODES.includes(text(value)))
|
|
162
|
+
add(`permissionModes.${key}`, `kabul edilen değerler: ${PERMISSION_MODES.join(' | ')}`);
|
|
163
|
+
}
|
|
164
|
+
const launchPermissions = Array.isArray(settings.launchPermissions) ? settings.launchPermissions : [];
|
|
165
|
+
for (const [index, key] of launchPermissions.entries()) {
|
|
166
|
+
if (!PERMISSION_KEY_PATTERN.test(text(key)))
|
|
167
|
+
add(`launchPermissions.${String(key)}`, `izin anahtarı ${PERMISSION_KEY_PATTERN.source} biçiminde olmalı; anahtarlar: mobile_store_get { detail: ['permissions'] }`);
|
|
168
|
+
else if (launchPermissions.indexOf(key) !== index)
|
|
169
|
+
add(`launchPermissions.${String(key)}`, 'anahtar iki kez yazılmış');
|
|
170
|
+
else if (isObject(settings.permissionModes) && settings.permissionModes[text(key)] === 'off')
|
|
171
|
+
add(`launchPermissions.${String(key)}`, `permissionModes.${String(key)} 'off': derlemeye dahil edilmeyen izin açılışta sorulamaz — kipi auto ya da on yapın ya da anahtarı listeden çıkarın`);
|
|
172
|
+
}
|
|
173
|
+
for (const [locale, listing] of Object.entries(isObject(settings.listing) ? settings.listing : {})) {
|
|
174
|
+
if (!LOCALE_PATTERN.test(locale)) {
|
|
175
|
+
add(`listing.${locale}`, "dil kodu geçersiz (ör. 'tr', 'en-US')");
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const entry = isObject(listing) ? listing : {};
|
|
179
|
+
for (const [field, max] of Object.entries(LISTING_LIMITS)) {
|
|
180
|
+
if (text(entry[field]).length > max)
|
|
181
|
+
add(`listing.${locale}.${field}`, `en çok ${max} karakter (${text(entry[field]).length} verildi)`);
|
|
182
|
+
}
|
|
183
|
+
const keywords = Array.isArray(entry.keywords) ? entry.keywords.map(text).join(',') : '';
|
|
184
|
+
if (keywords.length > KEYWORDS_MAX_LENGTH)
|
|
185
|
+
add(`listing.${locale}.keywords`, `virgülle birleşik en çok ${KEYWORDS_MAX_LENGTH} karakter (${keywords.length} verildi)`);
|
|
186
|
+
}
|
|
187
|
+
const urls = isObject(settings.urls) ? settings.urls : {};
|
|
188
|
+
for (const field of URL_FIELDS) {
|
|
189
|
+
if (!isBlank(urls[field]) && !isHttpsUrl(text(urls[field])))
|
|
190
|
+
add(`urls.${field}`, 'boş ya da mutlak https:// adres olmalı');
|
|
191
|
+
}
|
|
192
|
+
const play = isObject(settings.play) ? settings.play : {};
|
|
193
|
+
const review = isObject(settings.review) ? settings.review : {};
|
|
194
|
+
const apple = isObject(settings.apple) ? settings.apple : {};
|
|
195
|
+
if (!isBlank(play.contactEmail) && !isEmail(text(play.contactEmail)))
|
|
196
|
+
add('play.contactEmail', 'geçerli e-posta olmalı');
|
|
197
|
+
if (play.releaseStatus !== undefined && play.releaseStatus !== null && !RELEASE_STATUSES.includes(text(play.releaseStatus)))
|
|
198
|
+
add('play.releaseStatus', `kabul edilen değerler: ${RELEASE_STATUSES.join(' | ')}`);
|
|
199
|
+
if (!isBlank(review.email) && !isEmail(text(review.email)))
|
|
200
|
+
add('review.email', 'geçerli e-posta olmalı');
|
|
201
|
+
if (text(apple.copyright).length > COPYRIGHT_MAX_LENGTH)
|
|
202
|
+
add('apple.copyright', `en çok ${COPYRIGHT_MAX_LENGTH} karakter`);
|
|
203
|
+
return errors;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Mağazaya YÜKLEME (testflight/internal) için boş kalan gizli olmayan alanlar — `build` hedefini
|
|
207
|
+
* etkilemez, taslak kaydı engellemez. Kesin liste ön kontroldür (P-01, varsayılan dil projeden gelir).
|
|
208
|
+
*/
|
|
209
|
+
export function storeSettingsMissingForUpload(settings) {
|
|
210
|
+
const urls = isObject(settings.urls) ? settings.urls : {};
|
|
211
|
+
const apple = isObject(settings.apple) ? settings.apple : {};
|
|
212
|
+
const categories = isObject(apple.categories) ? apple.categories : {};
|
|
213
|
+
const play = isObject(settings.play) ? settings.play : {};
|
|
214
|
+
const listings = Object.values(isObject(settings.listing) ? settings.listing : {}).filter(isObject);
|
|
215
|
+
const missing = [];
|
|
216
|
+
if (!listings.some(listing => !isBlank(listing.title) && !isBlank(listing.description)))
|
|
217
|
+
missing.push('listing.<dil>.title + description');
|
|
218
|
+
if (isBlank(urls.privacyPolicy))
|
|
219
|
+
missing.push('urls.privacyPolicy');
|
|
220
|
+
if (isBlank(categories.primary))
|
|
221
|
+
missing.push('apple.categories.primary (iOS)');
|
|
222
|
+
if (isBlank(apple.copyright))
|
|
223
|
+
missing.push('apple.copyright (iOS)');
|
|
224
|
+
if (isBlank(play.contactEmail))
|
|
225
|
+
missing.push('play.contactEmail (Android)');
|
|
226
|
+
return missing;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Backend `PUT` tam satırı yazar: gönderilmeyen alan varsayılana döner (`displayName` boşalır → 422,
|
|
230
|
+
* `listing` silinir). Yama bu yüzden okunan kaydın üstüne birleştirilir: düz nesneler alan alan,
|
|
231
|
+
* dizi ve skaler değer yerine geçer. Sayaçlar yalnız yamada varsa gider — okunan sayacı geri yazmak,
|
|
232
|
+
* arada derleme başlamışsa kilit ihlali (422) üretirdi (`null` = değiştirme).
|
|
233
|
+
*/
|
|
234
|
+
export function mergeStoreSettings(current, patch) {
|
|
235
|
+
const merge = (base, overlay) => {
|
|
236
|
+
if (!isObject(base) || !isObject(overlay))
|
|
237
|
+
return overlay;
|
|
238
|
+
return Object.fromEntries([...new Set([...Object.keys(base), ...Object.keys(overlay)])]
|
|
239
|
+
.map(key => [key, key in overlay ? merge(base[key], overlay[key]) : base[key]]));
|
|
240
|
+
};
|
|
241
|
+
const merged = merge(current, patch);
|
|
242
|
+
for (const counter of ['iosBuildNumber', 'androidVersionCode']) {
|
|
243
|
+
if (!(counter in patch))
|
|
244
|
+
delete merged[counter];
|
|
245
|
+
}
|
|
246
|
+
return merged;
|
|
247
|
+
}
|
|
248
|
+
/** Yamanın gerçekten değiştirdiği yaprak alan yolları (`listing.tr.title`, `bundleIdentifier`). */
|
|
249
|
+
export function changedStoreFields(current, patch, prefix = '') {
|
|
250
|
+
return Object.entries(patch).flatMap(([key, value]) => {
|
|
251
|
+
const before = current[key];
|
|
252
|
+
const path = `${prefix}${key}`;
|
|
253
|
+
if (isObject(value) && isObject(before))
|
|
254
|
+
return changedStoreFields(before, value, `${path}.`);
|
|
255
|
+
return JSON.stringify(value) === JSON.stringify(before ?? null) ? [] : [path];
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
const guide = "platform_guide('mobile-publish')";
|
|
259
|
+
/**
|
|
260
|
+
* MOB-023 — taşınan küme derlemede donar: kullanılan izin mağazadaki son derlemede (backend'in
|
|
261
|
+
* `missingFromStoreBuilds`'i) yoksa kurulu uygulama onu isteyemez. Production kullanıyorsa bugünün sorunudur;
|
|
262
|
+
* yalnız okunan ortam kullanıyorsa dağıtımdan sonra olacaktır. Kip `off` ise sessiz: yeni derleme de taşımaz
|
|
263
|
+
* (o çelişkiyi P-12 söyler). Kullanılmayan iznin derlemede olmaması budamanın işidir.
|
|
264
|
+
*/
|
|
265
|
+
export function permissionStoreBuildWarnings(permissions, environment) {
|
|
266
|
+
return permissions.flatMap((entry) => {
|
|
267
|
+
const builds = (Array.isArray(entry.missingFromStoreBuilds) ? entry.missingFromStoreBuilds : []).filter(isObject);
|
|
268
|
+
if (builds.length === 0 || entry.mode === 'off')
|
|
269
|
+
return [];
|
|
270
|
+
const names = builds.map(build => `${text(build.platform)} ${text(build.appVersion)} (${String(build.buildNumber)})`).join(', ');
|
|
271
|
+
const productionUsage = isObject(entry.build) && typeof entry.build.usageCount === 'number' ? entry.build.usageCount : 0;
|
|
272
|
+
const usage = Array.isArray(entry.usage) ? entry.usage.length : 0;
|
|
273
|
+
if (productionUsage > 0)
|
|
274
|
+
return [`${text(entry.key)}: production kullanıyor ama mağazadaki son derleme taşımıyor (${names}) — kurulu uygulamada izin istenemez ('unavailable'); yeni bir mağaza derlemesi gerekir (MOB-023, ${guide}).`];
|
|
275
|
+
return usage > 0
|
|
276
|
+
? [`${text(entry.key)}: ${environment} kullanıyor, mağazadaki son derleme taşımıyor (${names}) — production'a dağıtıldıktan sonra yeni bir mağaza derlemesi gerekir (MOB-023, ${guide}).`]
|
|
277
|
+
: [];
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* MOB-025 — açılışta sorma kabuğun ayrı bir yeteneğidir (`shell.carriesLaunchPermissions`). Yayındaki kabuk onu
|
|
282
|
+
* taşımıyorsa ayar saklanır ama derleme sormaz: liste manifeste yazılmaz. Eski backend alanı söylemez; o zaman
|
|
283
|
+
* iddia edilmez.
|
|
284
|
+
*/
|
|
285
|
+
export function permissionLaunchShellWarnings(permissions, shell) {
|
|
286
|
+
const asked = permissions.filter(entry => entry.askOnLaunch === true).map(entry => text(entry.key));
|
|
287
|
+
if (asked.length === 0 || !isObject(shell) || shell.carriesLaunchPermissions !== false)
|
|
288
|
+
return [];
|
|
289
|
+
return [`${asked.join(', ')}: açılışta sorulacak diye ayarlı ama yayındaki kabuk paketi (${text(shell.version)}) açılışta izin sormuyor — ayar saklanır, mağaza derlemesi sormaz (ön kontrol P-12 uyarır). Daha yeni bir kabuk yayınlanana kadar izni bir akış adımından isteyin (MOB-025, ${guide}).`];
|
|
290
|
+
}
|
|
291
|
+
/** MOB-022 — `definition` birleşmiş kayıttır; biçim hatası backend'in 422'siyle aynı ret (block), eksik alan uyarı. */
|
|
292
|
+
export const mobileStorePolicyRules = [
|
|
293
|
+
{
|
|
294
|
+
id: 'MOB-022',
|
|
295
|
+
module: 'mobileStore',
|
|
296
|
+
appliesTo: ['update'],
|
|
297
|
+
sourceRef: 'MobileStoreSettingsValidator (zeyrek-backend/docs/mobile-builds.md §Doğrulama tablosu); yükleme eksikleri MobileStorePreflightService P-01',
|
|
298
|
+
check: (definition) => {
|
|
299
|
+
const errors = storeSettingsFormatErrors(definition);
|
|
300
|
+
const missing = storeSettingsMissingForUpload(definition);
|
|
301
|
+
return [
|
|
302
|
+
...(errors.length > 0
|
|
303
|
+
? [{
|
|
304
|
+
ruleId: 'MOB-022',
|
|
305
|
+
severity: 'block',
|
|
306
|
+
message: `Mağaza ayarı biçimsiz — backend PUT'u 422 ile reddeder, hiçbir alan yazılmaz: ${errors.map(error => `${error.field}: ${error.message}`).join(' · ')}`,
|
|
307
|
+
guide
|
|
308
|
+
}]
|
|
309
|
+
: []),
|
|
310
|
+
...(missing.length > 0
|
|
311
|
+
? [{
|
|
312
|
+
ruleId: 'MOB-022',
|
|
313
|
+
severity: 'warn',
|
|
314
|
+
message: `Mağazaya yükleme (testflight/internal) için eksik: ${missing.join(', ')}. Kayıt taslak olarak yazılır ve 'build' hedefini etkilemez; kesin liste mobile_build_start { dryRun: true } ön kontrolündedir. Görseller mobile_asset_create ile, beyanlar kullanıcının onayıyla mobile_store_update { declarations } ile yazılır; gizli bilgi MCP'den yazılmaz — Studio › Yayın › Hesaplar.`,
|
|
315
|
+
guide
|
|
316
|
+
}]
|
|
317
|
+
: [])
|
|
318
|
+
];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
];
|