@appaflytech/zeyrek-ai-mcp 0.0.55 → 0.0.57
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/config.js +3 -1
- package/dist/knowledge/backendConstraints.js +12 -0
- package/dist/knowledge/customDomain.js +76 -0
- package/dist/platform/errors.js +27 -3
- package/dist/resources/guides/custom-domain.md +56 -0
- package/dist/resources/guides/deployment.md +9 -2
- package/dist/resources/guides/expressions.md +1 -1
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/CreateEntityCommand.json +3 -0
- package/dist/resources/schemas/CreateWorkflowCommand.json +3 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +3 -0
- package/dist/resources/schemas/UpdateWorkflowCommand.json +3 -0
- package/dist/server.js +2 -0
- package/dist/tools/customDomains.js +73 -0
- package/dist/tools/deployments.js +1 -1
- package/dist/tools/platformInfo.js +1 -0
- package/package.json +2 -1
package/dist/config.js
CHANGED
|
@@ -32,6 +32,7 @@ export const moduleNames = [
|
|
|
32
32
|
"dependency",
|
|
33
33
|
"deployment",
|
|
34
34
|
"environment",
|
|
35
|
+
"customDomain",
|
|
35
36
|
"merge",
|
|
36
37
|
"activity",
|
|
37
38
|
"revision",
|
|
@@ -70,6 +71,7 @@ export const modulePresets = {
|
|
|
70
71
|
"access",
|
|
71
72
|
"dependency",
|
|
72
73
|
"environment",
|
|
74
|
+
"customDomain",
|
|
73
75
|
"merge",
|
|
74
76
|
"activity",
|
|
75
77
|
"revision",
|
|
@@ -106,7 +108,7 @@ export const modulePresets = {
|
|
|
106
108
|
"mobile",
|
|
107
109
|
"assistant",
|
|
108
110
|
],
|
|
109
|
-
admin: ["platform", "template", "organization", "deployment", "environment", "merge", "activity"],
|
|
111
|
+
admin: ["platform", "template", "organization", "deployment", "environment", "customDomain", "merge", "activity"],
|
|
110
112
|
};
|
|
111
113
|
function expandModuleNames(entries) {
|
|
112
114
|
const modules = [];
|
|
@@ -822,6 +822,18 @@ export const backendRules = [
|
|
|
822
822
|
guide: 'ngapps://guides/entity',
|
|
823
823
|
check: body => entityTransferFindings(body)
|
|
824
824
|
},
|
|
825
|
+
{
|
|
826
|
+
id: 'ENT-019',
|
|
827
|
+
module: 'entity',
|
|
828
|
+
commands: { create: 'CreateEntityCommand', update: 'UpdateEntityCommand' },
|
|
829
|
+
status: 400,
|
|
830
|
+
summary: "roles tablosunda recordTransferSkipExisting açılamaz",
|
|
831
|
+
sourceRef: 'RecordTransferValidator.ValidateAsync: requestedSkipExisting && entity.Id == Defaults.RoleEntityGuid ⇒ RecordTransferSkipExistingNotAvailableForRolesException (ADR 0072, K-4)',
|
|
832
|
+
guide: 'ngapps://guides/deployment',
|
|
833
|
+
check: body => String(body.slug ?? '').toLowerCase() === 'roles' && body.recordTransferSkipExisting === true
|
|
834
|
+
? ["recordTransferSkipExisting: Keeping existing rows isn't available for 'roles' — roller kendi taşıyıcılarıyla (Module.Role) aktarılır, satır parçasıyla değil; ayar orada uygulanamadığı için platform 400 döner. Ayarı kapalı bırakın."]
|
|
835
|
+
: []
|
|
836
|
+
},
|
|
825
837
|
{
|
|
826
838
|
id: 'MS-017',
|
|
827
839
|
module: 'microservice',
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { isIP } from 'node:net';
|
|
2
|
+
import { domainToASCII } from 'node:url';
|
|
3
|
+
import { getDomain } from 'tldts-icann';
|
|
4
|
+
const wildcardPrefix = '*.';
|
|
5
|
+
const hostPattern = /^(?=.{4,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]([a-z0-9-]{0,61}[a-z0-9])$/;
|
|
6
|
+
const pendingStates = new Set(['pending_dns', 'verifying']);
|
|
7
|
+
export function normalizeHost(host) {
|
|
8
|
+
const trimmed = host.trim().replace(/\.$/, '').toLowerCase();
|
|
9
|
+
const isWildcard = trimmed.startsWith(wildcardPrefix);
|
|
10
|
+
const name = isWildcard ? trimmed.slice(wildcardPrefix.length) : trimmed;
|
|
11
|
+
const ascii = domainToASCII(name) || name;
|
|
12
|
+
return isWildcard ? `${wildcardPrefix}${ascii}` : ascii;
|
|
13
|
+
}
|
|
14
|
+
export const isPattern = (host) => host.startsWith(wildcardPrefix);
|
|
15
|
+
// Studio'nun kuralıyla aynı (`apps/studio/src/features/custom-domain/custom-domain.functions.ts` `isApex`): kök public
|
|
16
|
+
// suffix listesinden gelir (kök `docs/adr/0027`), `firma.com.tr` apex'tir. Yalnız DNS yönergesinin kayıt tipini seçer, reddetmez.
|
|
17
|
+
export const isApex = (host) => {
|
|
18
|
+
const name = isPattern(host) ? host.slice(wildcardPrefix.length) : host;
|
|
19
|
+
return (getDomain(name) ?? name) === host;
|
|
20
|
+
};
|
|
21
|
+
/** Backend'in reddedeceği bir host için ne · neden · ne yapılacak; geçen host için null. */
|
|
22
|
+
export function hostProblem(host, kind, platformBaseDomains) {
|
|
23
|
+
const normalized = normalizeHost(host);
|
|
24
|
+
const name = isPattern(normalized) ? normalized.slice(wildcardPrefix.length) : normalized;
|
|
25
|
+
if (isPattern(normalized) && kind !== 'pattern') {
|
|
26
|
+
return `'${host}' bir dal kalıbı (joker '*.'): joker yalnız custom_domain_pattern_create ile açılır, bu araçta kullanılmaz.`;
|
|
27
|
+
}
|
|
28
|
+
if (!isPattern(normalized) && kind === 'pattern') {
|
|
29
|
+
return `'${host}' kalıp değil: dal kalıbı '*.' ile başlar (ör. *.ornek.com). Tek bir adres için custom_domain_create kullanın.`;
|
|
30
|
+
}
|
|
31
|
+
if (!name.includes('.') || isIP(name) !== 0 || platformBaseDomains.some(base => name === base || name.endsWith(`.${base}`))) {
|
|
32
|
+
return `'${host}': platform alan adı altına kayıt açılamaz — platform adresi (${platformBaseDomains.join(', ')}), noktasız ad ve IP özel alan adı olamaz. Müşterinin kendi alan adını verin; platform adresi uygulamayı zaten sunar.`;
|
|
33
|
+
}
|
|
34
|
+
if (!hostPattern.test(name)) {
|
|
35
|
+
return `'${host}' geçerli bir alan adı değil: harf/rakam/tire etiketleri, en az bir nokta, 4-253 karakter, son etiket harfle başlar.`;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/** Müşterinin DNS sağlayıcısına gireceği kayıtlar; hedef her zaman backend'in verdiği `cnameTarget`'tır. */
|
|
40
|
+
export function dnsRecords(domain) {
|
|
41
|
+
const records = [];
|
|
42
|
+
if (domain.cnameTarget) {
|
|
43
|
+
records.push({ type: isApex(domain.host) ? 'ALIAS / CNAME flattening' : 'CNAME', name: domain.host, value: domain.cnameTarget });
|
|
44
|
+
}
|
|
45
|
+
if (domain.ownershipTxtName && domain.ownershipTxtValue) {
|
|
46
|
+
records.push({ type: 'TXT', name: domain.ownershipTxtName, value: domain.ownershipTxtValue });
|
|
47
|
+
}
|
|
48
|
+
return records;
|
|
49
|
+
}
|
|
50
|
+
export const dnsTable = (records) => records.map(record => `${record.type} ${record.name} ${record.value}`).join('\n');
|
|
51
|
+
export const isPending = (state) => pendingStates.has(String(state));
|
|
52
|
+
// Yanıt bütçesi (41 §5): DNS yönergesi yalnız müşterinin hâlâ kayıt girmesi gereken satırda taşınır.
|
|
53
|
+
const needsRecords = (state) => isPending(state) || state === 'error';
|
|
54
|
+
export const withDns = (row) => needsRecords(row.state) ? { ...row, dns: dnsRecords(row) } : row;
|
|
55
|
+
/** Tek kayıt dönen yazma yanıtı: satır + DNS yönergesi (düz metin tablo da, ajan kullanıcıya iletebilsin) + sonraki adım. */
|
|
56
|
+
export function domainResponse(payload, note) {
|
|
57
|
+
const envelope = payload && typeof payload === 'object' ? payload : {};
|
|
58
|
+
const row = envelope.data;
|
|
59
|
+
if (!row || typeof row !== 'object')
|
|
60
|
+
return { ...envelope, note };
|
|
61
|
+
const records = dnsRecords(row);
|
|
62
|
+
return { ...envelope, data: { ...row, dns: records }, dnsTable: dnsTable(records), note };
|
|
63
|
+
}
|
|
64
|
+
export function listResponse(payload) {
|
|
65
|
+
const envelope = payload && typeof payload === 'object' ? payload : {};
|
|
66
|
+
const rows = Array.isArray(envelope.data) ? envelope.data : [];
|
|
67
|
+
return { ...envelope, data: rows.map(withDns), note: noteFor(rows) };
|
|
68
|
+
}
|
|
69
|
+
/** Listede ajanın bir sonraki adımı; bekleyen ve bağsız satır yoksa not yok. */
|
|
70
|
+
export function noteFor(rows) {
|
|
71
|
+
const notes = [
|
|
72
|
+
rows.some(row => isPending(row.state)) ? 'doğrulama sürüyor; 60 sn sonra custom_domain_list ile yeniden çağır, state active olunca adres yayında' : '',
|
|
73
|
+
rows.some(row => row.state === 'unbound') ? 'ortam silinmiş; custom_domain_bind ile bağla' : ''
|
|
74
|
+
].filter(Boolean);
|
|
75
|
+
return notes.length > 0 ? notes.join(' · ') : undefined;
|
|
76
|
+
}
|
package/dist/platform/errors.js
CHANGED
|
@@ -111,6 +111,30 @@ function templateSubscriptionHint(code) {
|
|
|
111
111
|
return '';
|
|
112
112
|
return ' Bu proje şablon güncellemelerini alıyor; dal açma, dal silme ve merge planının hiçbir adımı bu projede yapılamaz. Değişikliği şablonun kaynak projesinde yapın, template_create ile yeni sürüm yayımlayın, bu projede template_check_updates → template_receive_updates ile alın. Aynı çağrıyı tekrarlamak sonucu değiştirmez.';
|
|
113
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Özel alan adı retlerinin her biri başka bir araca ya da başka bir id'ye gönderir; kod olmadan
|
|
116
|
+
* "400" diye okunur ve ajan aynı host'u tekrar dener. Kodlar: backend `CustomDomainExceptions.cs`,
|
|
117
|
+
* durumlar `ExceptionStatusMap.cs` (HostTaken 409, Provider 502, kalanı 400).
|
|
118
|
+
*/
|
|
119
|
+
function customDomainHint(code) {
|
|
120
|
+
if (code === 'CustomDomainHostTakenException')
|
|
121
|
+
return " Bu host başka bir kayıtta (bu ya da başka bir kuruluşta). custom_domain_list ile bakın: aynı projedeyse var olan kaydı custom_domain_bind ile istediğiniz ortama bağlayın, yeni kayıt açmayın.";
|
|
122
|
+
if (code === 'PlatformHostCantBeCustomDomainException')
|
|
123
|
+
return ' Platformun kendi alan adı ve altı, noktasız ad ve IP özel alan adı olamaz. Müşterinin kendi alan adını verin; platform adresi uygulamayı zaten sunar.';
|
|
124
|
+
if (code === 'InvalidCustomDomainHostException')
|
|
125
|
+
return " Host biçimi geçersiz: harf/rakam/tire etiketleri, en az bir nokta. Joker (*.) yalnız custom_domain_pattern_create'te; kalıp da yalnız jokerle açılır.";
|
|
126
|
+
if (code === 'CustomDomainBindingOutsideProjectException')
|
|
127
|
+
return " applicationId / environmentId / hedef bu projenin değil. application_list ve environment_list ile bu projenin id'lerini alın.";
|
|
128
|
+
if (code === 'CustomDomainRedirectTargetInvalidException')
|
|
129
|
+
return " Yönlendirme hedefi aynı projede, yayında (state active), kind primary bir kayıt olmalı. custom_domain_list'ten o satırın id'sini verin.";
|
|
130
|
+
if (code === 'InvalidCustomDomainStateException')
|
|
131
|
+
return " Kaydın durumu bu işlemi almıyor: removing kayıt bağlanmaz ve denetlenmez, unbound kayıt önce custom_domain_bind ister, kalıbın çocuğu ve yönlendirme bağlanmaz. custom_domain_list ile state ve kind'a bakın.";
|
|
132
|
+
if (code === 'InvalidCustomDomainBindingException')
|
|
133
|
+
return ' Bağlama türle uyuşmuyor: birincil uygulama + ortam ister, kalıp yalnız uygulama, yönlendirme yalnız hedef alan adı.';
|
|
134
|
+
if (code === 'CustomDomainProviderException')
|
|
135
|
+
return ' Sertifika sağlayıcısı isteği reddetti ya da ulaşılamadı; kayıt değişmedi. Bir dakika sonra custom_domain_verify ile yeniden deneyin; tekrarlarsa platform_gap_report.';
|
|
136
|
+
return '';
|
|
137
|
+
}
|
|
114
138
|
/**
|
|
115
139
|
* İçe aktarma zinciri dört çağrıdır ve her hata farklı bir adıma geri gönderir: plan süresi
|
|
116
140
|
* dolduysa analizden, anahtar benzersiz değilse plan gövdesinden, hata oranı yüksekse dosyanın
|
|
@@ -401,7 +425,7 @@ export function mapPlatformError(status, payload, context) {
|
|
|
401
425
|
if (validationMessages.length > 0) {
|
|
402
426
|
return new PlatformApiError(`Doğrulama hatası (${location}): ${validationMessages.join(' ; ')}. Gövde şeması için ilgili ngapps://schemas kaynağına ya da mevcut bir kaydın *_get çıktısına bakın.`, status, code);
|
|
403
427
|
}
|
|
404
|
-
return new PlatformApiError(`Geçersiz istek (${location}): ${apiMessage ?? 'API gövdeyi reddetti.'}${mergeRevertHint(code)}${templateSubscriptionHint(code)}${importHint(code, context.path)}${accessHint(code, apiMessage)}`, status, code);
|
|
428
|
+
return new PlatformApiError(`Geçersiz istek (${location}): ${apiMessage ?? 'API gövdeyi reddetti.'}${mergeRevertHint(code)}${templateSubscriptionHint(code)}${importHint(code, context.path)}${accessHint(code, apiMessage)}${customDomainHint(code)}`, status, code);
|
|
405
429
|
}
|
|
406
430
|
if (status === 401) {
|
|
407
431
|
// Uygulama oturumu 401'i gateway kimliğinin değil uygulama kullanıcısının sorunudur; USERNAME/PASSWORD
|
|
@@ -467,7 +491,7 @@ export function mapPlatformError(status, payload, context) {
|
|
|
467
491
|
: '';
|
|
468
492
|
const validationMessages = collectValidationMessages(body);
|
|
469
493
|
const detail = validationMessages.length > 0 ? ` → ${validationMessages.join(' ; ')}` : '';
|
|
470
|
-
const rejected = new PlatformApiError(`İş kuralı reddetti (${location}): ${apiMessage ?? 'çakışma'}${code ? ` [${code}]` : ''}${detail}${projectConflictHint}${pageSchemaHint(code, context.path)}${processHint(code, context.path)}${bulkRowHint(code)}${importHint(code, context.path)}${versionConflictHint(code, context.path)}${mergeHint(context.path)}${accessHint(code, apiMessage)}${microfunctionArchiveHint(code)}`, status, code);
|
|
494
|
+
const rejected = new PlatformApiError(`İş kuralı reddetti (${location}): ${apiMessage ?? 'çakışma'}${code ? ` [${code}]` : ''}${detail}${projectConflictHint}${pageSchemaHint(code, context.path)}${processHint(code, context.path)}${bulkRowHint(code)}${importHint(code, context.path)}${versionConflictHint(code, context.path)}${mergeHint(context.path)}${accessHint(code, apiMessage)}${microfunctionArchiveHint(code)}${customDomainHint(code)}`, status, code);
|
|
471
495
|
if (typeof body.rowIndex === 'number')
|
|
472
496
|
rejected.rowIndex = body.rowIndex;
|
|
473
497
|
return rejected;
|
|
@@ -476,7 +500,7 @@ export function mapPlatformError(status, payload, context) {
|
|
|
476
500
|
const fallbackDetail = fallbackValidationMessages.length > 0 ? ` → ${fallbackValidationMessages.join(' ; ')}` : '';
|
|
477
501
|
const errorBody = status >= 500 ? describeErrorBody(body, { code, message: apiMessage }) : [];
|
|
478
502
|
const errorBodyDetail = errorBody.length > 0 ? ` — ${errorBody.join(' · ')}` : '';
|
|
479
|
-
return new PlatformApiError(`Platform hatası ${status} (${location}): ${apiMessage ?? 'beklenmeyen hata'}${code ? ` [${code}]` : ''}${errorBodyDetail}${fallbackDetail}${diagnoseKnownFailure(status, apiMessage ?? '', code, context)}`, status, code);
|
|
503
|
+
return new PlatformApiError(`Platform hatası ${status} (${location}): ${apiMessage ?? 'beklenmeyen hata'}${code ? ` [${code}]` : ''}${errorBodyDetail}${fallbackDetail}${diagnoseKnownFailure(status, apiMessage ?? '', code, context)}${customDomainHint(code)}`, status, code);
|
|
480
504
|
}
|
|
481
505
|
const CONNECTION_RESET_CODES = new Set(['ECONNRESET', 'UND_ERR_SOCKET', 'EPIPE', 'ECONNABORTED']);
|
|
482
506
|
/**
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Özel Alan Adı Rehberi
|
|
2
|
+
|
|
3
|
+
Bir uygulamanın bir ortamını müşterinin kendi alan adında (`demo.ornek.com`) yayımlamak. Kayıt platformun
|
|
4
|
+
çekirdek tablosundadır; ortamın verisine dokunmaz. Studio'da proje › Ayarlar › **Alan adları** ekranının
|
|
5
|
+
yaptığı her şey `custom_domain_*` araçlarıyla yapılır.
|
|
6
|
+
|
|
7
|
+
## Dört kural (değişmez)
|
|
8
|
+
|
|
9
|
+
1. **Platform alan adı yasak.** Platformun kendi tabanı (kurulumda `zeyrek.app`, lokalde `zeyrek.local`) ve
|
|
10
|
+
altı, noktasız ad ve IP özel alan adı olamaz. Platform adresi uygulamayı zaten sunar; özel alan adı onun
|
|
11
|
+
**yanına** gelir, yerine geçmez.
|
|
12
|
+
2. **Apex ALIAS ister.** Kökün kendisi (`ornek.com`, `firma.com.tr`; kök public suffix listesinden bulunur) çoğu DNS
|
|
13
|
+
sağlayıcısında CNAME alamaz: ALIAS /
|
|
14
|
+
ANAME / CNAME flattening kullanılır. Sağlayıcı bunu bilmiyorsa `www.ornek.com`'u birincil açıp `ornek.com`'u
|
|
15
|
+
ona yönlendirme (`custom_domain_redirect_create`) olarak açın.
|
|
16
|
+
3. **Dal kalıbı kotadan düşer.** `*.onizleme.ornek.com` her açık dal için `<dal-slug>.onizleme.ornek.com`
|
|
17
|
+
çocuğunu kendisi açar ve dal silinince düşürür; her çocuk sağlayıcıda ayrı hostname'dir ve kurulumun
|
|
18
|
+
ücretsiz kotasından (100) düşer. 31 karakteri aşan ya da `www` / `zeyrek-check` olan dal slug'ı çocuk almaz.
|
|
19
|
+
4. **Şablon abonesi serbest, alan adı şablon içeriği değil.** Şablondan kurulup güncelleme alan proje kendi
|
|
20
|
+
alan adını ekler, bağlar, kaldırır; şablon güncellemesi alan adını taşımaz ve bozmaz. Şablonun kaynak
|
|
21
|
+
projesindeki alan adı abonelere kopyalanmaz.
|
|
22
|
+
|
|
23
|
+
## Sıra
|
|
24
|
+
|
|
25
|
+
1. `application_list` + `environment_list` → uygulamanın ve ortamın id'si (production kabul edilir).
|
|
26
|
+
2. `custom_domain_create { projectId, host, applicationId, environmentId }` → kayıt `pending_dns`; yanıt
|
|
27
|
+
`dns` satırlarını ve `dnsTable` düz metnini taşır. Bu kayıtları **müşteri** kendi DNS sağlayıcısına girer;
|
|
28
|
+
ajan DNS'e yazamaz.
|
|
29
|
+
3. `custom_domain_list` ile 60 sn arayla okuyun: `pending_dns → verifying → active`. `active` olunca adres
|
|
30
|
+
yayındadır. Beklemeyi kısaltmak için `custom_domain_verify`.
|
|
31
|
+
4. Başka ortama taşımak: `custom_domain_bind { id, applicationId, environmentId }` — host ve DNS değişmez.
|
|
32
|
+
5. Kaldırmak: `custom_domain_delete` → `removing` → listeden çıkar. Müşterinin DNS kaydı kalır.
|
|
33
|
+
|
|
34
|
+
## Durumlar
|
|
35
|
+
|
|
36
|
+
| state | Anlamı | Sonraki adım |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `pending_dns` | DNS kaydı henüz platformu göstermiyor | Müşteri `dnsTable`'ı girer; bekle |
|
|
39
|
+
| `verifying` | DNS doğru, sertifika alınıyor | Bekle |
|
|
40
|
+
| `active` | Yayında | — |
|
|
41
|
+
| `error` | 72 saatte DNS gelmedi ya da sağlayıcı reddetti; `error` alanı sebebi söyler | Sebebi gider, `custom_domain_verify` (baştan başlar) |
|
|
42
|
+
| `unbound` | Bağlı ortam silindi ya da uygulama kaldırıldı; host ve DNS korunur | `custom_domain_bind` |
|
|
43
|
+
| `removing` | Sağlayıcıdan düşürülüyor | Bekle; bu kayıtta başka işlem yok |
|
|
44
|
+
|
|
45
|
+
## Yönlendirme ve kalıp
|
|
46
|
+
|
|
47
|
+
- `custom_domain_redirect_create { host, targetDomainId }`: 301, yol ve sorgu korunur. Hedef aynı projede
|
|
48
|
+
`active` bir **birincil** kayıttır; hedef silinince yönlendirme de silinir.
|
|
49
|
+
- `custom_domain_pattern_create { host: '*.…', applicationId }`: dallar içindir; ortam seçilmez. Çocuklar
|
|
50
|
+
`custom_domain_list`'te `parentDomainId` ile görünür ve elle bağlanmaz.
|
|
51
|
+
|
|
52
|
+
## Tuzaklar
|
|
53
|
+
|
|
54
|
+
- Özel alan adı kapalı kurulumda (`CustomDomains:Enabled=false`) uçlar 404 döner; araç değil kurulum ayarıdır.
|
|
55
|
+
- Bağlama ya da kaldırma adresin sunduğu ortamı en geç 30 sn içinde değiştirir (çözüm önbelleği).
|
|
56
|
+
- Aynı host ikinci kez açılamaz (409); aynı projedeyse var olan kaydı `custom_domain_bind` ile taşıyın.
|
|
@@ -57,11 +57,17 @@ Satırlar **tablo başına** açılan kayıt taşıma ayarıyla gider. Ayar enti
|
|
|
57
57
|
satırları ana tabloyla **otomatik** gider; onlara ayrıca ayar açılmaz. Junction satırı yalnız iki
|
|
58
58
|
tarafı da taşınıyorsa gider (dosya tarafı her zaman geçer).
|
|
59
59
|
- **Kimlikler 1:1 korunur:** satır production'a aynı birincil anahtarla yazılır, identity sayacı
|
|
60
|
-
taşınan id'lerin ötesine ilerletilir. Production'da aynı id'li satır varsa üzerine yazılır.
|
|
60
|
+
taşınan id'lerin ötesine ilerletilir. Production'da aynı id'li satır varsa üzerine yazılır (ayar kapalıyken).
|
|
61
61
|
- **`'all'` = ayna (DEP-005, backend ADR 0011):** promote'ta production o tabloda development'ın
|
|
62
62
|
aynasıdır. Kaynakta olmayan satır, çevirisi ve junction satırı production'da **silinir** —
|
|
63
63
|
production'a doğrudan girilmiş satırlar dahil. Kaynak tablo boşsa hedef tablo boşalır. Platformun
|
|
64
64
|
kendi tabloları (`users`, `roles`, `permissions`) taşımaya açılabilir ama aynalanmaz.
|
|
65
|
+
- **Hedefte varsa elleme (`recordTransferSkipExisting: true`, backend ADR 0072):** hedefte aynı birincil anahtarlı
|
|
66
|
+
ya da başka bir unique anahtarı çakışan satır **güncellenmez**, yalnız eksik satır eklenir; tablo **aynalanmaz**
|
|
67
|
+
(hedefin kendi eklediği satır silinmez). Şablon güncellemesinde de geçerlidir; dal açılışı ve merge yok sayar.
|
|
68
|
+
`roles`'ta açılamaz (ENT-019). Identity anahtarlı tabloya iki taraf da satır eklerse kimlikler çakışır ve kaynağın
|
|
69
|
+
satırı gelmez — iki tarafın satır eklediği tabloda `uuid` anahtar kullanın. Studio: tablo paneli → **"Hedefte zaten olan
|
|
70
|
+
kayıtları güncelleme"**.
|
|
65
71
|
- **`'specific'` silmez:** yalnız upsert yapar. Seçili satırın FK ile gösterdiği satırlar zincirleme
|
|
66
72
|
gelir (bir satır seçmek birkaçını taşıyabilir); seçilmemiş bir satıra giden çoka-çok bağı düşer.
|
|
67
73
|
- **İlişki sırası:** `'all'` açılan tablonun ilişki hedefinde de taşıma açık olmalıdır, yoksa kayıt
|
|
@@ -122,4 +128,5 @@ yeni bir deploy.
|
|
|
122
128
|
| Çeviriler eksik, satırlar var | ana tablonun ayarı | çeviri tablosu ana tabloyla gider; ana tabloda ayar açık olmalı |
|
|
123
129
|
| Görsel production'da 404 | `page_schema_get` → prop düz URL mi, `{ type:'file', ref }` mi | prop'u `ref` ile bağlayın ya da dosyayı taşınan satırın dosya sütunundan okuyun |
|
|
124
130
|
| Satırın dosyası 404, satır var | satır taşınıyor mu (`recordTransferMode`) | dosya yalnız taşınan satırla gider |
|
|
125
|
-
| Production'da silinmiş satırlar | tablo `'all'` mı | ayna kuralı (DEP-005); production'a girilen veri bu tabloda tutulmaz |
|
|
131
|
+
| Production'da silinmiş satırlar | tablo `'all'` mı | ayna kuralı (DEP-005); production'a girilen veri bu tabloda tutulmaz — tutulsun isteniyorsa `recordTransferSkipExisting: true` |
|
|
132
|
+
| Production / abone değeri deploy ya da şablon güncellemesiyle ezildi | `entity_get` → `recordTransferSkipExisting` | `true` yapın: var olan satır güncellenmez |
|
|
@@ -31,7 +31,7 @@ tetikleyen satır `row` / `previousRow` / `user`.
|
|
|
31
31
|
|
|
32
32
|
| Çağrı | Ne yapar | Gerçek örnek (qm) |
|
|
33
33
|
|---|---|---|
|
|
34
|
-
| `system.getPageUrl(path)` | Sayfanın environment'a göre doğru serve URL'ini üretir — e-posta/redirect linki için TEK doğru yol, sabit URL yazma | `system.getPageUrl(`/web/dif-kayit?id=${row.finding_record}`)` |
|
|
34
|
+
| `system.getPageUrl(path)` | Sayfanın environment'a göre doğru serve URL'ini üretir — e-posta/redirect linki için TEK doğru yol, sabit URL yazma. İstek uygulamanın özel alan adından geldiyse adres o alan adında döner (`https://demo.firma.com/dif-kayit?id=…`); istek yokken (zamanlanmış iş, kuyruk) sayfayı gösteren aktif alan adı varsa yine o, yoksa platform adresi | `system.getPageUrl(`/web/dif-kayit?id=${row.finding_record}`)` |
|
|
35
35
|
| `system.generateToken({claims})` | Org secret'ıyla JWT üretir — sign-in ucunun kalbi | `{ access_token: system.generateToken({ userId: user.data.id, email: user.data.email }) }` |
|
|
36
36
|
| `system.validateToken(token)` | Org secret'ıyla doğrular; dönüş `{ isValid, claims }` — **claim'ler bir seviye içeride** ve anahtarları `generateToken`'a verdiğin sözlüğün anahtarları (`r.claims.userId`); `r.id` YOK | `const r = system.validateToken(cookie.APP_Token)` → condition: `token.data.isValid && token.data.claims.userId` |
|
|
37
37
|
| `file.readAsBase64(fileId)` | Drive dosyasını `data:<mime>;base64,…` döner | şablon okuma |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
3
|
-
"generatedAt": "2026-11-
|
|
2
|
+
"hash": "0598b6dcd46ea1951cf067de1e0f3f38b12eaaddc2669205451097bb2a089f90",
|
|
3
|
+
"generatedAt": "2026-11-02T13:49:36.654Z",
|
|
4
4
|
"types": 377,
|
|
5
5
|
"files": 196,
|
|
6
6
|
"note": "Şemaları üreten backend kaynaklarının parmak izi. Elle düzenlemeyin: 'npm run generate-schemas' yazar, 'npm run schema:check' denetler.",
|
package/dist/server.js
CHANGED
|
@@ -36,6 +36,7 @@ import { registerFileTools } from "./tools/files.js";
|
|
|
36
36
|
import { registerRowTools } from "./tools/rows.js";
|
|
37
37
|
import { registerImportTools } from "./tools/imports.js";
|
|
38
38
|
import { registerEnvironmentTools } from "./tools/environments.js";
|
|
39
|
+
import { registerCustomDomainTools } from "./tools/customDomains.js";
|
|
39
40
|
import { registerMergeTools } from "./tools/merges.js";
|
|
40
41
|
import { registerRevisionTools } from "./tools/revisions.js";
|
|
41
42
|
import { registerActivityTools } from "./tools/activities.js";
|
|
@@ -95,6 +96,7 @@ const moduleRegistrations = {
|
|
|
95
96
|
dependency: registerDependencyTools,
|
|
96
97
|
deployment: registerDeploymentTools,
|
|
97
98
|
environment: registerEnvironmentTools,
|
|
99
|
+
customDomain: registerCustomDomainTools,
|
|
98
100
|
merge: registerMergeTools,
|
|
99
101
|
activity: registerActivityTools,
|
|
100
102
|
revision: registerRevisionTools,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { destructive, guid, readOnly, updates, writes } from './common.js';
|
|
2
|
+
import { domainResponse, hostProblem, listResponse, normalizeHost } from '../knowledge/customDomain.js';
|
|
3
|
+
import { PlatformApiError } from '../platform/errors.js';
|
|
4
|
+
import { handle } from '../platform/responses.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
const host = z.string().min(1).max(253)
|
|
7
|
+
.describe("Müşterinin alan adı (ör. demo.ornek.com). Gateway kırpar, küçültür, IDN'yi punycode'a çevirir; platformun kendi alan adı ve altı reddedilir.");
|
|
8
|
+
const pendingNote = 'DNS kayıtları (dnsTable) müşterinin DNS sağlayıcısına girilir; doğrulama asenkron — custom_domain_list ile 60 sn arayla okuyun, state active olunca adres yayında.';
|
|
9
|
+
// Platform tabanı kuruluşa göre değişir; yalnız backend bilir (`CustomDomains:BaseDomains`), uç `mounts` onu yayımlar.
|
|
10
|
+
async function assertHost(platform, tool, value, kind) {
|
|
11
|
+
const mounts = await platform.org('GET', '/custom-domains/mounts');
|
|
12
|
+
const problem = hostProblem(value, kind, mounts?.platformBaseDomains ?? []);
|
|
13
|
+
if (problem)
|
|
14
|
+
throw new PlatformApiError(`${tool}: ${problem}`, 400);
|
|
15
|
+
return normalizeHost(value);
|
|
16
|
+
}
|
|
17
|
+
export function registerCustomDomainTools(server, platform) {
|
|
18
|
+
const config = platform.config;
|
|
19
|
+
server.registerTool('custom_domain_list', {
|
|
20
|
+
title: 'Özel alan adları',
|
|
21
|
+
description: "Projenin özel alan adlarını döner (birincil · yönlendirme · dal kalıbı ve kalıbın çocukları, parentDomainId ile). Her satırda state: pending_dns | verifying | active | error | unbound | removing; yalnız active yayındadır. DNS'i bekleyen ya da hatalı satır dns yönergesini taşır. Bekleyen satır varsa note '60 sn sonra yeniden çağır' der; unbound satır ortamı silinmiş ya da uygulaması kaldırılmış kayıttır, custom_domain_bind ile bağlanır. Özel alan adı kapalı kurulumda uç 404 döner.",
|
|
22
|
+
inputSchema: { projectId: guid },
|
|
23
|
+
annotations: readOnly
|
|
24
|
+
}, handle(config, async ({ projectId }) => listResponse(await platform.org('GET', `/custom-domains/${projectId}`))));
|
|
25
|
+
server.registerTool('custom_domain_create', {
|
|
26
|
+
title: 'Özel alan adı ekle',
|
|
27
|
+
description: "Bir uygulamanın bir ortamını müşterinin alan adında yayımlar (definition = CreateCustomDomainCommand: { host, applicationId, environmentId }). Kayıt pending_dns doğar; yanıt müşterinin gireceği DNS kayıtlarını dns satırlarında ve dnsTable düz metninde verir. production ortamı kabul edilir: kayıt CORE tablosuna yazılır, ortamın verisine dokunmaz. Joker (*.) host bu araçta reddedilir — dal kalıbı custom_domain_pattern_create'tir; tek adresi başka adrese yönlendirmek custom_domain_redirect_create'tir. Şablon abonesi proje de alan adını kendisi yönetir (alan adı şablon içeriği değildir).",
|
|
28
|
+
inputSchema: { projectId: guid, host, applicationId: guid, environmentId: guid },
|
|
29
|
+
annotations: writes
|
|
30
|
+
}, handle(config, async ({ projectId, host: value, applicationId, environmentId }) => {
|
|
31
|
+
const normalized = await assertHost(platform, 'custom_domain_create', value, 'primary');
|
|
32
|
+
return domainResponse(await platform.org('POST', `/custom-domains/${projectId}`, { body: { host: normalized, applicationId, environmentId } }), pendingNote);
|
|
33
|
+
}));
|
|
34
|
+
server.registerTool('custom_domain_pattern_create', {
|
|
35
|
+
title: 'Dal kalıbı ekle',
|
|
36
|
+
description: "Bir uygulamanın dallarını tek kalıpla yayımlar: '*.onizleme.ornek.com' her açık dal için '<dal-slug>.onizleme.ornek.com' çocuğunu kendiliğinden açar, dal silinince düşürür (definition = CreateCustomDomainPatternCommand: { host, applicationId }). Müşteri tek joker CNAME girer. Her çocuk sağlayıcıda ayrı hostname'dir ve kotadan düşer; 31 karakteri aşan ya da 'www'/'zeyrek-check' olan dal slug'ı çocuk almaz. Kalıp joker olmayan host'u reddeder.",
|
|
37
|
+
inputSchema: { projectId: guid, host: host.describe("Joker host: '*.' ile başlar (ör. *.onizleme.ornek.com)."), applicationId: guid },
|
|
38
|
+
annotations: writes
|
|
39
|
+
}, handle(config, async ({ projectId, host: value, applicationId }) => {
|
|
40
|
+
const normalized = await assertHost(platform, 'custom_domain_pattern_create', value, 'pattern');
|
|
41
|
+
return domainResponse(await platform.org('POST', `/custom-domains/${projectId}/pattern`, { body: { host: normalized, applicationId } }), pendingNote);
|
|
42
|
+
}));
|
|
43
|
+
server.registerTool('custom_domain_redirect_create', {
|
|
44
|
+
title: 'Yönlendirme ekle',
|
|
45
|
+
description: "Bir alan adını aynı projedeki yayında (active) birincil alan adına 301 ile yönlendirir (ör. www.ornek.com → ornek.com; definition = CreateCustomDomainRedirectCommand: { host, targetDomainId }). Yol ve sorgu korunur. Hedef silinince yönlendirme de silinir. Hedef id'si custom_domain_list'te kind: 'primary', state: 'active' satırıdır.",
|
|
46
|
+
inputSchema: { projectId: guid, host, targetDomainId: guid.describe('Yönlendirmenin hedefi: aynı projede active, kind primary bir kaydın id\'si') },
|
|
47
|
+
annotations: writes
|
|
48
|
+
}, handle(config, async ({ projectId, host: value, targetDomainId }) => {
|
|
49
|
+
const normalized = await assertHost(platform, 'custom_domain_redirect_create', value, 'redirect');
|
|
50
|
+
return domainResponse(await platform.org('POST', `/custom-domains/${projectId}/redirect`, { body: { host: normalized, targetDomainId } }), pendingNote);
|
|
51
|
+
}));
|
|
52
|
+
server.registerTool('custom_domain_verify', {
|
|
53
|
+
title: 'Alan adını şimdi denetle',
|
|
54
|
+
description: "DNS'i ve sertifikayı sıradaki tur beklenmeden şimdi denetler; error durumundaki kayıt baştan başlar. Arka plan zaten dakikada bir denetler, bu yalnız beklemeyi kısaltır. unbound ve removing kayıt denetlenmez (400).",
|
|
55
|
+
inputSchema: { id: guid.describe('Alan adı kaydının id\'si (custom_domain_list)') },
|
|
56
|
+
annotations: updates
|
|
57
|
+
}, handle(config, async ({ id }) => domainResponse(await platform.org('POST', `/custom-domains/${id}/verify`), pendingNote)));
|
|
58
|
+
server.registerTool('custom_domain_bind', {
|
|
59
|
+
title: 'Alan adını başka ortama bağla',
|
|
60
|
+
description: "Birincil alan adını aynı projede başka bir uygulama ortamına bağlar (definition = BindCustomDomainCommand: { applicationId, environmentId }); unbound kayıt böyle yeniden yayına girer. Host değişmez, DNS'e dokunulmaz. Yalnız kind primary; kalıbın çocukları ve yönlendirmeler bağlanmaz.",
|
|
61
|
+
inputSchema: { id: guid.describe('Alan adı kaydının id\'si (custom_domain_list)'), applicationId: guid, environmentId: guid },
|
|
62
|
+
annotations: updates
|
|
63
|
+
}, handle(config, async ({ id, applicationId, environmentId }) => domainResponse(await platform.org('PUT', `/custom-domains/${id}/environment`, { body: { applicationId, environmentId } }), 'Bağlama kalıcıdır; adres en geç 30 sn içinde yeni ortamı sunar.')));
|
|
64
|
+
server.registerTool('custom_domain_delete', {
|
|
65
|
+
title: 'Alan adını kaldır',
|
|
66
|
+
description: "Alan adını kaldırır: kayıt removing olur, sağlayıcıdaki hostname arka planda düşürülür ve kayıt listeden çıkar. Kalıp silinirse çocukları, birincil silinirse ona yönlendiren kayıtlar da silinir. Müşterinin DNS kayıtlarına dokunulmaz.",
|
|
67
|
+
inputSchema: { id: guid.describe('Alan adı kaydının id\'si (custom_domain_list)') },
|
|
68
|
+
annotations: destructive
|
|
69
|
+
}, handle(config, async ({ id }) => ({
|
|
70
|
+
...await platform.org('DELETE', `/custom-domains/${id}`),
|
|
71
|
+
note: 'kayıt removing; custom_domain_list ile listeden çıkmasını bekleyin'
|
|
72
|
+
})));
|
|
73
|
+
}
|
|
@@ -27,7 +27,7 @@ export function registerDeploymentTools(server, platform) {
|
|
|
27
27
|
const config = platform.config;
|
|
28
28
|
server.registerTool('deployment_start', {
|
|
29
29
|
title: 'Deployment başlat',
|
|
30
|
-
description: 'Projeyi kaynak environment\'tan hedef environment\'a deploy eder. Asenkron bir saga\'dır: sonuç bu yanıtta bitmez, deployment_status ile izleyin. Environment id\'lerini project_get çıktısından alın. BPM: süreç tanımları ve iş takvimleri taşınır — hedefte farklı aktif model yeni sürüm olarak yayınlanır (production\'da gelişte aktif), hedefin uyarlaması korunur; uyarlama, örnek, görev ve defter taşınmaz; kaynakta olmayan tanım silinir, açık örneği varsa emekliye ayrılır. KAYNAK YALNIZ DEVELOPMENT\'TIR: dal ya da production kaynak verilirse 400 (CantDeployFromBranchException) — dalı önce development\'a merge edin. ÖN DENETİM: deploy başlamadan production verisi denetlenir; veriyi bozacak ya da silecek her değişiklik 400 (DeploymentDataRiskException) ile listelenir ve deploy BAŞLAMAZ — biçim \'tablo.alan: tür (satır)\', türler not-null | unique | field-removed | table-removed | localization-move. YALNIZ TANIM TAŞINIR: tablo satırları ancak tabloda recordTransferMode (\'all\' | \'specific\' + transferRowIds) açıksa gider, çeviri ve junction satırları ana tabloyla birlikte. Kayıt taşıması \'all\' olan tabloda production development\'ın AYNASIDIR (kaynakta olmayan satır ve çevirisi silinir). DOSYA yalnız id referansıyla gider (file tipli prop { type:\'file\', ref:<fileId> } ya da taşınan satırın dosya sütunu); sayfaya düz yazılan /d/ serve URL\'si /p/\'ye çevrilir ama dosya kopyalanmaz, production\'da 404 döner — platform_guide(\'deployment\'). Microfunction\'ın yalnız YAYINLANMIŞ kodu taşınır ve hedefte yayınlanır; hiç yayınlanmamış olan hedefte taslak kalır. Zamanlanmış işin duraklatma durumu taşınır. YAYINLANMAMIŞ TASLAK TAŞINMAZ: kaynakta taslağı olan süreçler yanıtta unpublishedDrafts ({ slug, name, draftVersionNumber, activeVersionNumber }) ve note ile listelenir; hedefte aktif sürüm kalır. Taşımak için taslağı kaynakta yayınlayın (requireGreenScenarios açıksa önce senaryoları taslak üzerinde koşun), sonra yeniden deploy edin. DELTA (varsayılan): yalnız içerik özeti production\'dakinden farklı tanımlar taşınır, kaynakta olmayan tanım silinir; entity, rol, erişim politikası, bileşen, dosya, süreç tanımı, organizasyon yapısı ve tablo satırları her deploy\'da tam taşınır; klasör silme taşınmaz. Kaynağın ya da production\'ın özeti güvenilir değilse (son tamamlanmış özet denetimi güncel biçimde bir fill ya da farksız bir check değilse) deploy kendiliğinden tam koşar; fullMode:true her tanımı taşır. Hangi kipte koştuğu ve modül başına sayılar deployment_status yanıtında (mode, counters).',
|
|
30
|
+
description: 'Projeyi kaynak environment\'tan hedef environment\'a deploy eder. Asenkron bir saga\'dır: sonuç bu yanıtta bitmez, deployment_status ile izleyin. Environment id\'lerini project_get çıktısından alın. BPM: süreç tanımları ve iş takvimleri taşınır — hedefte farklı aktif model yeni sürüm olarak yayınlanır (production\'da gelişte aktif), hedefin uyarlaması korunur; uyarlama, örnek, görev ve defter taşınmaz; kaynakta olmayan tanım silinir, açık örneği varsa emekliye ayrılır. KAYNAK YALNIZ DEVELOPMENT\'TIR: dal ya da production kaynak verilirse 400 (CantDeployFromBranchException) — dalı önce development\'a merge edin. ÖN DENETİM: deploy başlamadan production verisi denetlenir; veriyi bozacak ya da silecek her değişiklik 400 (DeploymentDataRiskException) ile listelenir ve deploy BAŞLAMAZ — biçim \'tablo.alan: tür (satır)\', türler not-null | unique | field-removed | table-removed | localization-move. YALNIZ TANIM TAŞINIR: tablo satırları ancak tabloda recordTransferMode (\'all\' | \'specific\' + transferRowIds) açıksa gider, çeviri ve junction satırları ana tabloyla birlikte. Kayıt taşıması \'all\' olan tabloda production development\'ın AYNASIDIR (kaynakta olmayan satır ve çevirisi silinir) — tabloda recordTransferSkipExisting açıksa ayna yoktur, production\'da var olan satır güncellenmez, yalnız eksik satır eklenir. DOSYA yalnız id referansıyla gider (file tipli prop { type:\'file\', ref:<fileId> } ya da taşınan satırın dosya sütunu); sayfaya düz yazılan /d/ serve URL\'si /p/\'ye çevrilir ama dosya kopyalanmaz, production\'da 404 döner — platform_guide(\'deployment\'). Microfunction\'ın yalnız YAYINLANMIŞ kodu taşınır ve hedefte yayınlanır; hiç yayınlanmamış olan hedefte taslak kalır. Zamanlanmış işin duraklatma durumu taşınır. YAYINLANMAMIŞ TASLAK TAŞINMAZ: kaynakta taslağı olan süreçler yanıtta unpublishedDrafts ({ slug, name, draftVersionNumber, activeVersionNumber }) ve note ile listelenir; hedefte aktif sürüm kalır. Taşımak için taslağı kaynakta yayınlayın (requireGreenScenarios açıksa önce senaryoları taslak üzerinde koşun), sonra yeniden deploy edin. DELTA (varsayılan): yalnız içerik özeti production\'dakinden farklı tanımlar taşınır, kaynakta olmayan tanım silinir; entity, rol, erişim politikası, bileşen, dosya, süreç tanımı, organizasyon yapısı ve tablo satırları her deploy\'da tam taşınır; klasör silme taşınmaz. Kaynağın ya da production\'ın özeti güvenilir değilse (son tamamlanmış özet denetimi güncel biçimde bir fill ya da farksız bir check değilse) deploy kendiliğinden tam koşar; fullMode:true her tanımı taşır. Hangi kipte koştuğu ve modül başına sayılar deployment_status yanıtında (mode, counters).',
|
|
31
31
|
inputSchema: {
|
|
32
32
|
projectId: guid,
|
|
33
33
|
sourceEnvironmentId: guid,
|
|
@@ -81,6 +81,7 @@ const guideRouting = {
|
|
|
81
81
|
translation: 'sayfa/içerik çevirileri (çoklu dil)',
|
|
82
82
|
access: 'kompleks proje yetkisi: organizasyon ağacı, izin kataloğu, kapsam, grant/atama, alan koruması (maske · şifre · türetilmiş alan)',
|
|
83
83
|
merge: "dal aç, dalda çalış, development'a merge et; çakışma çözümü ve apply kapıları",
|
|
84
|
+
'custom-domain': 'uygulamayı müşterinin alan adında yayımlama: DNS yönergesi, durumlar, yönlendirme, dal kalıbı, dört kural',
|
|
84
85
|
deployment: "development → production deploy'u neyi taşır: yalnız tanım; tablo satırları recordTransferMode ile, dosyalar yalnız id referansıyla; production'da eksik satır/dosya teşhisi",
|
|
85
86
|
bpm: 'süreç motoru: tanım modeli, düğümler, atama sözlüğü, bölge olayları, kutu ve görev eylemleri, bağlayıcı/belge/imza/kanallar (süreç ≠ workflow)',
|
|
86
87
|
decision: 'DMN karar tabloları: model, isabet politikaları, FEEL alt kümesi, DRD, süreçte decision düğümü, DMN XML'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appaflytech/zeyrek-ai-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.57",
|
|
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",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"fast-json-patch": "^3.1.1",
|
|
51
51
|
"pino": "^9.5.0",
|
|
52
52
|
"playwright-core": "^1.49.0",
|
|
53
|
+
"tldts-icann": "^7.4.18",
|
|
53
54
|
"undici": "^7.3.0",
|
|
54
55
|
"zod": "^3.24.1"
|
|
55
56
|
},
|