@enformik/cli 0.1.1 → 0.2.0
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/README.md +3 -2
- package/dist/cli.js +4 -2
- package/dist/commands/schema.js +45 -3
- package/dist/schema.js +33 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,20 +23,21 @@ npx @enformik/cli site deploy --dir dist
|
|
|
23
23
|
|
|
24
24
|
## Şema (modül) yükseltme
|
|
25
25
|
|
|
26
|
-
Gerekenler: uygulamanızda **Şema yükseltici** (ya da Yönetici
|
|
26
|
+
Gerekenler: uygulamanızda **Şema yükseltici** (yalnızca yükseltme), **Şema oluşturucu** (yükseltme + ilk kurulum) ya da Yönetici rolünde bir **API istemcisi** (konsol → **API Anahtarları** sayfası). Modülün ilk kurulumu `schema install` ile (Şema oluşturucu/Yönetici), sonraki yükseltmeler `schema push` ile yapılır.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
export ENFORMIK_APP_URL=https://<uygulama-adresiniz>
|
|
30
30
|
export ENFORMIK_CLIENT_ID=apic-…
|
|
31
31
|
export ENFORMIK_CLIENT_SECRET=…
|
|
32
32
|
|
|
33
|
+
npx @enformik/cli schema install --manifest module.json --yes # modülün ilk kurulumu (--dry-run: yalnızca göster)
|
|
33
34
|
npx @enformik/cli schema diff --manifest module.json --check # değişiklik varsa çıkış kodu 2
|
|
34
35
|
npx @enformik/cli schema push --manifest module.json --yes
|
|
35
36
|
```
|
|
36
37
|
|
|
37
38
|
> **Dikkat:** modül (şema) değişikliği uygulamanın **tüm çalışma alanlarını** etkiler. Canlı uygulamaya laptop'tan değil, CI'dan ve canlıya özel bir istemci ile uygulayın.
|
|
38
39
|
|
|
39
|
-
"Şema yükseltici"
|
|
40
|
+
"Şema yükseltici" ve "Şema oluşturucu" rolleri betik, otomasyon, yetki tanımı, veri kaynağı, etkileşimli sayfa, arayüz uzantısı ve tohum veri içeren manifestleri ve alan türü değişikliklerini uygulayamaz; bunlar bir yönetici tarafından uygulanır.
|
|
40
41
|
|
|
41
42
|
## Komutlar
|
|
42
43
|
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readFileSync, realpathSync } from 'node:fs';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { parseArgs } from 'node:util';
|
|
5
5
|
import { link } from './commands/link.js';
|
|
6
|
-
import { schemaDiff, schemaPush } from './commands/schema.js';
|
|
6
|
+
import { schemaDiff, schemaInstall, schemaPush } from './commands/schema.js';
|
|
7
7
|
import { siteDeploy, siteStatus } from './commands/site.js';
|
|
8
8
|
import { whoami } from './commands/whoami.js';
|
|
9
9
|
import { loadConfig, resolveSettings } from './config.js';
|
|
@@ -16,7 +16,7 @@ const OPTIONS = {
|
|
|
16
16
|
config: { type: 'string' },
|
|
17
17
|
'console-url': { type: 'string' }, 'app-url': { type: 'string' }, workspace: { type: 'string' },
|
|
18
18
|
module: { type: 'string' }, manifest: { type: 'string' }, dir: { type: 'string' },
|
|
19
|
-
check: { type: 'boolean' }, yes: { type: 'boolean', short: 'y' }, 'seed-data': { type: 'boolean' }, 'expect-host': { type: 'string' },
|
|
19
|
+
check: { type: 'boolean' }, yes: { type: 'boolean', short: 'y' }, 'seed-data': { type: 'boolean' }, 'dry-run': { type: 'boolean' }, 'expect-host': { type: 'string' },
|
|
20
20
|
'no-wait': { type: 'boolean' }, timeout: { type: 'string' }, 'no-verify': { type: 'boolean' },
|
|
21
21
|
};
|
|
22
22
|
const GLOBAL = ['json', 'help', 'version', 'debug', 'config'];
|
|
@@ -24,6 +24,7 @@ const COMMANDS = {
|
|
|
24
24
|
link: { flags: ['console-url', 'app-url', 'workspace', 'module', 'manifest', 'dir', 'no-verify'], run: link, usage: 'enformik link [--console-url U] [--app-url U] [--workspace ID] [--module SLUG] [--manifest YOL] [--dir KLASÖR]' },
|
|
25
25
|
whoami: { flags: ['console-url', 'app-url', 'workspace'], run: whoami, usage: 'enformik whoami' },
|
|
26
26
|
'schema diff': { flags: ['app-url', 'workspace', 'module', 'manifest', 'check', 'seed-data', 'expect-host'], run: schemaDiff, usage: 'enformik schema diff [--manifest module.json] [--check]' },
|
|
27
|
+
'schema install': { flags: ['app-url', 'workspace', 'module', 'manifest', 'yes', 'dry-run', 'seed-data', 'expect-host'], run: schemaInstall, usage: 'enformik schema install [--manifest module.json] [--yes] [--dry-run]' },
|
|
27
28
|
'schema push': { flags: ['app-url', 'workspace', 'module', 'manifest', 'yes', 'seed-data', 'expect-host'], run: schemaPush, usage: 'enformik schema push [--manifest module.json] [--yes] [--seed-data]' },
|
|
28
29
|
'site deploy': { flags: ['console-url', 'dir', 'no-wait', 'timeout'], run: siteDeploy, usage: 'enformik site deploy [--dir dist] [--no-wait] [--timeout 600]' },
|
|
29
30
|
'site status': { flags: ['console-url'], run: siteStatus, usage: 'enformik site status' },
|
|
@@ -37,6 +38,7 @@ Komutlar
|
|
|
37
38
|
link .enformik/config.json yazar (adresler; sır içermez)
|
|
38
39
|
whoami Hangi kimlikle, hangi hedefe bağlanıldığını gösterir
|
|
39
40
|
schema diff Modül manifestini uygulamadakiyle karşılaştırır (--check: değişiklik varsa çıkış kodu 2)
|
|
41
|
+
schema install Modülü uygulamaya İLK kez kurar (rol: Şema oluşturucu; --dry-run yalnızca gösterir)
|
|
40
42
|
schema push Değişiklikleri uygular (etkileşimsiz ortamda --yes gerekir)
|
|
41
43
|
site deploy Derlenmiş siteyi (varsayılan: dist) web sitesi ortamına yayınlar
|
|
42
44
|
site status Hedef site ve canlı sürüm bilgisi
|
package/dist/commands/schema.js
CHANGED
|
@@ -5,12 +5,12 @@ import { CliError } from '../errors.js';
|
|
|
5
5
|
import { assertSecureUrl } from '../http.js';
|
|
6
6
|
import { adminOnlySections, parseManifest, pendingChanges, renderDiff, SchemaClient, typeChanges } from '../schema.js';
|
|
7
7
|
/** Ortak hazırlık: manifest → uygulama keşfi → belirteç → modül kimliği. */
|
|
8
|
-
async function prepare(ctx) {
|
|
8
|
+
async function prepare(ctx, mode = 'existing') {
|
|
9
9
|
const { settings, out } = ctx;
|
|
10
10
|
if (!settings.appUrl)
|
|
11
11
|
throw new CliError('Uygulama adresi yok. `enformik link --app-url https://…` çalıştırın ya da ENFORMIK_APP_URL tanımlayın.');
|
|
12
12
|
if (!settings.clientId || !settings.clientSecret) {
|
|
13
|
-
throw new CliError('ENFORMIK_CLIENT_ID ve ENFORMIK_CLIENT_SECRET tanımlı olmalı (konsolda
|
|
13
|
+
throw new CliError('ENFORMIK_CLIENT_ID ve ENFORMIK_CLIENT_SECRET tanımlı olmalı (konsolda "API anahtarları" sayfasından rolü "Şema yükseltici" — ilk kurulum için "Şema oluşturucu" — olan bir istemci oluşturun).');
|
|
14
14
|
}
|
|
15
15
|
const appUrl = assertSecureUrl(settings.appUrl, 'Uygulama adresi');
|
|
16
16
|
const expect = ctx.flags['expect-host'];
|
|
@@ -33,7 +33,7 @@ async function prepare(ctx) {
|
|
|
33
33
|
const seedData = ctx.flags['seed-data'] === true;
|
|
34
34
|
const admin = adminOnlySections(manifest, { seedData });
|
|
35
35
|
if (admin.length > 0) {
|
|
36
|
-
out.warn(`Not: manifest yönetici gerektiren bölümler içeriyor (${admin.join(', ')}). "Şema yükseltici" rolündeki bir istemci bunu uygulayamaz.`);
|
|
36
|
+
out.warn(`Not: manifest yönetici gerektiren bölümler içeriyor (${admin.join(', ')}). "Şema yükseltici/oluşturucu" rolündeki bir istemci bunu uygulayamaz.`);
|
|
37
37
|
}
|
|
38
38
|
const app = await discoverApp(settings.appUrl, ctx.version, ctx.fetchImpl);
|
|
39
39
|
const workspaceId = settings.workspaceId || app.tenantId;
|
|
@@ -41,6 +41,12 @@ async function prepare(ctx) {
|
|
|
41
41
|
throw new CliError('Çalışma alanı belirlenemedi. --workspace <kimlik> verin ya da `enformik link --workspace` ile kaydedin.');
|
|
42
42
|
const tok = await fetchAccessToken(app, settings.clientId, settings.clientSecret, ctx.version, ctx.fetchImpl);
|
|
43
43
|
const client = new SchemaClient({ appUrl: settings.appUrl, token: tok.token, workspaceId, version: ctx.version, fetchImpl: ctx.fetchImpl });
|
|
44
|
+
if (mode === 'install') {
|
|
45
|
+
const existing = await client.findModule(slug);
|
|
46
|
+
if (existing)
|
|
47
|
+
throw new CliError(`"${slug}" modülü bu uygulamada zaten kurulu (sürüm ${existing.version}). Yükseltmek için \`enformik schema push\` kullanın.`);
|
|
48
|
+
return { client, manifest, manifestJson: JSON.stringify(manifest), moduleId: '', installedVersion: '', appHost: appUrl.hostname, seedData };
|
|
49
|
+
}
|
|
44
50
|
const mod = await client.resolveModule(slug);
|
|
45
51
|
return { client, manifest, manifestJson: JSON.stringify(manifest), moduleId: mod.id, installedVersion: mod.version, appHost: appUrl.hostname, seedData };
|
|
46
52
|
}
|
|
@@ -109,3 +115,39 @@ export async function schemaPush(ctx) {
|
|
|
109
115
|
ctx.out.result({ ...summary(p, res), applied: true });
|
|
110
116
|
return 0;
|
|
111
117
|
}
|
|
118
|
+
/** enformik schema install [--yes] [--dry-run] — modülün ilk kurulumu (rol: Şema oluşturucu ya da Yönetici). */
|
|
119
|
+
export async function schemaInstall(ctx) {
|
|
120
|
+
const p = await prepare(ctx, 'install');
|
|
121
|
+
const slug = p.manifest.module.slug;
|
|
122
|
+
const dry = await p.client.install(p.manifestJson, { seedData: p.seedData, dryRun: true });
|
|
123
|
+
ctx.out.info(`Modül: ${slug} yeni kurulum → manifest ${p.manifest.module.version}`);
|
|
124
|
+
ctx.out.info(renderDiff(ctx.out, dry, { appHost: p.appHost }));
|
|
125
|
+
const base = { module: slug, manifestVersion: p.manifest.module.version, changes: pendingChanges(dry.diffs).length, diffs: dry.diffs, errors: dry.errors };
|
|
126
|
+
if (dry.errors.length > 0) {
|
|
127
|
+
ctx.out.result({ ...base, installed: false });
|
|
128
|
+
return 1;
|
|
129
|
+
}
|
|
130
|
+
if (ctx.flags['dry-run'] === true) {
|
|
131
|
+
ctx.out.result({ ...base, installed: false });
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
if (ctx.flags.yes !== true) {
|
|
135
|
+
if (!ctx.isTTY)
|
|
136
|
+
throw new CliError('Etkileşimli terminal yok: modülü kurmak için --yes verin (sessizce onaylanmaz).');
|
|
137
|
+
if (!(await ctx.confirm('Modülü kurmak istiyor musunuz?'))) {
|
|
138
|
+
ctx.out.info('Vazgeçildi; hiçbir şey kurulmadı.');
|
|
139
|
+
ctx.out.result({ ...base, installed: false });
|
|
140
|
+
return 1;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const res = await p.client.install(p.manifestJson, { seedData: p.seedData, dryRun: false });
|
|
144
|
+
if (res.errors.length > 0) {
|
|
145
|
+
for (const e of res.errors)
|
|
146
|
+
ctx.out.error(`Hata: ${e}`);
|
|
147
|
+
ctx.out.result({ ...base, diffs: res.diffs, errors: res.errors, installed: false });
|
|
148
|
+
return 1;
|
|
149
|
+
}
|
|
150
|
+
ctx.out.info(ctx.out.paint('green', `✓ Kuruldu: modül ${slug} ${p.manifest.module.version} (${pendingChanges(res.diffs).length} kaynak). Sonraki değişiklikler için \`enformik schema push\` kullanın.`));
|
|
151
|
+
ctx.out.result({ ...base, moduleId: res.moduleId, diffs: res.diffs, errors: [], installed: true });
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
package/dist/schema.js
CHANGED
|
@@ -110,6 +110,33 @@ export class SchemaClient {
|
|
|
110
110
|
const j = res.json;
|
|
111
111
|
return { id: j.id, name: j.name, version: j.version };
|
|
112
112
|
}
|
|
113
|
+
/** slug → kurulu modül ya da null (404 module_not_found); diğer hatalar fırlatılır. */
|
|
114
|
+
async findModule(slug) {
|
|
115
|
+
try {
|
|
116
|
+
return await this.resolveModule(slug);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
if (e instanceof CliError && e.code === 'module_not_found')
|
|
120
|
+
return null;
|
|
121
|
+
throw e;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Modülün İLK kurulumu (POST /api/modules/install, module.install yetkisi). dryRun: yalnızca fark, kurmaz. */
|
|
125
|
+
async install(manifestJson, opts) {
|
|
126
|
+
const q = [opts.dryRun ? 'dry_run=true' : '', opts.seedData ? 'seed_data=true' : ''].filter(Boolean).join('&');
|
|
127
|
+
// Kurulum tekrar edilmemeli (yeniden denemede 409 module_exists dönerdi); yalnızca kuru çalıştırma yeniden denenebilir.
|
|
128
|
+
const res = await request(joinUrl(this.o.appUrl, `/api/modules/install${q ? `?${q}` : ''}`), {
|
|
129
|
+
method: 'POST', headers: this.headers({ 'Content-Type': 'application/json' }), body: manifestJson,
|
|
130
|
+
retries: opts.dryRun ? 1 : 0, timeoutMs: 300_000, fetchImpl: this.o.fetchImpl,
|
|
131
|
+
});
|
|
132
|
+
try {
|
|
133
|
+
ensureOk(res);
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
throw describeSchemaError(e, { install: true });
|
|
137
|
+
}
|
|
138
|
+
return normalizeDiff(res.json);
|
|
139
|
+
}
|
|
113
140
|
async diff(moduleId, manifestJson, opts) {
|
|
114
141
|
const res = await request(joinUrl(this.o.appUrl, `/api/modules/${moduleId}/diff${opts.seedData ? '?seed_data=true' : ''}`), {
|
|
115
142
|
method: 'POST', headers: this.headers({ 'Content-Type': 'application/json' }), body: manifestJson, retries: 1, timeoutMs: 120_000, fetchImpl: this.o.fetchImpl,
|
|
@@ -154,14 +181,18 @@ export function describeSchemaError(e, ctx) {
|
|
|
154
181
|
case 'breaking_change_blocked':
|
|
155
182
|
return new CliError(`${e.message}`, 1, e.code, e.body);
|
|
156
183
|
case 'module_not_found':
|
|
157
|
-
return new CliError(`"${ctx.slug ?? 'modül'}" slug'lı bir modül bu uygulamada kurulu değil.
|
|
184
|
+
return new CliError(`"${ctx.slug ?? 'modül'}" slug'lı bir modül bu uygulamada kurulu değil. İlk kurulumu \`enformik schema install\` ile ("Şema oluşturucu" rolündeki bir istemciyle) ya da bir yönetici yapar; sonraki yükseltmeleri \`schema push\` yapar.`, 1, e.code);
|
|
185
|
+
case 'module_exists':
|
|
186
|
+
return new CliError('Bu slug ile bir modül zaten kurulu. Var olanı yükseltmek için `enformik schema push` kullanın.', 1, e.code);
|
|
158
187
|
case 'payment_required':
|
|
159
188
|
return new CliError('Uygulamanın planı/ödeme durumu nedeniyle işlem engellendi (402). Konsoldan abonelik durumunu kontrol edin.', 1, e.code);
|
|
160
189
|
}
|
|
161
190
|
if (e.status === 401)
|
|
162
191
|
return new CliError('Kimlik reddedildi (401): belirteç geçersiz ya da istemci iptal edilmiş.', 1, 'unauthorized');
|
|
163
192
|
if (e.status === 403) {
|
|
164
|
-
return new CliError(
|
|
193
|
+
return new CliError((ctx.install
|
|
194
|
+
? 'Bu istemcinin rolü yeni modül kurmaya yetmiyor (403). Konsolda rolü "Şema oluşturucu" ya da "Yönetici" olan bir API istemcisi kullanın.'
|
|
195
|
+
: 'Bu istemcinin rolü modül yükseltmeye yetmiyor (403). Konsolda rolü "Şema yükseltici", "Şema oluşturucu" ya da "Yönetici" olan bir API istemcisi kullanın.') +
|
|
165
196
|
(body.required ? ` (gereken yetki: ${body.required})` : ''), 1, 'forbidden');
|
|
166
197
|
}
|
|
167
198
|
if (e.status === 404)
|