tsoft-cli 3.9.0 → 3.9.1

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 CHANGED
@@ -5,6 +5,12 @@ All notable changes to T-Soft CLI will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.9.1] - 2026-05-20
9
+
10
+ ### Fixed
11
+ - `theme section add` no longer fails with `ENOENT: theme-update.zip` when the local theme directory does not exist yet (e.g. running `section add` before `theme dev`/`pull`). The target directory is now created before the theme archive is written.
12
+ - `theme dev` no longer corrupts binary assets: image files (`png`, `jpg`, `jpeg`, `gif`, `webp`) were read as UTF-8 text, which mangled invalid byte sequences. They are now read as a buffer and sent base64-encoded for the server to decode.
13
+
8
14
  ## [3.9.0] - 2026-05-20
9
15
 
10
16
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsoft-cli",
3
- "version": "3.9.0",
3
+ "version": "3.9.1",
4
4
  "description": "Command-line tool for tsoft360 theme development and management",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -112,10 +112,12 @@ async function pullAndSync(themeUuid, themePath) {
112
112
  }
113
113
  }
114
114
 
115
+ const BINARY_EXTENSIONS = ['jpeg', 'jpg', 'png', 'gif', 'webp'];
116
+
115
117
  async function handleFileChange(themeUuid, themePath, filePath) {
116
118
  try {
117
119
  const relativePath = path.relative(themePath, filePath);
118
- const extension = path.extname(filePath).slice(1);
120
+ const extension = path.extname(filePath).slice(1).toLowerCase();
119
121
 
120
122
  const allowedExtensions = ['theme', 'twig', 'css', 'js', 'md', 'json', 'svg', 'jpeg', 'jpg', 'png', 'gif', 'webp'];
121
123
 
@@ -123,14 +125,17 @@ async function handleFileChange(themeUuid, themePath, filePath) {
123
125
  return;
124
126
  }
125
127
 
126
- const content = await fs.readFile(filePath, 'utf-8');
127
128
  const apiClient = await createApiClient();
128
-
129
129
  const startTime = Date.now();
130
130
 
131
- await apiClient.post(`/theme/${themeUuid}/file-manager?q=save`, {
132
- path: relativePath, content: content
133
- });
131
+ // Binary dosyalar (resim) utf-8 string olarak okunursa geçersiz
132
+ // byte'lar bozulur; base64 ile gönderilir, server decode eder.
133
+ const isBinary = BINARY_EXTENSIONS.includes(extension);
134
+ const payload = isBinary
135
+ ? { path: relativePath, content: (await fs.readFile(filePath)).toString('base64'), content_encoding: 'base64' }
136
+ : { path: relativePath, content: await fs.readFile(filePath, 'utf-8') };
137
+
138
+ await apiClient.post(`/theme/${themeUuid}/file-manager?q=save`, payload);
134
139
 
135
140
  const duration = Date.now() - startTime;
136
141
  console.log(chalk.green(`[${new Date().toLocaleTimeString()}] ` + t('dev.file_saved', { path: relativePath, duration })));
@@ -294,6 +294,10 @@ export async function themeSectionAddCommand() {
294
294
  const themePath = path.join(process.cwd(), storeSlug, activeTheme);
295
295
 
296
296
  try {
297
+ // Tema klasörü henüz lokalde yoksa (theme dev/pull yapılmamışsa)
298
+ // createWriteStream ENOENT verir — önce dizini garantiye al.
299
+ await fs.mkdir(themePath, { recursive: true });
300
+
297
301
  // Temayı indir
298
302
  const downloadResponse = await apiClient.download(`/theme/${themeInfo.uuid}/download`, {});
299
303
 
@@ -333,6 +337,8 @@ export async function themeSectionAddCommand() {
333
337
  }
334
338
 
335
339
  async function downloadThemeFiles(apiClient, themeUuid, themePath) {
340
+ await fs.mkdir(themePath, { recursive: true });
341
+
336
342
  const downloadResponse = await apiClient.download(`/theme/${themeUuid}/download`, {});
337
343
 
338
344
  const zipPath = path.join(themePath, 'theme-update.zip');