@devoplus/one-sdk 0.0.0-stage → 0.2.0-next.117
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/CHANGELOG.md +268 -0
- package/README.md +893 -2
- package/bin/accessRequest.d.mts +96 -0
- package/bin/accessRequest.mjs +340 -0
- package/bin/appOps.d.mts +97 -0
- package/bin/appOps.mjs +336 -0
- package/bin/dataCommand.mjs +131 -0
- package/bin/devConfig.mjs +132 -0
- package/bin/one.mjs +341 -0
- package/bin/session.mjs +239 -0
- package/dist/agentInput.d.ts +9 -0
- package/dist/agentInput.d.ts.map +1 -0
- package/dist/agentInput.js +102 -0
- package/dist/agentInput.js.map +1 -0
- package/dist/agentTools.d.ts +83 -0
- package/dist/agentTools.d.ts.map +1 -0
- package/dist/agentTools.js +164 -0
- package/dist/agentTools.js.map +1 -0
- package/dist/ai.d.ts +67 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +129 -0
- package/dist/ai.js.map +1 -0
- package/dist/audit.d.ts +21 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +58 -0
- package/dist/audit.js.map +1 -0
- package/dist/backend.d.ts +27 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +63 -0
- package/dist/backend.js.map +1 -0
- package/dist/cache.d.ts +20 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +84 -0
- package/dist/cache.js.map +1 -0
- package/dist/client.d.ts +147 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +469 -0
- package/dist/client.js.map +1 -0
- package/dist/components.d.ts +235 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +1491 -0
- package/dist/components.js.map +1 -0
- package/dist/context.d.ts +110 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +126 -0
- package/dist/context.js.map +1 -0
- package/dist/data/crud.d.ts +74 -0
- package/dist/data/crud.d.ts.map +1 -0
- package/dist/data/crud.js +614 -0
- package/dist/data/crud.js.map +1 -0
- package/dist/data/ddl.d.ts +76 -0
- package/dist/data/ddl.d.ts.map +1 -0
- package/dist/data/ddl.js +362 -0
- package/dist/data/ddl.js.map +1 -0
- package/dist/data/fold.d.ts +14 -0
- package/dist/data/fold.d.ts.map +1 -0
- package/dist/data/fold.js +76 -0
- package/dist/data/fold.js.map +1 -0
- package/dist/data/model.d.ts +113 -0
- package/dist/data/model.d.ts.map +1 -0
- package/dist/data/model.js +408 -0
- package/dist/data/model.js.map +1 -0
- package/dist/data/values.d.ts +29 -0
- package/dist/data/values.d.ts.map +1 -0
- package/dist/data/values.js +152 -0
- package/dist/data/values.js.map +1 -0
- package/dist/dexa.d.ts +44 -0
- package/dist/dexa.d.ts.map +1 -0
- package/dist/dexa.js +74 -0
- package/dist/dexa.js.map +1 -0
- package/dist/dexaCommand.d.ts +116 -0
- package/dist/dexaCommand.d.ts.map +1 -0
- package/dist/dexaCommand.js +226 -0
- package/dist/dexaCommand.js.map +1 -0
- package/dist/export/columns.d.ts +62 -0
- package/dist/export/columns.d.ts.map +1 -0
- package/dist/export/columns.js +127 -0
- package/dist/export/columns.js.map +1 -0
- package/dist/export/csv.d.ts +10 -0
- package/dist/export/csv.d.ts.map +1 -0
- package/dist/export/csv.js +30 -0
- package/dist/export/csv.js.map +1 -0
- package/dist/export/report.d.ts +19 -0
- package/dist/export/report.d.ts.map +1 -0
- package/dist/export/report.js +91 -0
- package/dist/export/report.js.map +1 -0
- package/dist/export/response.d.ts +14 -0
- package/dist/export/response.d.ts.map +1 -0
- package/dist/export/response.js +70 -0
- package/dist/export/response.js.map +1 -0
- package/dist/export/xlsx.d.ts +15 -0
- package/dist/export/xlsx.d.ts.map +1 -0
- package/dist/export/xlsx.js +167 -0
- package/dist/export/xlsx.js.map +1 -0
- package/dist/export/zip.d.ts +7 -0
- package/dist/export/zip.d.ts.map +1 -0
- package/dist/export/zip.js +83 -0
- package/dist/export/zip.js.map +1 -0
- package/dist/files.d.ts +52 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +137 -0
- package/dist/files.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs.d.ts +57 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +157 -0
- package/dist/jobs.js.map +1 -0
- package/dist/log.d.ts +22 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +107 -0
- package/dist/log.js.map +1 -0
- package/dist/notify.d.ts +41 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +11 -0
- package/dist/notify.js.map +1 -0
- package/dist/org.d.ts +184 -0
- package/dist/org.d.ts.map +1 -0
- package/dist/org.js +114 -0
- package/dist/org.js.map +1 -0
- package/dist/people.d.ts +39 -0
- package/dist/people.d.ts.map +1 -0
- package/dist/people.js +88 -0
- package/dist/people.js.map +1 -0
- package/dist/problem.d.ts +12 -0
- package/dist/problem.d.ts.map +1 -0
- package/dist/problem.js +33 -0
- package/dist/problem.js.map +1 -0
- package/dist/runtime.d.ts +92 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +8 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scenarios.d.ts +125 -0
- package/dist/scenarios.d.ts.map +1 -0
- package/dist/scenarios.js +251 -0
- package/dist/scenarios.js.map +1 -0
- package/package.json +55 -3
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// accessRequest.mjs tipleri — Devoplus One MCP sunucusu ve TypeScript tüketicileri için. Davranış .mjs'tedir.
|
|
2
|
+
|
|
3
|
+
export declare class AccessRequestError extends Error {
|
|
4
|
+
readonly status: number | undefined
|
|
5
|
+
readonly code: string | undefined
|
|
6
|
+
constructor(message: string, details?: { status?: number; code?: string })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type AccessRequestKindName =
|
|
10
|
+
| 'registration'
|
|
11
|
+
| 'installation'
|
|
12
|
+
| 'dexa-query'
|
|
13
|
+
| 'dexa-command'
|
|
14
|
+
| 'app-permission'
|
|
15
|
+
| 'scope'
|
|
16
|
+
| 'new-query'
|
|
17
|
+
|
|
18
|
+
export interface AccessRequestKind {
|
|
19
|
+
wire: string
|
|
20
|
+
label: string
|
|
21
|
+
required: readonly string[]
|
|
22
|
+
optional: readonly string[]
|
|
23
|
+
audience: 'platform' | 'company'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export declare const KINDS: Readonly<Record<AccessRequestKindName, AccessRequestKind>>
|
|
27
|
+
export declare const LIMITS: Readonly<{
|
|
28
|
+
justification: number
|
|
29
|
+
description: number
|
|
30
|
+
draftSql: number
|
|
31
|
+
title: number
|
|
32
|
+
permissionName: number
|
|
33
|
+
additionalPermissions: number
|
|
34
|
+
}>
|
|
35
|
+
|
|
36
|
+
/** Kayıt talebinin ek izni: `One.<Uygulama>.<Eylem>` kodu + Türkçe ad (zorunlu) + İngilizce ad. */
|
|
37
|
+
export interface AdditionalPermissionInput {
|
|
38
|
+
code: string
|
|
39
|
+
nameTr: string
|
|
40
|
+
nameEn?: string | undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AccessRequestFields {
|
|
44
|
+
appSlug?: string | undefined
|
|
45
|
+
justification?: string | undefined
|
|
46
|
+
titleTr?: string | undefined
|
|
47
|
+
titleEn?: string | undefined
|
|
48
|
+
portalKey?: string | undefined
|
|
49
|
+
queryKey?: string | undefined
|
|
50
|
+
permissionCode?: string | undefined
|
|
51
|
+
permissionNameTr?: string | undefined
|
|
52
|
+
permissionNameEn?: string | undefined
|
|
53
|
+
userGroupId?: string | undefined
|
|
54
|
+
scope?: string | undefined
|
|
55
|
+
description?: string | undefined
|
|
56
|
+
draftSql?: string | undefined
|
|
57
|
+
/** registration: uygulama içi izinler (en çok 16). */
|
|
58
|
+
additionalPermissions?: readonly AdditionalPermissionInput[] | undefined
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type AccessRequestBody = { kind: string; appSlug: string } & Record<string, string | AdditionalPermissionInput[]>
|
|
62
|
+
|
|
63
|
+
/** `GET api/v1/One/access-requests/context` — oturum portalı. */
|
|
64
|
+
export interface PortalContext {
|
|
65
|
+
portalId: string
|
|
66
|
+
portalName: string
|
|
67
|
+
/** Portaldaki var olan bir kurulumun anahtarı; yoksa `null`. */
|
|
68
|
+
portalKey: string | null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Sunucunun talep satırı (backend `OneAccessRequestResponse`). */
|
|
72
|
+
export interface AccessRequestRow {
|
|
73
|
+
id: string
|
|
74
|
+
kind: string
|
|
75
|
+
audience: string
|
|
76
|
+
status: string
|
|
77
|
+
appSlug: string
|
|
78
|
+
[field: string]: unknown
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface AccessRequestClientOptions {
|
|
82
|
+
apiBase: string
|
|
83
|
+
accessToken: string
|
|
84
|
+
fetch?: typeof fetch
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export declare function resolveKind(value: unknown): AccessRequestKindName | undefined
|
|
88
|
+
export declare function buildAccessRequest(kind: string, fields?: AccessRequestFields): AccessRequestBody
|
|
89
|
+
export declare function submitAccessRequest(options: AccessRequestClientOptions, body: AccessRequestBody): Promise<AccessRequestRow>
|
|
90
|
+
export declare function listMyAccessRequests(options: AccessRequestClientOptions): Promise<AccessRequestRow[]>
|
|
91
|
+
export declare function getAccessRequest(options: AccessRequestClientOptions, id: string): Promise<AccessRequestRow>
|
|
92
|
+
export declare function describeAccessRequest(row: Partial<AccessRequestRow>): string
|
|
93
|
+
export declare function buildAdditionalPermissions(value: unknown): Array<{ code: string; nameTr: string; nameEn?: string }>
|
|
94
|
+
export declare function parsePermissionOptions(trValues: readonly string[], enValues?: readonly string[]): AdditionalPermissionInput[]
|
|
95
|
+
export declare function getPortalContext(options: AccessRequestClientOptions): Promise<PortalContext>
|
|
96
|
+
export declare function describePortalContext(context: Partial<PortalContext>): string
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
// Devoplus One ERİŞİM TALEBİ istemcisi (D-75). `one request` komutu ve Devoplus One MCP sunucusu AYNI modülü kullanır;
|
|
2
|
+
// ikisi aynı backend ucunu (`api/v1/One/access-requests`) çağırır.
|
|
3
|
+
//
|
|
4
|
+
// ⛔ Talep YENİ BİR YETKİ YOLU AÇMAZ: yalnız yöneticiye bir istek bırakır. Gönderenin kimliği ve portalı OTURUMDAN
|
|
5
|
+
// (kullanıcının kendi erişim belirtecinden) gelir; bu modül gövdeye portal ya da kişi YAZMAZ.
|
|
6
|
+
//
|
|
7
|
+
// Burada yalnız gövdenin kurulması, türe göre ZORUNLU alanların varlığı, uzunluk ve sayı sınırları denetlenir. Biçim
|
|
8
|
+
// kuralları (kısa ad, portal anahtarı, izin kodu, sorgu anahtarı, yetki alanı) sunucudadır; sunucunun reddi
|
|
9
|
+
// açıklamasıyla birlikte kullanıcıya taşınır. İki yerde tutulan biçim kuralı zamanla ayrışırdı.
|
|
10
|
+
|
|
11
|
+
export class AccessRequestError extends Error {
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} message kullanıcıya gösterilecek Türkçe metin
|
|
14
|
+
* @param {{ status?: number, code?: string }} [details]
|
|
15
|
+
*/
|
|
16
|
+
constructor(message, details = {}) {
|
|
17
|
+
super(message)
|
|
18
|
+
this.name = 'AccessRequestError'
|
|
19
|
+
this.status = details.status
|
|
20
|
+
this.code = details.code
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Sunucu sınırları — backend `OneAccessRequest` / `OneApp` / `OneAppPermission` sabitleriyle aynı. */
|
|
25
|
+
export const LIMITS = {
|
|
26
|
+
justification: 2000,
|
|
27
|
+
description: 2000,
|
|
28
|
+
draftSql: 20000,
|
|
29
|
+
title: 120,
|
|
30
|
+
permissionName: 120,
|
|
31
|
+
additionalPermissions: 16,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Talep türleri: komut adı → tel adı (backend `OneAccessRequestNames`) + zorunlu alanlar + kime düşer.
|
|
36
|
+
* `audience: 'platform'` → platform yöneticisi; `'company'` → talebin portalının şirket yöneticisi (küresel yönetici de
|
|
37
|
+
* onaylayabilir). Kayıt talebi 19.10.2026'dan beri şirket yöneticisine düşer; yetki alanı platformda kalır.
|
|
38
|
+
*/
|
|
39
|
+
export const KINDS = {
|
|
40
|
+
registration: {
|
|
41
|
+
wire: 'registration',
|
|
42
|
+
label: 'Yeni uygulama kaydı',
|
|
43
|
+
required: ['titleTr'],
|
|
44
|
+
// `additionalPermissions`: uygulama içi izinler kayıtla birlikte istenir; onayda kataloğa girer (19.10.2026).
|
|
45
|
+
optional: ['titleEn', 'additionalPermissions'],
|
|
46
|
+
audience: 'company',
|
|
47
|
+
},
|
|
48
|
+
installation: {
|
|
49
|
+
wire: 'installation',
|
|
50
|
+
label: 'Uygulamanın portala kurulması',
|
|
51
|
+
// Portal anahtarını sunucu portalın adından belirler (örn. "Süvari Portal" için suvari); elle seçilemez.
|
|
52
|
+
// `portalKey` yalnız eski istemcilerle uyumluluk için kabul edilir, sunucu onu yok sayar (19.10.2026).
|
|
53
|
+
required: [],
|
|
54
|
+
optional: ['portalKey'],
|
|
55
|
+
audience: 'company',
|
|
56
|
+
},
|
|
57
|
+
'dexa-query': {
|
|
58
|
+
wire: 'dexaQuery',
|
|
59
|
+
label: 'DEXA okuma sorgusu izni',
|
|
60
|
+
required: ['queryKey'],
|
|
61
|
+
optional: [],
|
|
62
|
+
audience: 'company',
|
|
63
|
+
},
|
|
64
|
+
'dexa-command': {
|
|
65
|
+
wire: 'dexaCommand',
|
|
66
|
+
label: 'ERP\'ye yazan DEXA işlemi izni',
|
|
67
|
+
required: ['queryKey'],
|
|
68
|
+
optional: [],
|
|
69
|
+
audience: 'company',
|
|
70
|
+
},
|
|
71
|
+
'app-permission': {
|
|
72
|
+
wire: 'appPermission',
|
|
73
|
+
label: 'Uygulama izninin bir gruba atanması',
|
|
74
|
+
required: ['permissionCode'],
|
|
75
|
+
optional: ['permissionNameTr', 'permissionNameEn', 'userGroupId'],
|
|
76
|
+
audience: 'company',
|
|
77
|
+
},
|
|
78
|
+
scope: {
|
|
79
|
+
wire: 'scope',
|
|
80
|
+
label: 'Yetki alanı (scope)',
|
|
81
|
+
required: ['scope'],
|
|
82
|
+
optional: [],
|
|
83
|
+
audience: 'platform',
|
|
84
|
+
},
|
|
85
|
+
'new-query': {
|
|
86
|
+
wire: 'newQuery',
|
|
87
|
+
label: 'Henüz olmayan bir sorgu için iş talebi',
|
|
88
|
+
required: ['description'],
|
|
89
|
+
optional: ['draftSql'],
|
|
90
|
+
audience: 'company',
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Alanların kullanıcıya görünen adları (hata metinleri için). */
|
|
95
|
+
const FIELD_LABELS = {
|
|
96
|
+
appSlug: 'uygulamanın kısa adı',
|
|
97
|
+
justification: 'gerekçe',
|
|
98
|
+
titleTr: 'uygulamanın Türkçe adı',
|
|
99
|
+
titleEn: 'uygulamanın İngilizce adı',
|
|
100
|
+
portalKey: 'portal anahtarı',
|
|
101
|
+
queryKey: 'sorgu anahtarı',
|
|
102
|
+
permissionCode: 'izin kodu',
|
|
103
|
+
permissionNameTr: 'iznin Türkçe adı',
|
|
104
|
+
permissionNameEn: 'iznin İngilizce adı',
|
|
105
|
+
userGroupId: 'kullanıcı grubu kimliği',
|
|
106
|
+
scope: 'yetki alanı',
|
|
107
|
+
description: 'sorgu tarifi',
|
|
108
|
+
draftSql: 'SQL taslağı',
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const LENGTH_OF = {
|
|
112
|
+
justification: LIMITS.justification,
|
|
113
|
+
description: LIMITS.description,
|
|
114
|
+
draftSql: LIMITS.draftSql,
|
|
115
|
+
titleTr: LIMITS.title,
|
|
116
|
+
titleEn: LIMITS.title,
|
|
117
|
+
permissionNameTr: LIMITS.permissionName,
|
|
118
|
+
permissionNameEn: LIMITS.permissionName,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Tel adı ya da komut adı → komut adı. Harf duyarsız (`dexaQuery` = `dexa-query`). */
|
|
122
|
+
export function resolveKind(value) {
|
|
123
|
+
const text = String(value ?? '').trim().toLowerCase().replace(/_/g, '-')
|
|
124
|
+
for (const [name, kind] of Object.entries(KINDS)) {
|
|
125
|
+
if (name === text || kind.wire.toLowerCase() === text) return name
|
|
126
|
+
}
|
|
127
|
+
return undefined
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function clean(value) {
|
|
131
|
+
if (value === undefined || value === null) return undefined
|
|
132
|
+
const text = String(value).trim()
|
|
133
|
+
return text === '' ? undefined : text
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Talep gövdesini kurar. İlgisiz alanlar gövdeye girmez (sunucu yok sayardı; göndermemek talebi okuyan yöneticiye
|
|
138
|
+
* gösterilen içeriği daraltır). Hata → `AccessRequestError`, ağ çağrısı YAPILMADAN.
|
|
139
|
+
*
|
|
140
|
+
* @param {string} kind komut adı ya da tel adı
|
|
141
|
+
* @param {Record<string, unknown>} fields `appSlug`, `justification` + türün alanları
|
|
142
|
+
*/
|
|
143
|
+
export function buildAccessRequest(kind, fields = {}) {
|
|
144
|
+
const name = resolveKind(kind)
|
|
145
|
+
if (!name)
|
|
146
|
+
throw new AccessRequestError(`Talep türü tanınmadı: "${kind}". Geçerli türler: ${Object.keys(KINDS).join(', ')}.`)
|
|
147
|
+
const spec = KINDS[name]
|
|
148
|
+
const appSlug = clean(fields.appSlug)?.toLowerCase()
|
|
149
|
+
if (!appSlug) throw new AccessRequestError('Uygulamanın kısa adı zorunludur (one.manifest.json dosyasındaki app.slug).')
|
|
150
|
+
|
|
151
|
+
const body = { kind: spec.wire, appSlug }
|
|
152
|
+
for (const key of ['justification', ...spec.required, ...spec.optional]) {
|
|
153
|
+
if (key === 'additionalPermissions') {
|
|
154
|
+
const list = buildAdditionalPermissions(fields[key])
|
|
155
|
+
if (list.length > 0) body[key] = list
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
const value = clean(fields[key])
|
|
159
|
+
if (value === undefined) {
|
|
160
|
+
if (spec.required.includes(key))
|
|
161
|
+
throw new AccessRequestError(`"${spec.label}" talebi için ${FIELD_LABELS[key]} zorunludur.`)
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
const max = LENGTH_OF[key]
|
|
165
|
+
if (max !== undefined && value.length > max)
|
|
166
|
+
throw new AccessRequestError(`${capitalize(FIELD_LABELS[key])} en çok ${max} karakter olabilir (${value.length}).`)
|
|
167
|
+
body[key] = value
|
|
168
|
+
}
|
|
169
|
+
return body
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Kayıt talebinin ek izinleri: `[{ code, nameTr, nameEn? }]`, en çok 16. Burada yalnız yapı, sayı, uzunluk ve birebir
|
|
174
|
+
* yinelenen kod denetlenir; kodun biçimi (`One.<Ad>.<Eylem>`) ve uygulamanın ad alanında olması SUNUCUDADIR.
|
|
175
|
+
*
|
|
176
|
+
* @param {unknown} value
|
|
177
|
+
* @returns {Array<{ code: string, nameTr: string, nameEn?: string }>}
|
|
178
|
+
*/
|
|
179
|
+
export function buildAdditionalPermissions(value) {
|
|
180
|
+
if (value === undefined || value === null) return []
|
|
181
|
+
if (!Array.isArray(value)) throw new AccessRequestError('Ek izinler bir liste olmalı: [{ code, nameTr, nameEn? }].')
|
|
182
|
+
if (value.length > LIMITS.additionalPermissions)
|
|
183
|
+
throw new AccessRequestError(`En çok ${LIMITS.additionalPermissions} ek izin istenebilir (${value.length}).`)
|
|
184
|
+
const seen = new Set()
|
|
185
|
+
return value.map((item, i) => {
|
|
186
|
+
const code = clean(item?.code)
|
|
187
|
+
const nameTr = clean(item?.nameTr)
|
|
188
|
+
const nameEn = clean(item?.nameEn)
|
|
189
|
+
const at = `${i + 1}. ek izin`
|
|
190
|
+
if (!code) throw new AccessRequestError(`${at}: izin kodu zorunludur (One.<Uygulama>.<Eylem>).`)
|
|
191
|
+
if (!nameTr) throw new AccessRequestError(`${at} (${code}): iznin Türkçe adı zorunludur.`)
|
|
192
|
+
if (code.length > 200) throw new AccessRequestError(`${at}: izin kodu en çok 200 karakter olabilir.`)
|
|
193
|
+
for (const [label, name] of [['Türkçe', nameTr], ['İngilizce', nameEn]])
|
|
194
|
+
if (name !== undefined && name.length > LIMITS.permissionName)
|
|
195
|
+
throw new AccessRequestError(`${at} (${code}): iznin ${label} adı en çok ${LIMITS.permissionName} karakter olabilir.`)
|
|
196
|
+
if (seen.has(code)) throw new AccessRequestError(`Ek izin kodu iki kez yazılmış: ${code}.`)
|
|
197
|
+
seen.add(code)
|
|
198
|
+
return nameEn === undefined ? { code, nameTr } : { code, nameTr, nameEn }
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Komut satırının `--permission <kod>=<Türkçe ad>` ve `--permission-en <kod>=<İngilizce ad>` değerlerini ek izin
|
|
204
|
+
* listesine çevirir. İngilizce ad yalnız `--permission` ile verilmiş bir koda eklenebilir.
|
|
205
|
+
*
|
|
206
|
+
* @param {readonly string[]} trValues
|
|
207
|
+
* @param {readonly string[]} [enValues]
|
|
208
|
+
*/
|
|
209
|
+
export function parsePermissionOptions(trValues, enValues = []) {
|
|
210
|
+
const split = (raw, option) => {
|
|
211
|
+
const text = String(raw ?? '')
|
|
212
|
+
const at = text.indexOf('=')
|
|
213
|
+
if (at <= 0) throw new AccessRequestError(`${option} "<kod>=<ad>" biçiminde olmalı: ${text}`)
|
|
214
|
+
return [text.slice(0, at).trim(), text.slice(at + 1).trim()]
|
|
215
|
+
}
|
|
216
|
+
const list = trValues.map((raw) => {
|
|
217
|
+
const [code, nameTr] = split(raw, '--permission')
|
|
218
|
+
return { code, nameTr }
|
|
219
|
+
})
|
|
220
|
+
for (const raw of enValues) {
|
|
221
|
+
const [code, nameEn] = split(raw, '--permission-en')
|
|
222
|
+
const item = list.find((p) => p.code === code)
|
|
223
|
+
if (!item) throw new AccessRequestError(`--permission-en için önce aynı kodla --permission verin: ${code}`)
|
|
224
|
+
item.nameEn = nameEn
|
|
225
|
+
}
|
|
226
|
+
return list
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function capitalize(text) {
|
|
230
|
+
return text.charAt(0).toLocaleUpperCase('tr-TR') + text.slice(1)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** API tabanı `https://.../` biçiminde olmalı; uç yolu ona eklenir. */
|
|
234
|
+
function endpoint(apiBase, path) {
|
|
235
|
+
// Belirteç bu adrese gider: düz http yalnız yerel geliştirme adresinde (RFC 6750 §5.3).
|
|
236
|
+
const base = apiBase ?? ''
|
|
237
|
+
if (!/^https:\/\/[^\s/]+(\/[^\s]*)?\/$/.test(base) && !/^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/([^\s]*\/)?$/.test(base))
|
|
238
|
+
throw new AccessRequestError(`API tabanı "https://.../" biçiminde ve "/" ile bitmeli (http yalnız localhost): ${apiBase}`)
|
|
239
|
+
return new URL(`api/v1/One/access-requests${path}`, apiBase).toString()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Sunucunun ProblemDetails yanıtını kullanıcı metnine çevirir; gövde yoksa durum koduna göre sabit cümle. */
|
|
243
|
+
async function failure(response) {
|
|
244
|
+
let detail
|
|
245
|
+
let code
|
|
246
|
+
try {
|
|
247
|
+
const problem = await response.json()
|
|
248
|
+
detail = typeof problem?.detail === 'string' ? problem.detail : undefined
|
|
249
|
+
code = typeof problem?.code === 'string' ? problem.code : undefined
|
|
250
|
+
} catch {
|
|
251
|
+
// gövdesiz 401/403 — aşağıdaki sabit metin
|
|
252
|
+
}
|
|
253
|
+
const fallback =
|
|
254
|
+
response.status === 401
|
|
255
|
+
? 'Oturumunuz geçersiz ya da süresi dolmuş; yeniden giriş yapın.'
|
|
256
|
+
: response.status === 403
|
|
257
|
+
? 'Bu talebi gönderme yetkiniz yok.'
|
|
258
|
+
: response.status === 429
|
|
259
|
+
? 'Çok fazla talep gönderdiniz; bir süre sonra yeniden deneyin.'
|
|
260
|
+
: `Devoplus isteği başarısız oldu (HTTP ${response.status}).`
|
|
261
|
+
return new AccessRequestError(detail ?? fallback, { status: response.status, code })
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @typedef {{ apiBase: string, accessToken: string, fetch?: typeof fetch }} ClientOptions
|
|
266
|
+
*/
|
|
267
|
+
|
|
268
|
+
async function call(options, path, init = {}) {
|
|
269
|
+
const doFetch = options.fetch ?? fetch
|
|
270
|
+
if (!options.accessToken) throw new AccessRequestError('Oturum yok; önce giriş yapın.', { status: 401 })
|
|
271
|
+
let response
|
|
272
|
+
try {
|
|
273
|
+
response = await doFetch(endpoint(options.apiBase, path), {
|
|
274
|
+
...init,
|
|
275
|
+
headers: {
|
|
276
|
+
Accept: 'application/json',
|
|
277
|
+
Authorization: `Bearer ${options.accessToken}`,
|
|
278
|
+
...(init.body ? { 'Content-Type': 'application/json' } : {}),
|
|
279
|
+
},
|
|
280
|
+
})
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error instanceof AccessRequestError) throw error
|
|
283
|
+
throw new AccessRequestError('Devoplus API\'ye ulaşılamadı.')
|
|
284
|
+
}
|
|
285
|
+
if (!response.ok) throw await failure(response)
|
|
286
|
+
return response.json()
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Talebi gönderir. Dönüş: sunucunun talep satırı (`id`, `status` …). */
|
|
290
|
+
export function submitAccessRequest(options, body) {
|
|
291
|
+
return call(options, '', { method: 'POST', body: JSON.stringify(body) })
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Çağıranın kendi talepleri (en yeni önce). */
|
|
295
|
+
export function listMyAccessRequests(options) {
|
|
296
|
+
return call(options, '/mine')
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Oturum portalının bağlamı: `{ portalId, portalName, portalKey | null }`. Kurulum talebinde kullanıcıya portal adresi
|
|
301
|
+
* sormamak için okunur; `portalKey` portaldaki var olan bir kurulumun anahtarıdır, yoksa `null`.
|
|
302
|
+
*/
|
|
303
|
+
export function getPortalContext(options) {
|
|
304
|
+
return call(options, '/context')
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Portal bağlamını tek satırlık Türkçe özete çevirir. */
|
|
308
|
+
export function describePortalContext(context) {
|
|
309
|
+
const name = context?.portalName ? String(context.portalName) : 'adı okunamadı'
|
|
310
|
+
const key =
|
|
311
|
+
typeof context?.portalKey === 'string' && context.portalKey
|
|
312
|
+
? `kısa ad (portal anahtarı): ${context.portalKey}`
|
|
313
|
+
: 'bu portalda henüz kısa ad yok; kurulum onayında sunucu portalın adından belirler'
|
|
314
|
+
return `Portal: ${name} (kimlik ${context?.portalId ?? '?'}); ${key}`
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** Tek talep — çağıran talep sahibi değilse sunucu 404 döner. */
|
|
318
|
+
export function getAccessRequest(options, id) {
|
|
319
|
+
const text = String(id ?? '').trim()
|
|
320
|
+
if (!/^[0-9a-f]{24}$/i.test(text)) throw new AccessRequestError(`Talep kimliği 24 karakterlik onaltılık olmalı: ${id}`)
|
|
321
|
+
return call(options, `/${text}`)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const STATUS_LABELS = { pending: 'Bekliyor', approved: 'Onaylandı', rejected: 'Reddedildi' }
|
|
325
|
+
|
|
326
|
+
/** Talep satırını tek satırlık Türkçe özete çevirir (CLI listesi ve MCP yanıtı). */
|
|
327
|
+
export function describeAccessRequest(row) {
|
|
328
|
+
const name = resolveKind(row?.kind)
|
|
329
|
+
const label = name ? KINDS[name].label : String(row?.kind ?? '?')
|
|
330
|
+
const subject =
|
|
331
|
+
row?.portalKey ?? row?.queryKey ?? row?.permissionCode ?? row?.scope ?? row?.titleTr ?? row?.description ?? ''
|
|
332
|
+
const status = STATUS_LABELS[row?.status] ?? String(row?.status ?? '?')
|
|
333
|
+
const parts = [`${row?.id ?? '?'} ${status.padEnd(10)} ${row?.appSlug ?? '?'}, ${label}`]
|
|
334
|
+
if (subject) parts.push(`: ${String(subject).slice(0, 80)}`)
|
|
335
|
+
const extra = Array.isArray(row?.additionalPermissions) ? row.additionalPermissions.length : 0
|
|
336
|
+
if (extra > 0) parts.push(` (+${extra} ek izin)`)
|
|
337
|
+
if (row?.decisionNote) parts.push(`; not: ${row.decisionNote}`)
|
|
338
|
+
if (row?.resolvedQueryKey) parts.push(`; sorgu anahtarı: ${row.resolvedQueryKey}`)
|
|
339
|
+
return parts.join('')
|
|
340
|
+
}
|
package/bin/appOps.d.mts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// appOps.mjs tipleri — Devoplus One MCP sunucusu ve TypeScript tüketicileri için. Davranış .mjs'tedir.
|
|
2
|
+
|
|
3
|
+
export declare class AppOpsError extends Error {
|
|
4
|
+
readonly status: number | undefined
|
|
5
|
+
readonly code: string | undefined
|
|
6
|
+
constructor(message: string, details?: { status?: number; code?: string })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export declare const SLUG_RE: RegExp
|
|
10
|
+
export declare const SLUG_MAX: number
|
|
11
|
+
export declare const PORTAL_KEY_RE: RegExp
|
|
12
|
+
export declare const VERSION_RE: RegExp
|
|
13
|
+
export declare const DAYS_DEFAULT: number
|
|
14
|
+
export declare const DAYS_MAX: number
|
|
15
|
+
export declare const PREVIEW_HOST_BASE: string
|
|
16
|
+
export declare const NOT_CONFIGURED_MESSAGE: string
|
|
17
|
+
export declare const INSIGHTS_NOT_CONFIGURED_MESSAGE: string
|
|
18
|
+
export declare const ROLLBACK_WARNING: string
|
|
19
|
+
|
|
20
|
+
export type DeploymentAction = 'deploy' | 'promote' | 'rollback'
|
|
21
|
+
export declare const ACTIONS: Readonly<Record<DeploymentAction, string>>
|
|
22
|
+
export declare const COMMAND_ACTIONS: Readonly<{ publish: 'deploy'; promote: 'promote'; rollback: 'rollback' }>
|
|
23
|
+
|
|
24
|
+
export interface AppOpsClientOptions {
|
|
25
|
+
apiBase: string
|
|
26
|
+
accessToken: string
|
|
27
|
+
fetch?: typeof fetch
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface DeploymentFields {
|
|
31
|
+
action?: string | undefined
|
|
32
|
+
portalKey?: string | undefined
|
|
33
|
+
toVersion?: string | undefined
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DeploymentRequestBody {
|
|
37
|
+
action: DeploymentAction
|
|
38
|
+
portalKey?: string
|
|
39
|
+
toVersion?: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Backend yanıtı (C5): 202 `{ id, status, pipelineUrl? }`. */
|
|
43
|
+
export interface DeploymentResult {
|
|
44
|
+
id: string
|
|
45
|
+
status: 'queued' | 'not_configured' | (string & {})
|
|
46
|
+
pipelineUrl?: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Liste satırı — C5 alanları; sunucu fazlasını taşıyabilir. */
|
|
50
|
+
export interface DeploymentRow extends Partial<DeploymentResult> {
|
|
51
|
+
action?: string
|
|
52
|
+
portalKey?: string
|
|
53
|
+
toVersion?: string
|
|
54
|
+
createdAt?: string
|
|
55
|
+
[field: string]: unknown
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface AppInsights {
|
|
59
|
+
configured: boolean
|
|
60
|
+
from?: string
|
|
61
|
+
to?: string
|
|
62
|
+
totals?: { requests?: number; errors?: number; cpuP50Ms?: number; cpuP99Ms?: number }
|
|
63
|
+
daily?: Array<{ date: string; requests: number; errors: number }>
|
|
64
|
+
recentErrors?: Array<{ time: string; message: string; path?: string }>
|
|
65
|
+
jobs?: { failed?: number }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type OpsCommand = 'publish' | 'promote' | 'rollback' | 'deployments' | 'status'
|
|
69
|
+
|
|
70
|
+
export interface OpsArgs {
|
|
71
|
+
json: boolean
|
|
72
|
+
portalKey: string | undefined
|
|
73
|
+
app: string | undefined
|
|
74
|
+
toVersion?: string | undefined
|
|
75
|
+
yes?: boolean
|
|
76
|
+
days?: number
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export declare function checkSlug(value: unknown): string
|
|
80
|
+
export declare function checkPortalKey(value: unknown): string | undefined
|
|
81
|
+
export declare function checkDays(value: unknown): number
|
|
82
|
+
export declare function buildDeploymentRequest(fields?: DeploymentFields): DeploymentRequestBody
|
|
83
|
+
export declare function requestDeployment(options: AppOpsClientOptions, slug: string, body: DeploymentFields): Promise<DeploymentResult>
|
|
84
|
+
export declare function listDeployments(options: AppOpsClientOptions, slug: string, portalKey?: string): Promise<DeploymentRow[]>
|
|
85
|
+
export declare function getInsights(
|
|
86
|
+
options: AppOpsClientOptions,
|
|
87
|
+
slug: string,
|
|
88
|
+
query?: { portalKey?: string | undefined; days?: number | string | undefined },
|
|
89
|
+
): Promise<AppInsights>
|
|
90
|
+
export declare function previewAddress(slug: string, portalKey: string | undefined): string | undefined
|
|
91
|
+
export declare function describeDeployment(row: Partial<DeploymentRow>): string
|
|
92
|
+
export declare function describeDeploymentResult(
|
|
93
|
+
result: Partial<DeploymentResult>,
|
|
94
|
+
request: { action: string; slug: string; portalKey?: string | undefined },
|
|
95
|
+
): string
|
|
96
|
+
export declare function describeInsights(insights: Partial<AppInsights> | undefined): string
|
|
97
|
+
export declare function parseOpsArgs(command: OpsCommand, argv: readonly string[]): OpsArgs
|