@appaflytech/zeyrek-ai-mcp 0.0.25 → 0.0.26

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.
@@ -69,12 +69,21 @@ function carriesValue(value) {
69
69
  return value.trim() !== '';
70
70
  return true;
71
71
  }
72
- function workflowCallSites(body) {
72
+ /**
73
+ * `type` tipindeki adımlar ve `loop` adımının `rule.stepType === type` olan çocuk kuralı.
74
+ * `LoopStep.cs` çocuğu `rule.Children.FirstOrDefault()` ile aynı tipin keyed `IStep`'ine verir:
75
+ * çocuk, üst seviyedeki aynı tip adımla AYNI kuralı okur ve aynı denetimden geçmelidir. İki
76
+ * kullanıcısı var: WF-032 (`workflow`) ve WF-MF-001 (`microfunction`; loop içinde koştuğu
77
+ * ölçüldü 2026-09-28, zeyrek-backend/docs/microfunction/03-workflow-adimi.md §Loop içinde).
78
+ * Etiketteki "(loop çocuğu)" bulguyu okuyan
79
+ * ajanı adımın `rule.stepRule`'una yönlendirir.
80
+ */
81
+ function stepCallSites(body, type) {
73
82
  return workflowSteps(body).flatMap((step) => {
74
83
  const rule = (step.rule ?? {});
75
- if (step.type === 'workflow')
84
+ if (step.type === type)
76
85
  return [{ step, rule, label: stepLabel(step) }];
77
- if (step.type === 'loop' && rule.stepType === 'workflow' && rule.stepRule && typeof rule.stepRule === 'object') {
86
+ if (step.type === 'loop' && rule.stepType === type && rule.stepRule && typeof rule.stepRule === 'object') {
78
87
  return [{ step, rule: rule.stepRule, label: `${stepLabel(step)} (loop çocuğu)` }];
79
88
  }
80
89
  return [];
@@ -713,19 +722,17 @@ export const policyRules = [
713
722
  id: 'WF-MF-001',
714
723
  module: 'workflow',
715
724
  appliesTo: ['create', 'update', 'preview'],
716
- sourceRef: "MicrofunctionStep.cs: rule.MicrofunctionId ile kayıt yüklenir, Status != Published ise FailedOutput(MicrofunctionNotPublishedException) — adım hata dalına düşer, akış 200 dönse bile iş yapılmaz. Ölçüldü 2026-09-10 (B4 doğrulaması: taslak fonksiyona bağlı uç 500 MicrofunctionNotPublishedException)",
717
- check: definition => {
718
- const body = workflowBody(definition);
719
- return workflowSteps(body)
720
- .filter(step => step.type === 'microfunction')
721
- .flatMap((step) => {
722
- const rule = (step.rule ?? {});
725
+ sourceRef: "MicrofunctionStep.cs: rule.MicrofunctionId ile kayıt yüklenir, Status != Published ise FailedOutput(MicrofunctionNotPublishedException) — adım hata dalına düşer, akış 200 dönse bile iş yapılmaz. Ölçüldü 2026-09-10 (B4 doğrulaması: taslak fonksiyona bağlı uç 500 MicrofunctionNotPublishedException). Loop çocuğu (rule.stepType: 'microfunction', rule.stepRule) aynı adımla koşar — ölçüldü 2026-09-28, microfunction-faz-2/development; taslak seçen loop İLK iterasyonda fail dalına düşer ve durur (ölçülen çıktı [{ item: 1 }])",
726
+ check: (definition, context) => {
727
+ const body = workflowBody(definition, context.workflowKind);
728
+ return stepCallSites(body, 'microfunction')
729
+ .flatMap(({ rule, label }) => {
723
730
  const microfunctionId = rule.microfunctionId;
724
731
  if (!hasText(microfunctionId)) {
725
732
  return [{
726
733
  ruleId: 'WF-MF-001',
727
734
  severity: 'block',
728
- message: `'${stepLabel(step)}' microfunction adımında rule.microfunctionId yok — adım hangi fonksiyonu koşturacağını bilmez. microfunction_list(status: 'published') ile id seçin; argümanlar rule.expression'a yazılır (fonksiyonun parameterDto'su varsa o şemaya göre).`,
735
+ message: `'${label}' microfunction adımında rule.microfunctionId yok — adım hangi fonksiyonu koşturacağını bilmez. microfunction_list(status: 'published') ile id seçin; argümanlar rule.expression'a yazılır (fonksiyonun parameterDto'su varsa o şemaya göre).`,
729
736
  guide: 'ngapps://guides/microfunction'
730
737
  }];
731
738
  }
@@ -733,7 +740,7 @@ export const policyRules = [
733
740
  return [{
734
741
  ruleId: 'WF-MF-001',
735
742
  severity: 'block',
736
- message: `'${stepLabel(step)}' adımının rule.microfunctionId'si GUID değil: '${String(microfunctionId)}'. Platform alanı Guid'e çeviremediği için 400 döner.`,
743
+ message: `'${label}' adımının rule.microfunctionId'si GUID değil: '${String(microfunctionId)}'. Platform alanı Guid'e çeviremediği için 400 döner.`,
737
744
  guide: 'ngapps://guides/microfunction'
738
745
  }];
739
746
  }
@@ -746,7 +753,7 @@ export const policyRules = [
746
753
  module: 'workflow',
747
754
  appliesTo: ['create', 'update', 'preview'],
748
755
  sourceRef: "WorkflowStep.cs EvaluateAsync: kural yalnız rule.WorkflowId ve rule.Expression okur; girdi workflow.HasParameter iken Expression'ın DataTransferObjectExpression.Eval'iyle bağlanır, başka hiçbir alan okunmaz. Studio WorkflowTrigger.svelte de yalnız bu iki alanı yazar ve expression'ı çağrılan akışın parameterScheme'inden nesne literali olarak doldurur. RFQ koşusu W-7 (2026-09-14): payloadExpression/customParameters kaydedildi, alt akış girdisiz koştu",
749
- check: (definition, context) => workflowCallSites(workflowBody(definition, context.workflowKind)).flatMap(({ label, rule }) => {
756
+ check: (definition, context) => stepCallSites(workflowBody(definition, context.workflowKind), 'workflow').flatMap(({ label, rule }) => {
750
757
  const workflowId = rule.workflowId;
751
758
  if (!hasText(workflowId)) {
752
759
  return [{
@@ -2206,7 +2213,7 @@ export const policyRules = [
2206
2213
  findings.push({
2207
2214
  ruleId: 'WF-018',
2208
2215
  severity: 'block',
2209
- message: `'${stepLabel(step)}' loop step'inde rule.stepRule yok${hasChildren ? " — ama rule.children dolu: çocuk kural alanının adı 'children' DEĞİL 'stepRule'dur (tekil)" : ''}. Çocuksuz loop çalışma anında NullReferenceException verir ve hata mesajı arrayExpression'ı suçlar. Çocuğun kendi rule gövdesini rule.stepRule'a koyun; loop'un çıktısı [{ item, result }] dizisidir. Geçerli öğeye 'loopItem' ile erişilir AMA yalnız loop'un kendi değerlendirdiği ifadelerde (table çocuğunun fields[].value / filters[].value gibi) — 'code' çocuğunda loopItem TANIMSIZDIR ve adım "loopItem is not defined" ile düşer (ölçüldü 2026-09-16); her öğe için hesabı arrayExpression'da önden yapın.`,
2216
+ message: `'${stepLabel(step)}' loop step'inde rule.stepRule yok${hasChildren ? " — ama rule.children dolu: çocuk kural alanının adı 'children' DEĞİL 'stepRule'dur (tekil)" : ''}. Çocuksuz loop çalışma anında NullReferenceException verir ve hata mesajı arrayExpression'ı suçlar. Çocuğun kendi rule gövdesini rule.stepRule'a koyun; loop'un çıktısı [{ item, result }] dizisidir. Geçerli öğeye 'loopItem' ile erişilir AMA yalnız loop'un kendi değerlendirdiği ifadelerde (table çocuğunun fields[].value / filters[].value, workflow ve microfunction çocuğunun expression'ı gibi) — 'code' çocuğunda loopItem TANIMSIZDIR ve adım "loopItem is not defined" ile düşer (ölçüldü 2026-09-16); her öğe için hesabı arrayExpression'da önden yapın.`,
2210
2217
  guide: 'ngapps://guides/workflow'
2211
2218
  });
2212
2219
  }
@@ -2974,15 +2981,13 @@ export const policyRules = [
2974
2981
  export async function microfunctionStepFindings(platform, project, environment, definition, kind, policyOverride = false) {
2975
2982
  if (platform.config.policyMode === 'off')
2976
2983
  return [];
2977
- const steps = workflowSteps(workflowBody(definition, kind))
2978
- .filter(step => step.type === 'microfunction')
2979
- .filter(step => hasText((step.rule ?? {}).microfunctionId));
2980
- if (steps.length === 0)
2984
+ const sites = stepCallSites(workflowBody(definition, kind), 'microfunction')
2985
+ .filter(site => hasText(site.rule.microfunctionId));
2986
+ if (sites.length === 0)
2981
2987
  return [];
2982
2988
  const records = new Map();
2983
2989
  const findings = [];
2984
- for (const step of steps) {
2985
- const rule = (step.rule ?? {});
2990
+ for (const { rule, label } of sites) {
2986
2991
  const microfunctionId = String(rule.microfunctionId);
2987
2992
  if (!records.has(microfunctionId)) {
2988
2993
  try {
@@ -3000,7 +3005,7 @@ export async function microfunctionStepFindings(platform, project, environment,
3000
3005
  findings.push({
3001
3006
  ruleId: 'WF-MF-001',
3002
3007
  severity: 'block',
3003
- message: `'${stepLabel(step)}' adımının microfunctionId'si (${microfunctionId}) bu ortamda YOK. Adım kuralı step_rules.microfunction_id ile kayda FK'lıdır: gövde gitseydi platform 400 dönerdi. microfunction_list ile bu ortamdaki kayıtları görün — fonksiyon başka bir dalda/ortamda kalmış olabilir.`,
3008
+ message: `'${label}' adımının microfunctionId'si (${microfunctionId}) bu ortamda YOK. Adım kuralı step_rules.microfunction_id ile kayda FK'lıdır: gövde gitseydi platform 400 dönerdi. microfunction_list ile bu ortamdaki kayıtları görün — fonksiyon başka bir dalda/ortamda kalmış olabilir.`,
3004
3009
  guide: 'ngapps://guides/microfunction'
3005
3010
  });
3006
3011
  continue;
@@ -3010,7 +3015,7 @@ export async function microfunctionStepFindings(platform, project, environment,
3010
3015
  findings.push({
3011
3016
  ruleId: 'WF-MF-001',
3012
3017
  severity: 'block',
3013
- message: `'${stepLabel(step)}' adımı '${String(record.name ?? microfunctionId)}' fonksiyonunu seçiyor ama kaydın durumu '${status}'${status === 'publish-failed' && hasText(record.publishError) ? ` (publishError: ${String(record.publishError)})` : ''}. Step YALNIZ yayındaki kaydı koşturur: MicrofunctionStep kaydı yükleyip Status != Published görünce MicrofunctionNotPublishedException ile FAIL dalına düşer — akış kurulur, kaydedilir ve koşumda sessizce hata yoluna girer. Önce microfunction_publish çağırın ve microfunction_get ile 'published' olduğunu görün.`,
3018
+ message: `'${label}' adımı '${String(record.name ?? microfunctionId)}' fonksiyonunu seçiyor ama kaydın durumu '${status}'${status === 'publish-failed' && hasText(record.publishError) ? ` (publishError: ${String(record.publishError)})` : ''}. Step YALNIZ yayındaki kaydı koşturur: MicrofunctionStep kaydı yükleyip Status != Published görünce MicrofunctionNotPublishedException ile FAIL dalına düşer — akış kurulur, kaydedilir ve koşumda sessizce hata yoluna girer. Önce microfunction_publish çağırın ve microfunction_get ile 'published' olduğunu görün.`,
3014
3019
  guide: 'ngapps://guides/microfunction'
3015
3020
  });
3016
3021
  continue;
@@ -3019,7 +3024,7 @@ export async function microfunctionStepFindings(platform, project, environment,
3019
3024
  findings.push({
3020
3025
  ruleId: 'WF-MF-001',
3021
3026
  severity: 'warn',
3022
- message: `'${stepLabel(step)}' adımının fonksiyonu ('${String(record.name ?? microfunctionId)}') şu anda yayınlanıyor. Yayın ASENKRONDUR: bu akış şimdi koşarsa adım fail dalına düşer. microfunction_get ile 'published' olduğunu doğrulayın (yayın başarısız olursa durum 'publish-failed' olur).`,
3027
+ message: `'${label}' adımının fonksiyonu ('${String(record.name ?? microfunctionId)}') şu anda yayınlanıyor. Yayın ASENKRONDUR: bu akış şimdi koşarsa adım fail dalına düşer. microfunction_get ile 'published' olduğunu doğrulayın (yayın başarısız olursa durum 'publish-failed' olur).`,
3023
3028
  guide: 'ngapps://guides/microfunction'
3024
3029
  });
3025
3030
  }
@@ -3035,7 +3040,7 @@ export async function microfunctionStepFindings(platform, project, environment,
3035
3040
  findings.push({
3036
3041
  ruleId: 'WF-MF-001',
3037
3042
  severity: 'warn',
3038
- message: `'${stepLabel(step)}' adımında rule.expression boş ama '${String(record.name ?? microfunctionId)}' fonksiyonunun bir parametre DTO'su var (parameterDtoId: ${String(record.parameterDtoId)}). Fonksiyon args olarak boş nesne alır ve kendi alanlarını undefined görür. Argümanları ifadeyle geçirin — şemayı microfunction_get çıktısındaki parameterScheme verir.`,
3043
+ message: `'${label}' adımında rule.expression boş ama '${String(record.name ?? microfunctionId)}' fonksiyonunun bir parametre DTO'su var (parameterDtoId: ${String(record.parameterDtoId)}). Fonksiyon args olarak boş nesne alır ve kendi alanlarını undefined görür. Argümanları ifadeyle geçirin — şemayı microfunction_get çıktısındaki parameterScheme verir.`,
3039
3044
  guide: 'ngapps://guides/microfunction'
3040
3045
  });
3041
3046
  }
@@ -3061,7 +3066,7 @@ export async function workflowStepFindings(platform, project, environment, appli
3061
3066
  : hasText(definition.applicationId) ? String(definition.applicationId) : undefined;
3062
3067
  if (application === undefined)
3063
3068
  return [];
3064
- const sites = workflowCallSites(workflowBody(definition, kind))
3069
+ const sites = stepCallSites(workflowBody(definition, kind), 'workflow')
3065
3070
  .filter(site => GUID_PATTERN.test(String(site.rule.workflowId ?? '')));
3066
3071
  if (sites.length === 0)
3067
3072
  return [];
@@ -131,6 +131,34 @@ kullanılabilir. Kuralı iki alan taşır:
131
131
  - `workflow_preview` adımı GERÇEK runtime'da koşturur; preview'ın rollback garantisi fonksiyonun
132
132
  dış dünyada yaptığı işi geri ALMAZ.
133
133
 
134
+ ### Loop içinde
135
+
136
+ Loop adımı dizinin her öğesi için fonksiyonu bir kez çağırır. Çocuğun tipi loop'un kendi
137
+ `rule.stepType`'ında, kuralı `rule.stepRule`'dadır (tekil — `children` değil, WF-018):
138
+
139
+ ```jsonc
140
+ { "id": "<GUID>", "name": "her", "type": "loop",
141
+ "rule": {
142
+ "stepType": "microfunction",
143
+ "arrayExpression": "input.kalemler || []",
144
+ "stepRule": { "stepType": "microfunction", "microfunctionId": "<published id>", "expression": "({ x: loopItem.x })" }
145
+ },
146
+ "branches": [ /* success + fail */ ] }
147
+ ```
148
+
149
+ - Çıktı `[{ item, result }]` dizisidir: `result` fonksiyonun o öğedeki dönüşü. Sonraki adımda
150
+ `her.data.map(r => r.result)`.
151
+ - **Öğe fonksiyona yalnız `args` ile gider.** `expression` loop'un motorunda değerlendirilir:
152
+ `loopItem`, `input` ve loop'tan önceki adımlar orada görünür. `context.input` akışın kendi
153
+ girdisidir, iterasyonun öğesi DEĞİL.
154
+ - `context.steps` loop'tan önce koşmuş adımları taşır (2026-09-28'den önce loop içinde boş
155
+ geliyordu; backend düzeltmesi).
156
+ - WF-MF-001 loop çocuğunu da denetler; bulgu adımı `her (loop çocuğu)` diye adlandırır. Taslak bir
157
+ fonksiyonu seçen loop ilk iterasyonda fail dalına düşer ve orada durur.
158
+ - Her iterasyon önceki adımların çıktısını `context.steps` ile yeniden taşır ve bu da
159
+ `MaxPayloadBytes` (5 MB) sınırına sayılır: büyük bir sorgudan sonra koşan loop'ta sınır
160
+ iterasyon başına dolabilir.
161
+
134
162
  Tam gövde örneği: `ngapps://examples/microfunction-node-sum`.
135
163
 
136
164
  ## Built-In ve AWS Lambda farkı
@@ -373,7 +373,7 @@ gidilir, hiçbiri tutmazsa `else` dalı yürür:
373
373
 
374
374
  | Step | workflow | automation | middleware |
375
375
  |------|:-:|:-:|:-:|
376
- | start, condition, code, loop, table, query, http, workflow, email, file-upload | ✓ | ✓ | ✓ |
376
+ | start, condition, code, loop, table, query, http, workflow, microfunction, email, file-upload | ✓ | ✓ | ✓ |
377
377
  | variable (Set Variable), set-user, setcookie, redirect | – | – | ✓ |
378
378
  | response | ✓ | – | ✓ |
379
379
  | convert | ✓ | – | – |
@@ -521,6 +521,7 @@ Tek uçta "başlık + N alt kayıt" yazmanın yolu budur (anket + sorular + seç
521
521
  `fields[].value` / `filters[].value` ifadelerinde `loopItem.<alan>` yazılır (ölçüldü 2026-09-16:
522
522
  `table` çocuğunun filtresinde `loopItem.slug` → `'super-admin'`); `input` ve önceki adımlar
523
523
  (`createSurvey.data.id`) da görünmeye devam eder.
524
+ - **`microfunction` çocuğunda `loopItem` argüman ifadesinde görünür** (`stepRule.expression`, loop'un motorunda değerlendirilir); fonksiyon öğeyi yalnız `args` ile alır. Ayrıntı: `platform_guide('microfunction')` §Workflow adımı → Loop içinde.
524
525
  - **`code` çocuğunda `loopItem` YOKTUR (ölçüm 2026-09-16).** `code` adımı kendi JS motorunu kurar
525
526
  ve `LoopStep`'in `loopItem` ataması oraya ulaşmaz: adım **`Error: loopItem is not defined`** ile
526
527
  düşer, o yinelemenin çıktısında `result` hiç oluşmaz. Motorda görünenler `input` · `system` ·
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appaflytech/zeyrek-ai-mcp",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "type": "module",
5
5
  "description": "Zeyrek (NgApps) platform APIs as MCP tools — data, logic and Studio design surface in one gateway",
6
6
  "license": "UNLICENSED",