uvako-cli 0.2.1 → 0.4.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 +175 -125
- package/package.json +1 -1
- package/src/api.js +6 -5
- package/src/check.js +155 -63
- package/src/config.js +6 -5
- package/src/i18n.js +67 -0
- package/src/init.js +74 -17
- package/src/locales/en.js +226 -0
- package/src/main.js +15 -10
- package/src/package.js +3 -2
- package/src/remote.js +51 -50
- package/src/zip.js +5 -4
package/src/remote.js
CHANGED
|
@@ -5,6 +5,7 @@ import { printReport } from "./check.js";
|
|
|
5
5
|
import { dropSession, saveSession, session, sessions, storeOrigin } from "./config.js";
|
|
6
6
|
import { buildArchive } from "./package.js";
|
|
7
7
|
import { unzip } from "./zip.js";
|
|
8
|
+
import { t, tm } from "./i18n.js";
|
|
8
9
|
|
|
9
10
|
// Mağazayla konuşan komutlar: giriş, yükleme, canlı geliştirme, indirme, incelemeye gönderme.
|
|
10
11
|
|
|
@@ -35,7 +36,7 @@ function askSecret(question) {
|
|
|
35
36
|
const onData = (chunk) => {
|
|
36
37
|
for (const char of chunk) {
|
|
37
38
|
if (char === "\r" || char === "\n") return done(resolve, value.trim());
|
|
38
|
-
if (char === "\u0003") return done(reject, new Error("İptal edildi."));
|
|
39
|
+
if (char === "\u0003") return done(reject, new Error(t("İptal edildi.")));
|
|
39
40
|
if (char === "\u007f" || char === "\b") value = value.slice(0, -1);
|
|
40
41
|
else if (char >= " ") value += char;
|
|
41
42
|
}
|
|
@@ -46,9 +47,9 @@ function askSecret(question) {
|
|
|
46
47
|
|
|
47
48
|
function explain(error) {
|
|
48
49
|
if (!(error instanceof ApiError)) throw error;
|
|
49
|
-
console.error(`✖ ${error.message}`);
|
|
50
|
-
for (const problem of error.problems) console.error(` ✖ ${problem}`);
|
|
51
|
-
if (error.status === 401) console.error(" Yeni anahtar: mağaza paneli → Ayarlar → Temalar → Geliştirici erişimi, sonra `uvako login`.");
|
|
50
|
+
console.error(`✖ ${tm(error.message)}`);
|
|
51
|
+
for (const problem of error.problems) console.error(` ✖ ${tm(problem)}`);
|
|
52
|
+
if (error.status === 401) console.error(t(" Yeni anahtar: mağaza paneli → Ayarlar → Temalar → Geliştirici erişimi, sonra `uvako login`."));
|
|
52
53
|
return 1;
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -56,16 +57,16 @@ const previewUrl = (origin, installationId) => `${origin}/?preview=${installatio
|
|
|
56
57
|
const editorUrl = (origin, installationId) => `${origin}/admin/ayarlar/temalar/${installationId}/editor`;
|
|
57
58
|
|
|
58
59
|
export async function login(options) {
|
|
59
|
-
if (!options.store || options.store === true) throw new Error("Mağaza adresi gerekli: uvako login --store <mağaza>");
|
|
60
|
-
if (options.token) throw new Error("Erişim anahtarı komut satırına yazılmaz. Komutu --token olmadan çalıştırın; anahtar sorulacak (ya da UVAKO_TOKEN ortam değişkenini kullanın).");
|
|
60
|
+
if (!options.store || options.store === true) throw new Error(t("Mağaza adresi gerekli: uvako login --store <mağaza>"));
|
|
61
|
+
if (options.token) throw new Error(t("Erişim anahtarı komut satırına yazılmaz. Komutu --token olmadan çalıştırın; anahtar sorulacak (ya da UVAKO_TOKEN ortam değişkenini kullanın)."));
|
|
61
62
|
const origin = storeOrigin(options.store);
|
|
62
|
-
const token = (process.env.UVAKO_TOKEN || (await askSecret(
|
|
63
|
-
if (!/^uvt_[A-Za-z0-9_-]{20,}$/.test(token)) throw new Error("Bu bir tema erişim anahtarı değil (uvt_ ile başlar).");
|
|
63
|
+
const token = (process.env.UVAKO_TOKEN || (await askSecret(t("{0} için tema erişim anahtarı (panel → Ayarlar → Temalar → Geliştirici erişimi): ", origin)))).trim();
|
|
64
|
+
if (!/^uvt_[A-Za-z0-9_-]{20,}$/.test(token)) throw new Error(t("Bu bir tema erişim anahtarı değil (uvt_ ile başlar)."));
|
|
64
65
|
try {
|
|
65
66
|
const me = await call({ origin, token }, "GET", "/me");
|
|
66
67
|
saveSession(origin, token, me.store?.name ?? "");
|
|
67
|
-
console.log(
|
|
68
|
-
if (me.uploadBlocked) console.warn("! Bu mağaza için tema yükleme kapatılmış. Uvako desteğine yazın.");
|
|
68
|
+
console.log(t("Giriş yapıldı: {0} ({1})", me.store?.name ?? origin, origin));
|
|
69
|
+
if (me.uploadBlocked) console.warn(t("! Bu mağaza için tema yükleme kapatılmış. Uvako desteğine yazın."));
|
|
69
70
|
return 0;
|
|
70
71
|
} catch (error) {
|
|
71
72
|
return explain(error);
|
|
@@ -74,8 +75,8 @@ export async function login(options) {
|
|
|
74
75
|
|
|
75
76
|
export function logout(options) {
|
|
76
77
|
const origin = dropSession(typeof options.store === "string" ? options.store : "");
|
|
77
|
-
console.log(origin ?
|
|
78
|
-
console.log("Anahtarı tamamen geçersiz kılmak için mağaza panelinden iptal edin.");
|
|
78
|
+
console.log(origin ? t("Çıkış yapıldı: {0}", origin) : t("Kayıtlı giriş yok."));
|
|
79
|
+
console.log(t("Anahtarı tamamen geçersiz kılmak için mağaza panelinden iptal edin."));
|
|
79
80
|
return 0;
|
|
80
81
|
}
|
|
81
82
|
|
|
@@ -84,14 +85,14 @@ export async function whoami(options) {
|
|
|
84
85
|
const current = session(typeof options.store === "string" ? options.store : "");
|
|
85
86
|
const me = await call(current, "GET", "/me");
|
|
86
87
|
console.log(`${me.store?.name ?? ""} — ${current.origin} (anahtar: ${me.token})`);
|
|
87
|
-
for (const other of sessions()) if (!other.current) console.log(
|
|
88
|
+
for (const other of sessions()) if (!other.current) console.log(t(" diğer giriş: {0} — {1}", other.name || other.origin, other.origin));
|
|
88
89
|
return 0;
|
|
89
90
|
} catch (error) {
|
|
90
91
|
return explain(error);
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
const statusLabels = { private: "yalnızca bu mağazada", pending: "incelemede", approved: "tema mağazasında", rejected: "reddedildi" };
|
|
95
|
+
const statusLabels = { private: t("yalnızca bu mağazada"), pending: "incelemede", approved: t("tema mağazasında"), rejected: "reddedildi" };
|
|
95
96
|
|
|
96
97
|
export async function list(options) {
|
|
97
98
|
try {
|
|
@@ -101,11 +102,11 @@ export async function list(options) {
|
|
|
101
102
|
console.log(JSON.stringify(data, null, 2));
|
|
102
103
|
return 0;
|
|
103
104
|
}
|
|
104
|
-
console.log(
|
|
105
|
-
for (const item of data.installations) console.log(` ${item.role === "published" ? "● yayında " : "○ kütüphane"} ${item.name} [${item.key}]${item.custom ? " (paket)" : ""}`);
|
|
106
|
-
console.log(data.packages.length ? "\nYüklediğiniz paketler:" : "\nYüklediğiniz paket yok.");
|
|
105
|
+
console.log(t("Mağazadaki temalar ({0}):", current.origin));
|
|
106
|
+
for (const item of data.installations) console.log(` ${item.role === "published" ? t("● yayında ") : t("○ kütüphane")} ${item.name} [${item.key}]${item.custom ? " (paket)" : ""}`);
|
|
107
|
+
console.log(data.packages.length ? t("\nYüklediğiniz paketler:") : t("\nYüklediğiniz paket yok."));
|
|
107
108
|
for (const pkg of data.packages) {
|
|
108
|
-
console.log(` ${pkg.key} ${pkg.version} (temel: ${pkg.base}) ${statusLabels[pkg.status] ?? pkg.status}${pkg.publishedVersion ?
|
|
109
|
+
console.log(` ${pkg.key} ${pkg.version} (temel: ${pkg.base}) ${statusLabels[pkg.status] ?? pkg.status}${pkg.publishedVersion ? t(" · mağazadaki sürüm {0}", pkg.publishedVersion) : ""}`);
|
|
109
110
|
if (pkg.status === "rejected" && pkg.reviewNote) console.log(` not: ${pkg.reviewNote}`);
|
|
110
111
|
}
|
|
111
112
|
return 0;
|
|
@@ -132,15 +133,15 @@ export async function push(target, options) {
|
|
|
132
133
|
const current = session(typeof options.store === "string" ? options.store : "");
|
|
133
134
|
const result = await upload(current, dir);
|
|
134
135
|
if (!result) {
|
|
135
|
-
console.error("Yüklenmedi: önce hataları düzeltin.");
|
|
136
|
+
console.error(t("Yüklenmedi: önce hataları düzeltin."));
|
|
136
137
|
return 1;
|
|
137
138
|
}
|
|
138
139
|
const pkg = result.package;
|
|
139
|
-
console.log(
|
|
140
|
-
console.log(
|
|
141
|
-
console.log(
|
|
142
|
-
console.log("Önizleme için tarayıcıda mağaza paneline giriş yapmış olmalısınız. Tema, panelden yayınlanana kadar vitrini değiştirmez.");
|
|
143
|
-
if (pkg.publishedVersion) console.log(
|
|
140
|
+
console.log(t("{0}: {1} {2} (sürüm no {3}) → {4}", result.created ? t("Yüklendi") : t("Güncellendi"), pkg.name, pkg.version, pkg.revision, current.origin));
|
|
141
|
+
console.log(t("Önizleme: {0}", previewUrl(current.origin, result.installationId)));
|
|
142
|
+
console.log(t("Düzenleme: {0}", editorUrl(current.origin, result.installationId)));
|
|
143
|
+
console.log(t("Önizleme için tarayıcıda mağaza paneline giriş yapmış olmalısınız. Tema, panelden yayınlanana kadar vitrini değiştirmez."));
|
|
144
|
+
if (pkg.publishedVersion) console.log(t("Tema mağazasındaki sürüm ({0}) değişmedi. Yeni sürümü incelemeye göndermek için: uvako theme submit {1}", pkg.publishedVersion, pkg.key));
|
|
144
145
|
return 0;
|
|
145
146
|
} catch (error) {
|
|
146
147
|
return explain(error);
|
|
@@ -167,18 +168,18 @@ export async function dev(target, options) {
|
|
|
167
168
|
first = await upload(current, dir);
|
|
168
169
|
} catch (error) {
|
|
169
170
|
if (error instanceof ApiError) return explain(error);
|
|
170
|
-
console.error(`✖ ${error.message}`);
|
|
171
|
+
console.error(`✖ ${tm(error.message)}`);
|
|
171
172
|
return 1;
|
|
172
173
|
}
|
|
173
174
|
if (!first) {
|
|
174
|
-
console.error("Başlatılamadı: önce hataları düzeltin.");
|
|
175
|
+
console.error(t("Başlatılamadı: önce hataları düzeltin."));
|
|
175
176
|
return 1;
|
|
176
177
|
}
|
|
177
|
-
console.log(
|
|
178
|
-
console.log(
|
|
179
|
-
console.log(
|
|
180
|
-
console.log("Önizleme için tarayıcıda mağaza paneline giriş yapın. Dosyaları kaydettikçe sayfa yenilenir. Durdurmak için Ctrl+C.\n");
|
|
181
|
-
console.log(options.keep ? "Durdurduğunuzda tema son hâliyle kütüphanede kalır (--keep)." : existed ? "Durdurduğunuzda mağazadaki paket geliştirme öncesindeki sürümüne döner. Kalıcı yüklemek için: uvako theme push" : "Durdurduğunuzda geliştirme kopyası mağazadan silinir. Kalıcı yüklemek için: uvako theme push");
|
|
178
|
+
console.log(t("\nCanlı geliştirme: {0} → {1}", first.package.name, current.origin));
|
|
179
|
+
console.log(t("Önizleme: {0}", previewUrl(current.origin, first.installationId)));
|
|
180
|
+
console.log(t("Düzenleme: {0}", editorUrl(current.origin, first.installationId)));
|
|
181
|
+
console.log(t("Önizleme için tarayıcıda mağaza paneline giriş yapın. Dosyaları kaydettikçe sayfa yenilenir. Durdurmak için Ctrl+C.\n"));
|
|
182
|
+
console.log(options.keep ? t("Durdurduğunuzda tema son hâliyle kütüphanede kalır (--keep).") : existed ? t("Durdurduğunuzda mağazadaki paket geliştirme öncesindeki sürümüne döner. Kalıcı yüklemek için: uvako theme push") : t("Durdurduğunuzda geliştirme kopyası mağazadan silinir. Kalıcı yüklemek için: uvako theme push"));
|
|
182
183
|
console.log("");
|
|
183
184
|
|
|
184
185
|
let timer = null;
|
|
@@ -193,15 +194,15 @@ export async function dev(target, options) {
|
|
|
193
194
|
running = true;
|
|
194
195
|
try {
|
|
195
196
|
const result = await upload(current, dir, true);
|
|
196
|
-
if (result) console.log(
|
|
197
|
-
else console.error(
|
|
197
|
+
if (result) console.log(t("[{0}] yüklendi (sürüm no {1})", stamp(), result.package.revision));
|
|
198
|
+
else console.error(t("[{0}] yüklenmedi: hataları düzeltip kaydedin.", stamp()));
|
|
198
199
|
} catch (error) {
|
|
199
200
|
if (error instanceof ApiError) {
|
|
200
|
-
console.error(`[${stamp()}] ✖ ${error.message}`);
|
|
201
|
-
for (const problem of error.problems) console.error(` ✖ ${problem}`);
|
|
201
|
+
console.error(`[${stamp()}] ✖ ${tm(error.message)}`);
|
|
202
|
+
for (const problem of error.problems) console.error(` ✖ ${tm(problem)}`);
|
|
202
203
|
if (error.status === 401 || error.status === 403) process.exit(1);
|
|
203
204
|
} else {
|
|
204
|
-
console.error(`[${stamp()}] ✖ ${error.message}`);
|
|
205
|
+
console.error(`[${stamp()}] ✖ ${tm(error.message)}`);
|
|
205
206
|
}
|
|
206
207
|
} finally {
|
|
207
208
|
running = false;
|
|
@@ -227,18 +228,18 @@ export async function dev(target, options) {
|
|
|
227
228
|
const key = first.package.key;
|
|
228
229
|
try {
|
|
229
230
|
if (options.keep) {
|
|
230
|
-
console.log("\nCanlı geliştirme durdu. Tema son hâliyle mağaza kütüphanesinde duruyor.");
|
|
231
|
+
console.log(t("\nCanlı geliştirme durdu. Tema son hâliyle mağaza kütüphanesinde duruyor."));
|
|
231
232
|
} else if (before) {
|
|
232
233
|
await call(current, "PUT", "/themes", { body: before });
|
|
233
|
-
console.log("\nCanlı geliştirme durdu. Mağazadaki paket geliştirme öncesindeki sürümüne döndü.");
|
|
234
|
+
console.log(t("\nCanlı geliştirme durdu. Mağazadaki paket geliştirme öncesindeki sürümüne döndü."));
|
|
234
235
|
} else {
|
|
235
236
|
await call(current, "DELETE", `/themes/${encodeURIComponent(key)}`);
|
|
236
|
-
console.log("\nCanlı geliştirme durdu. Geliştirme kopyası mağazadan silindi; vitrin ve kütüphane eski hâlinde.");
|
|
237
|
+
console.log(t("\nCanlı geliştirme durdu. Geliştirme kopyası mağazadan silindi; vitrin ve kütüphane eski hâlinde."));
|
|
237
238
|
}
|
|
238
239
|
resolve(0);
|
|
239
240
|
} catch (error) {
|
|
240
|
-
console.error(
|
|
241
|
-
console.error(
|
|
241
|
+
console.error(t("\nCanlı geliştirme durdu ama mağaza eski hâline döndürülemedi: {0}", error.message));
|
|
242
|
+
console.error(t("Elle kaldırmak için: uvako theme delete {0} --yes", key));
|
|
242
243
|
resolve(1);
|
|
243
244
|
}
|
|
244
245
|
});
|
|
@@ -246,10 +247,10 @@ export async function dev(target, options) {
|
|
|
246
247
|
}
|
|
247
248
|
|
|
248
249
|
export async function pull(key, options) {
|
|
249
|
-
if (!key) throw new Error("Tema anahtarı gerekli: uvako theme pull <anahtar>");
|
|
250
|
+
if (!key) throw new Error(t("Tema anahtarı gerekli: uvako theme pull <anahtar>"));
|
|
250
251
|
const parent = path.resolve(typeof options.dir === "string" ? options.dir : ".");
|
|
251
252
|
const dir = path.join(parent, key);
|
|
252
|
-
if (existsSync(dir) && !options.force) throw new Error(
|
|
253
|
+
if (existsSync(dir) && !options.force) throw new Error(t("Klasör zaten var: {0}\nÜstüne yazmak için --force ekleyin.", dir));
|
|
253
254
|
try {
|
|
254
255
|
const current = session(typeof options.store === "string" ? options.store : "");
|
|
255
256
|
const archive = await call(current, "GET", `/themes/${encodeURIComponent(key)}/package`, { raw: true });
|
|
@@ -258,12 +259,12 @@ export async function pull(key, options) {
|
|
|
258
259
|
// Paket yalnızca kendi klasörünün içine açılır.
|
|
259
260
|
const rel = entry.name.split("/").slice(1).join("/");
|
|
260
261
|
const file = path.resolve(dir, rel);
|
|
261
|
-
if (!rel || !entry.name.startsWith(`${key}/`) || rel.split("/").includes("..") || !file.startsWith(dir + path.sep)) throw new Error(
|
|
262
|
+
if (!rel || !entry.name.startsWith(`${key}/`) || rel.split("/").includes("..") || !file.startsWith(dir + path.sep)) throw new Error(t("Paketteki yol güvenli değil: {0}", entry.name));
|
|
262
263
|
mkdirSync(path.dirname(file), { recursive: true });
|
|
263
264
|
writeFileSync(file, entry.data);
|
|
264
265
|
count++;
|
|
265
266
|
}
|
|
266
|
-
console.log(
|
|
267
|
+
console.log(t("İndirildi: {0} ({1} dosya)", path.relative(process.cwd(), dir) || ".", count));
|
|
267
268
|
return 0;
|
|
268
269
|
} catch (error) {
|
|
269
270
|
return explain(error);
|
|
@@ -271,12 +272,12 @@ export async function pull(key, options) {
|
|
|
271
272
|
}
|
|
272
273
|
|
|
273
274
|
export async function submit(key, options) {
|
|
274
|
-
if (!key) throw new Error("Tema anahtarı gerekli: uvako theme submit <anahtar>");
|
|
275
|
+
if (!key) throw new Error(t("Tema anahtarı gerekli: uvako theme submit <anahtar>"));
|
|
275
276
|
try {
|
|
276
277
|
const current = session(typeof options.store === "string" ? options.store : "");
|
|
277
278
|
const pkg = await call(current, "POST", `/themes/${encodeURIComponent(key)}/submit`);
|
|
278
|
-
console.log(
|
|
279
|
-
console.log("İnceleme sürerken yeni sürüm yüklerseniz onay o sürüm için yeniden istenir.");
|
|
279
|
+
console.log(t("İncelemeye gönderildi: {0} {1}. Uvako ekibi onayladığında themes.uvako.com'da yayınlanır.", pkg.name, pkg.version));
|
|
280
|
+
console.log(t("İnceleme sürerken yeni sürüm yüklerseniz onay o sürüm için yeniden istenir."));
|
|
280
281
|
return 0;
|
|
281
282
|
} catch (error) {
|
|
282
283
|
return explain(error);
|
|
@@ -284,8 +285,8 @@ export async function submit(key, options) {
|
|
|
284
285
|
}
|
|
285
286
|
|
|
286
287
|
export async function remove(key, options) {
|
|
287
|
-
if (!key) throw new Error("Tema anahtarı gerekli: uvako theme delete <anahtar>");
|
|
288
|
-
if (!options.yes) throw new Error(
|
|
288
|
+
if (!key) throw new Error(t("Tema anahtarı gerekli: uvako theme delete <anahtar>"));
|
|
289
|
+
if (!options.yes) throw new Error(t("\"{0}\" paketi ve mağazadaki kopyaları silinir; geri alınamaz. Onaylamak için --yes ekleyin.", key));
|
|
289
290
|
try {
|
|
290
291
|
const current = session(typeof options.store === "string" ? options.store : "");
|
|
291
292
|
await call(current, "DELETE", `/themes/${encodeURIComponent(key)}`);
|
package/src/zip.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import zlib from "node:zlib";
|
|
2
|
+
import { t } from "./i18n.js";
|
|
2
3
|
|
|
3
4
|
// Bağımlılıksız zip yazıcı ve okuyucu. Dosya tarihleri sabit tutulur; aynı içerik her zaman aynı
|
|
4
5
|
// özeti verir.
|
|
@@ -62,12 +63,12 @@ export function unzip(buffer) {
|
|
|
62
63
|
break;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
|
-
if (end < 0) throw new Error("Geçerli bir zip dosyası değil.");
|
|
66
|
+
if (end < 0) throw new Error(t("Geçerli bir zip dosyası değil."));
|
|
66
67
|
const count = buffer.readUInt16LE(end + 10);
|
|
67
68
|
let cursor = buffer.readUInt32LE(end + 16);
|
|
68
69
|
const entries = [];
|
|
69
70
|
for (let i = 0; i < count; i++) {
|
|
70
|
-
if (buffer.readUInt32LE(cursor) !== 0x02014b50) throw new Error("Zip dizini okunamadı.");
|
|
71
|
+
if (buffer.readUInt32LE(cursor) !== 0x02014b50) throw new Error(t("Zip dizini okunamadı."));
|
|
71
72
|
const method = buffer.readUInt16LE(cursor + 10);
|
|
72
73
|
const compressedSize = buffer.readUInt32LE(cursor + 20);
|
|
73
74
|
const size = buffer.readUInt32LE(cursor + 24);
|
|
@@ -78,13 +79,13 @@ export function unzip(buffer) {
|
|
|
78
79
|
const name = buffer.subarray(cursor + 46, cursor + 46 + nameLength).toString("utf8");
|
|
79
80
|
cursor += 46 + nameLength + extraLength + commentLength;
|
|
80
81
|
if (name.endsWith("/")) continue;
|
|
81
|
-
if (size > maxEntryBytes) throw new Error(
|
|
82
|
+
if (size > maxEntryBytes) throw new Error(t("{0}: dosya çok büyük.", name));
|
|
82
83
|
const dataStart = localOffset + 30 + buffer.readUInt16LE(localOffset + 26) + buffer.readUInt16LE(localOffset + 28);
|
|
83
84
|
const raw = buffer.subarray(dataStart, dataStart + compressedSize);
|
|
84
85
|
let data;
|
|
85
86
|
if (method === 0) data = Buffer.from(raw);
|
|
86
87
|
else if (method === 8) data = zlib.inflateRawSync(raw, { maxOutputLength: maxEntryBytes });
|
|
87
|
-
else throw new Error(
|
|
88
|
+
else throw new Error(t("{0}: desteklenmeyen sıkıştırma yöntemi.", name));
|
|
88
89
|
entries.push({ name, data });
|
|
89
90
|
}
|
|
90
91
|
return entries;
|