tsoft-cli 1.3.0 → 1.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.
@@ -0,0 +1,280 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const chokidar = require('chokidar');
4
+ const readline = require('readline');
5
+ const { exec } = require('child_process');
6
+ const Tsoft = require('../Tsoft');
7
+ const Constants = require('../core/Constants');
8
+ const cliProgress = require('cli-progress');
9
+ const { Input } = require('enquirer');
10
+ const { displayAsciiArt, info, unzipFile } = require('../core/Utils');
11
+
12
+ class StartCommand {
13
+ static async showProgress(tsoft, theme) {
14
+ const themePath = path.join(process.cwd(), tsoft.site, theme);
15
+ const fileList = tsoft.fileManager.listFilesRecursive(themePath).filter(file => !file.includes('.env'));
16
+ const totalFiles = fileList.length;
17
+
18
+ const progressBar = new cliProgress.SingleBar({
19
+ format: 'İlerleme |{bar}| {percentage}% || {value}/{total} Dosya Yüklendi',
20
+ barCompleteChar: '\u2588',
21
+ barIncompleteChar: '\u2591',
22
+ hideCursor: true,
23
+ clearOnComplete: true
24
+ });
25
+ progressBar.start(totalFiles, 0);
26
+
27
+ for (let i = 0; i < totalFiles; i++) {
28
+ const file = fileList[i];
29
+ const fileName = tsoft.fileManager.getRelativePath(theme, file);
30
+ const content = tsoft.fileManager.readFile(file);
31
+ const env = tsoft.themeManager.getEnvironment(theme);
32
+
33
+ try {
34
+ await tsoft.saveFile(theme, fileName, content, env.bearer);
35
+ } catch (error) {
36
+ console.error(`Dosya yükleme hatası ${fileName}:`, error);
37
+ }
38
+ progressBar.update(i + 1);
39
+ }
40
+
41
+ progressBar.stop();
42
+
43
+ return 'Tüm dosyalar ilerleme ile başarıyla yüklendi';
44
+ }
45
+
46
+ static async initializeAndAuthorize(tsoft, themeName) {
47
+ await tsoft.initialize(themeName);
48
+
49
+ const approvalPrompt = new Input({
50
+ name: 'approval',
51
+ message: 'Lütfen onay kodunu sağlayın:'
52
+ });
53
+
54
+ const approval = await approvalPrompt.run();
55
+
56
+ if (approval) {
57
+ await Constants.APPROVAL.handler(tsoft.clientCredentials.setClientSecret(approval));
58
+ tsoft.buildEnvironment();
59
+ console.info('Ortam dosyası başarıyla oluşturuldu.');
60
+ return true;
61
+ } else {
62
+ console.error('Onay kodu gerekli.');
63
+ return false;
64
+ }
65
+ }
66
+
67
+ static async handleExistingEnvironment(tsoft, themeName, themeEnvPath) {
68
+ let envData = {};
69
+ if (fs.existsSync(themeEnvPath)) {
70
+ try {
71
+ envData = JSON.parse(fs.readFileSync(themeEnvPath, 'utf-8'));
72
+ } catch (error) {
73
+ console.warn(`${themeEnvPath} dosyasında geçersiz JSON formatı. Bu dosya silinecek ve yeniden yetkilendirmeniz gerekecek.`);
74
+ fs.unlinkSync(themeEnvPath);
75
+ console.info('Geçersiz ortam dosyası silindi. Başlatma işlemine devam ediliyor...');
76
+ }
77
+
78
+ if (envData.bearer) {
79
+ const bearerTokenValid = await tsoft.isTokenValid(themeName);
80
+
81
+ if (bearerTokenValid) {
82
+ console.info('Geçerli bir taşıyıcı jetonuna sahip mevcut ortam dosyası bulundu. Mevcut yapılandırma ile devam ediliyor...');
83
+ return true;
84
+ } else {
85
+ console.warn('Mevcut taşıyıcı jetonu geçersiz. Yeniden yetkilendirmeniz gerekecek.');
86
+ fs.unlinkSync(themeEnvPath);
87
+ }
88
+ }
89
+ }
90
+ return false;
91
+ }
92
+
93
+ static async startWatching(themePath, tsoft, theme) {
94
+ const watcher = chokidar.watch(themePath, {
95
+ ignored: /(^|[\/\\])(\.theme|(.*?)\.env)$/, // .theme ve .env dosyaları yoksayılır
96
+ persistent: true
97
+ });
98
+
99
+ watcher.on('change', async (filePath) => {
100
+ console.log(`Dosya değiştirildi ${filePath}`);
101
+ await StartCommand.handleFileChange(filePath, tsoft, theme);
102
+ }).on('unlink', async (filePath) => {
103
+ console.log(`Dosya silindi ${filePath}`);
104
+ await StartCommand.handleFileDeletion(filePath, tsoft, theme);
105
+ }).on('unlinkDir', async (dirPath) => {
106
+ console.log(`Dizin silindi ${dirPath}`);
107
+ await StartCommand.handleDirectoryDeletion(dirPath, tsoft, theme);
108
+ });
109
+
110
+ console.log(`${themePath} dizinindeki dosya değişiklikleri izleniyor`);
111
+
112
+ const rl = readline.createInterface({
113
+ input: process.stdin,
114
+ output: process.stdout
115
+ });
116
+
117
+ info();
118
+
119
+ rl.on('line', async (input) => {
120
+ await StartCommand.handleUserInput(input, tsoft, theme, watcher, rl);
121
+ });
122
+ }
123
+
124
+ static async handleFileChange(filePath, tsoft, theme) {
125
+ const env = JSON.parse(fs.readFileSync(path.join(process.cwd(), tsoft.site, theme, `${theme}.env`), 'utf-8'));
126
+ const fileName = filePath.replace(`${path.join(process.cwd(), tsoft.site, theme)}/`, '');
127
+ const content = fs.readFileSync(filePath).toString();
128
+
129
+ try {
130
+ await tsoft.saveFile(theme, fileName, content, env.bearer);
131
+ console.log(`Dosya başarıyla yüklendi ${fileName}`);
132
+ } catch (error) {
133
+ console.error(`Dosya yükleme hatası ${fileName}:`, error);
134
+ }
135
+ }
136
+
137
+ static async handleFileDeletion(filePath, tsoft, theme) {
138
+ const env = JSON.parse(fs.readFileSync(path.join(process.cwd(), tsoft.site, theme, `${theme}.env`), 'utf-8'));
139
+ const fileName = filePath.replace(`${path.join(process.cwd(), tsoft.site, theme)}/`, '');
140
+
141
+ try {
142
+ await tsoft.deleteFile(theme, fileName, env.bearer);
143
+ console.log(`Dosya başarıyla silindi ${fileName}`);
144
+ } catch (error) {
145
+ console.error(`Dosya silme hatası ${fileName}:`, error);
146
+ }
147
+ }
148
+
149
+ static async handleDirectoryDeletion(dirPath, tsoft, theme) {
150
+ const env = JSON.parse(fs.readFileSync(path.join(process.cwd(), tsoft.site, theme, `${theme}.env`), 'utf-8'));
151
+ const dirName = dirPath.replace(`${path.join(process.cwd(), tsoft.site, theme)}/`, '');
152
+
153
+ try {
154
+ await tsoft.deleteDirectory(theme, dirName, env.bearer);
155
+ console.log(`Dizin başarıyla silindi ${dirName}`);
156
+ } catch (error) {
157
+ console.error(`Dizin silme hatası ${dirName}:`, error);
158
+ }
159
+ }
160
+
161
+ static async handleUserInput(input, tsoft, theme, watcher, rl) {
162
+ info();
163
+ switch (input.trim()) {
164
+ case 'q':
165
+ console.log('Dosya izleme işlemi sonlandırılıyor...');
166
+ watcher.close();
167
+ rl.close();
168
+ process.exit(0);
169
+ break;
170
+ case 'u':
171
+ console.log('Tema güncelleniyor...');
172
+ try {
173
+ const result = await StartCommand.updateTheme(tsoft, theme);
174
+ console.log(result);
175
+
176
+ } catch (error) {
177
+ console.error(`Tema güncelleme hatası:`, error);
178
+ }
179
+ break;
180
+ case 's':
181
+ console.log('Tüm dosyalar ilerleme ile yüklenmeye başlanıyor...');
182
+ try {
183
+ const result = await StartCommand.showProgress(tsoft, theme);
184
+ console.log(result);
185
+
186
+ } catch (error) {
187
+ console.error(`İlerleme gösterim hatası:`, error);
188
+ }
189
+ break;
190
+ case 'e':
191
+ console.log('.theme dosyası düzenleniyor...');
192
+ try {
193
+ await StartCommand.editThemeFile(tsoft.themeManager, theme);
194
+ } catch (error) {
195
+ console.error(`.theme dosyası düzenleme hatası:`, error);
196
+ }
197
+ break;
198
+ case 'o':
199
+ console.log('Tema dizini açılıyor...');
200
+ const openCommand = process.platform === 'win32' ? 'start' :
201
+ process.platform === 'darwin' ? 'open' :
202
+ 'xdg-open';
203
+ exec(`${openCommand} ${path.join(process.cwd(), tsoft.site, theme)}`, (err) => {
204
+ if (err) {
205
+ console.error('Tema dizini açılamadı:', err);
206
+ } else {
207
+ console.log('Tema dizini başarıyla açıldı.');
208
+ }
209
+ });
210
+ break;
211
+ }
212
+ }
213
+
214
+ static async start(siteName, themeName, recentlyCreated = false) {
215
+ await displayAsciiArt();
216
+ console.log('Geliştirme ortamı aşağıdaki ayrıntılarla başlatılıyor:');
217
+ console.log(`Site Adı: ${siteName}`);
218
+ console.log(`Tema Adı: ${themeName}`);
219
+
220
+ const tsoft = new Tsoft(siteName);
221
+ const themeEnvPath = path.join(process.cwd(), siteName, themeName, `${themeName}.env`);
222
+
223
+ const existingEnvValid = await StartCommand.handleExistingEnvironment(tsoft, themeName, themeEnvPath);
224
+ if (existingEnvValid) {
225
+ await StartCommand.startWatching(path.join(process.cwd(), siteName, themeName), tsoft, themeName);
226
+ return;
227
+ }
228
+
229
+ const initializedAndAuthorized = await StartCommand.initializeAndAuthorize(tsoft, themeName);
230
+ if (initializedAndAuthorized) {
231
+ if(recentlyCreated) {
232
+ const defaultZipFile = path.join(process.cwd(), siteName, themeName, 'theme.zip');
233
+ console.log('Default tema dosyaları indirme işlemi başlatılıyor, lütfen bekleyin');
234
+ const themePath = path.join(process.cwd(), siteName, themeName);
235
+ await tsoft.fileManager.downloadAndSaveZip(
236
+ themePath, defaultZipFile,
237
+ tsoft.clientCredentials.bearer,
238
+ 'default'
239
+ );
240
+ console.log('Default tema dosyaları indirildi. Çıkarma işlemi başlatılıyor');
241
+ await unzipFile(defaultZipFile, themePath);
242
+ console.log('Çıkarma işlemi tamamlandı.');
243
+ fs.unlinkSync(defaultZipFile);
244
+ }
245
+
246
+ await StartCommand.startWatching(path.join(process.cwd(), siteName, themeName), tsoft, themeName);
247
+ }
248
+ }
249
+
250
+ static async updateTheme(tsoft, theme) {
251
+ const directoryName = path.basename(path.join(process.cwd(), tsoft.site, theme));
252
+ const response = await tsoft.updateTheme(directoryName);
253
+ if (response.status === true) {
254
+ return 'Successfully updated';
255
+ } else {
256
+ throw new Error('Update failed');
257
+ }
258
+ }
259
+
260
+ static async editThemeFile(themeManager, directoryName) {
261
+ const themePath = path.join(process.cwd(), themeManager.site, directoryName, '.theme');
262
+ if (!fs.existsSync(themePath)) {
263
+ console.error('.theme file not found.');
264
+ return;
265
+ }
266
+ console.log(`Opening .theme file: ${themePath}`);
267
+ const openCommand = process.platform === 'win32' ? 'start' :
268
+ process.platform === 'darwin' ? 'open' :
269
+ 'xdg-open';
270
+ exec(`${openCommand} ${themePath}`, (err) => {
271
+ if (err) {
272
+ console.error('Failed to open .theme file:', err);
273
+ } else {
274
+ console.log('.theme file opened successfully.');
275
+ }
276
+ });
277
+ }
278
+ }
279
+
280
+ module.exports = StartCommand;
@@ -0,0 +1,97 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { Input } = require('enquirer');
4
+ const { clearScreen } = require('../core/Utils');
5
+ const { selectSite, createThemeDirectory } = require('./CreateCommand');
6
+ const StartCommand = require('./StartCommand');
7
+ const Tsoft = require("../Tsoft");
8
+ const { slugify, unzipFile } = require('../core/Utils');
9
+
10
+ class SyncCommand {
11
+ static async syncTheme() {
12
+ const cwd = process.cwd();
13
+ const sites = fs.readdirSync(cwd).filter(file => {
14
+ return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
15
+ }).filter(file => fs.statSync(path.join(cwd, file)).isDirectory());
16
+
17
+ const selectedSite = await selectSite(sites);
18
+
19
+ const tsoft = new Tsoft(selectedSite);
20
+
21
+ let recoveryCode;
22
+ let recoveryData;
23
+ while (!recoveryData) {
24
+ const codePrompt = new Input({
25
+ name: 'code',
26
+ message: 'Lütfen kurtarma anahtarını girin:'
27
+ });
28
+
29
+ recoveryCode = await codePrompt.run();
30
+
31
+ try {
32
+ recoveryData = await tsoft.startRecovery(recoveryCode);
33
+ } catch (error) {
34
+ if (error.message.includes('Çok fazla deneme yapıldı')) {
35
+ console.error(`Hata: ${error.message}`);
36
+ return;
37
+ } else {
38
+ console.error(`Hata: ${error.message}`);
39
+ continue;
40
+ }
41
+ }
42
+
43
+ if (!recoveryData) {
44
+ console.error('Kurtarma işlemi başarısız oldu. Lütfen geçerli bir kurtarma anahtarı girin.');
45
+ }
46
+ }
47
+
48
+ const { secret, public_key } = recoveryData;
49
+
50
+ tsoft.clientCredentials.setClientSecret(secret).setClientId(public_key);
51
+ const authorizeResponse = await tsoft.clientCredentials.authorize(true);
52
+ const themeInformation = authorizeResponse.data.tokenable;
53
+
54
+ const themeName = themeInformation.name;
55
+ const themeNameSlug = slugify(themeName);
56
+ const themePath = await createThemeDirectory(selectedSite, themeNameSlug);
57
+
58
+ const themeData = {
59
+ site: selectedSite,
60
+ name: themeName,
61
+ author: themeInformation.author,
62
+ version: themeInformation.version
63
+ };
64
+
65
+ fs.writeFileSync(path.join(themePath, '.theme'), JSON.stringify(themeData, null, 2));
66
+ tsoft.themeManager.setTheme(themeNameSlug);
67
+
68
+ if (!fs.existsSync(themePath)) {
69
+ fs.mkdirSync(themePath, { recursive: true });
70
+ }
71
+
72
+ clearScreen();
73
+
74
+ const zipFilePath = path.join(themePath, 'theme.zip');
75
+
76
+ try {
77
+ console.log('Zip dosyası indiriliyor...');
78
+ await tsoft.fileManager.downloadAndSaveZip(themePath, zipFilePath, tsoft.clientCredentials.bearer);
79
+ console.log('İndirme tamamlandı.');
80
+
81
+ console.log('Dosyalar çıkarılıyor...');
82
+ await unzipFile(zipFilePath, themePath);
83
+ console.log('Çıkarma işlemi tamamlandı.');
84
+ fs.unlinkSync(zipFilePath);
85
+ } catch (error) {
86
+ console.error(`Zip dosyası ile ilgili bir hata oluştu: ${error.message}`);
87
+ return;
88
+ }
89
+
90
+ tsoft.buildEnvironment();
91
+
92
+ // Geliştirme ortamını başlat
93
+ await StartCommand.start(selectedSite, themeNameSlug);
94
+ }
95
+ }
96
+
97
+ module.exports = SyncCommand;
@@ -1,27 +1,16 @@
1
- const {buildPostRequest} = require('./request');
1
+ const {buildPostRequest} = require('./Request');
2
2
 
3
3
  class ClientCredentials {
4
- site;
5
- clientId;
6
- clientSecret;
7
- bearer;
8
-
9
4
  constructor(site) {
10
5
  this.site = site;
6
+ this.clientId = null;
7
+ this.clientSecret = null;
8
+ this.bearer = null;
11
9
  }
12
10
 
13
- getEnvironment() {
14
- return {
15
- site: this.site, clientId: this.clientId, clientSecret: this.clientSecret, bearer: this.bearer
16
- }
17
- }
18
-
19
- set clientId(clientId) {
11
+ setClientId(clientId) {
20
12
  this.clientId = clientId;
21
- }
22
-
23
- get clientId() {
24
- return this.clientId;
13
+ return this;
25
14
  }
26
15
 
27
16
  setClientSecret(clientSecret) {
@@ -29,19 +18,25 @@ class ClientCredentials {
29
18
  return this;
30
19
  }
31
20
 
32
- setClientId(clientId) {
33
- this.clientId = clientId;
34
- return this;
21
+ getEnvironment() {
22
+ return {
23
+ site: this.site,
24
+ clientId: this.clientId,
25
+ clientSecret: this.clientSecret,
26
+ bearer: this.bearer
27
+ };
35
28
  }
36
29
 
37
30
  async register(CLIENT_UUID, clientConfiguration = {}) {
38
-
39
31
  const uri = "api/v3/admin/auth/auth-application";
40
- const result = await this.buildPostRequest(uri, {
41
- header: {
42
- 'Content-Type': 'application/json', 'Accept': 'application/json',
43
- }, body: JSON.stringify({
44
- uuid: CLIENT_UUID, configuration: {
32
+ const result = await buildPostRequest(this.site, uri, {
33
+ headers: {
34
+ 'Content-Type': 'application/json',
35
+ 'Accept': 'application/json'
36
+ },
37
+ body: JSON.stringify({
38
+ uuid: CLIENT_UUID,
39
+ configuration: {
45
40
  name: clientConfiguration.name,
46
41
  author: clientConfiguration.author,
47
42
  version: clientConfiguration.version
@@ -51,22 +46,26 @@ class ClientCredentials {
51
46
 
52
47
  if (result.status === true) {
53
48
  this.clientId = result.data.public_key;
49
+ return true;
54
50
  } else {
55
51
  return false;
56
52
  }
57
-
58
- return true;
59
53
  }
60
54
 
61
55
  async authorize() {
62
56
  const uri = "api/v3/admin/auth/auth-application/authorize";
63
- return await this.buildPostRequest(uri, {
57
+ return await buildPostRequest(this.site, uri, {
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ 'Accept': 'application/json'
61
+ },
64
62
  body: JSON.stringify({
65
- public_key: this.clientId, secret: this.clientSecret
63
+ public_key: this.clientId,
64
+ secret: this.clientSecret
66
65
  })
67
66
  }).then((result) => {
68
67
  if (result.status === true) {
69
- this.bearer = result.data.token.plainTextToken
68
+ this.bearer = result.data.token.plainTextToken;
70
69
  return result;
71
70
  }
72
71
  return false;
@@ -74,39 +73,35 @@ class ClientCredentials {
74
73
  console.error('Hata:', error.message);
75
74
  return false;
76
75
  });
77
-
78
- }
79
-
80
-
81
- async buildPostRequest(uri, options = {}) {
82
- return buildPostRequest(this.site, uri, options);
83
76
  }
84
77
 
85
78
  async validateToken(token) {
86
79
  const uri = 'api/v3/admin/auth/me';
87
80
  const response = await buildPostRequest(this.site, uri, {
81
+ headers: {
82
+ Authorization: `Bearer ${token}`
83
+ },
88
84
  body: JSON.stringify({
89
85
  _method: 'GET'
90
- }), headers: {
91
- Authorization: `Bearer ${token}`
92
- }
86
+ })
93
87
  });
94
88
  return response.message === 'ok';
95
89
  }
96
90
 
97
91
  async recovery(token) {
98
- const uri = 'api/v3/admin/auth/auth-application/recovery/' + token;
99
-
92
+ const uri = `api/v3/admin/auth/auth-application/recovery/${token}`;
100
93
  const response = await buildPostRequest(this.site, uri);
101
-
102
94
  if (response.status) {
103
95
  return {
104
96
  secret: response.data.secret,
105
97
  public_key: response.data.public_key
106
- }
98
+ };
99
+ } else if (response?.throttle) {
100
+ const {limit, retryAfter, resetDate} = response.throttle;
101
+ throw new Error(`Çok fazla deneme yapıldı. Lütfen ${retryAfter} saniye sonra tekrar deneyin. Limit: ${limit}, Reset Zamanı: ${resetDate}`);
107
102
  }
108
-
103
+ return null;
109
104
  }
110
105
  }
111
106
 
112
- module.exports = ClientCredentials;
107
+ module.exports = ClientCredentials;
@@ -1,7 +1,8 @@
1
1
  const handleAuthorization = async (credentialHandler) => {
2
2
  await credentialHandler.authorize();
3
3
  };
4
- module.exports = Object.freeze({
4
+
5
+ const Constants = Object.freeze({
5
6
  INITIALIZE: {
6
7
  type: 'input',
7
8
  name: 'site',
@@ -13,4 +14,6 @@ module.exports = Object.freeze({
13
14
  message: 'Parolanızı giriniz (Lütfen panelden onaylayınız):',
14
15
  handler: handleAuthorization
15
16
  }
16
- });
17
+ });
18
+
19
+ module.exports = Constants;
@@ -1,8 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const utils = require('./utils');
4
- const { exec } = require('child_process');
5
- const {buildDownloadZipRequest} = require('./request');
3
+ const Utils = require('./Utils');
4
+ const { buildDownloadZipRequest } = require('./Request');
6
5
 
7
6
  class FileManager {
8
7
  constructor(site) {
@@ -34,11 +33,10 @@ class FileManager {
34
33
 
35
34
  isAllowedExtension(file) {
36
35
  const ext = path.extname(file).substring(1);
37
- return utils.allowedExtensions.includes(ext);
36
+ return Utils.allowedExtensions.includes(ext);
38
37
  }
39
38
 
40
39
  async downloadAndSaveZip(saveToDir, zipFilePath, bearerToken, type = 'none') {
41
- // Fetch the zip file and save it
42
40
  const response = await buildDownloadZipRequest(this.site, `api/v3/admin/online-store-2/theme/download-theme?type=${type}`, {
43
41
  headers: {
44
42
  'Content-Type': 'application/zip',
@@ -47,23 +45,8 @@ class FileManager {
47
45
  }
48
46
  });
49
47
 
50
-
51
48
  fs.writeFileSync(zipFilePath, Buffer.from(response));
52
-
53
49
  console.log(`Zip dosyası ${zipFilePath} konumuna kaydedildi.`);
54
-
55
- // Open the directory in file explorer
56
- const openCommand = process.platform === 'win32' ? 'start' :
57
- process.platform === 'darwin' ? 'open' :
58
- 'xdg-open';
59
- exec(`${openCommand} ${saveToDir}`, (err) => {
60
- if (err) {
61
- console.error('Dizin açılamadı:', err);
62
- } else {
63
- console.log(`Dizin açıldı: ${saveToDir}`);
64
- console.log('Lütfen zip dosyasını bu dizine çıkartın.');
65
- }
66
- });
67
50
  }
68
51
  }
69
52
 
@@ -0,0 +1,41 @@
1
+ class Request {
2
+ static async buildPostRequest(site, uri, options = {}) {
3
+ const fetch = (await import('node-fetch')).default;
4
+ try {
5
+ const response = await fetch(`https://${site}/${uri}`, {
6
+ method: 'POST',
7
+ headers: {
8
+ 'Content-Type': 'application/json',
9
+ 'Accept': 'application/json',
10
+ ...options.headers
11
+ },
12
+ body: options.body
13
+ });
14
+ return await response.json();
15
+ } catch (error) {
16
+ console.error(error);
17
+ throw new Error('Request failed');
18
+ }
19
+ }
20
+
21
+ static async buildDownloadZipRequest(site, uri, options = {}) {
22
+ const fetch = (await import('node-fetch')).default;
23
+ try {
24
+ const response = await fetch(`https://${site}/${uri}`, {
25
+ method: 'POST',
26
+ headers: {
27
+ 'Content-Type': 'application/zip',
28
+ 'Accept': 'application/zip',
29
+ ...options.headers
30
+ },
31
+ body: options.body
32
+ });
33
+ return await response.arrayBuffer();
34
+ } catch (error) {
35
+ console.error(error);
36
+ throw new Error('Request failed');
37
+ }
38
+ }
39
+ }
40
+
41
+ module.exports = Request;
@@ -1,6 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const {slugify} = require('./utils');
3
+ const { slugify } = require('./Utils');
4
4
  const http = require('http');
5
5
  const https = require('https');
6
6
 
@@ -55,8 +55,9 @@ class ThemeManager {
55
55
  }
56
56
 
57
57
  setTheme(theme) {
58
- this.theme = slugify(theme)
58
+ this.theme = slugify(theme);
59
59
  }
60
+
60
61
  isRegistered() {
61
62
  return this.registered;
62
63
  }