@enformik/cli 0.1.0 → 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 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) rolünde bir **API istemcisi** (konsol → uygulamanın "API erişimi" bölümü) ve uygulamada kurulu bir modül. Modülün **ilk kurulumunu** bir yönetici yapar; sonraki yükseltmeler bu CLI ile yapılır.
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" rolü 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
+ "Ş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
@@ -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 uygulamanızın "API erişimi" bölümünden rolü "Şema yükseltici" olan bir istemci oluşturun).');
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. Modülün ilk kurulumunu (içe aktarma) bir yönetici bir kez yapmalıdır; sonraki yükseltmeleri bu CLI yapar.`, 1, e.code);
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('Bu istemcinin rolü modül yükseltmeye yetmiyor (403). Konsolda rolü "Şema yükseltici" ya da "Yönetici" olan bir API istemcisi kullanın.' +
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enformik/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Enformik geliştirici CLI'si: web sitesi dağıtımı ve uygulama modülü (şema) yükseltme.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",