@devstroupe/devkit-cli 1.1.13 → 1.1.15

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,49 @@
1
+ import { Controller, Get, Post, Param, Res, NotFoundException, UseInterceptors, UploadedFile, Body } from '@nestjs/common';
2
+ import { FileInterceptor } from '@nestjs/platform-express';
3
+ import { Response } from 'express';
4
+ import { StorageService } from '@devstroupe/devkit-nest';
5
+
6
+ @Controller('storage')
7
+ export class StorageController {
8
+ constructor(
9
+ private readonly storageService: StorageService,
10
+ ) {}
11
+
12
+ @Post('upload')
13
+ @UseInterceptors(FileInterceptor('file'))
14
+ async upload(
15
+ @UploadedFile() file: any,
16
+ @Body('path') path?: string,
17
+ ) {
18
+ if (!file) {
19
+ throw new NotFoundException('Nenhum arquivo enviado.');
20
+ }
21
+
22
+ const result = await this.storageService.upload(
23
+ {
24
+ originalname: file.originalname,
25
+ mimetype: file.mimetype,
26
+ buffer: file.buffer,
27
+ size: file.size,
28
+ },
29
+ { path }
30
+ );
31
+
32
+ return result;
33
+ }
34
+
35
+ @Get('download/*key')
36
+ async download(@Param('key') key: string, @Res() res: Response) {
37
+ try {
38
+ const result = await this.storageService.download(key);
39
+
40
+ if (result.type === 'file') {
41
+ return res.sendFile(result.filePath!);
42
+ } else {
43
+ return res.redirect(result.url!);
44
+ }
45
+ } catch (err: any) {
46
+ throw new NotFoundException(err.message || 'Arquivo não encontrado.');
47
+ }
48
+ }
49
+ }
@@ -1,7 +1,7 @@
1
1
  import { Module } from '@nestjs/common';
2
- import { StorageDownloadController } from './infra/http/storage-download.controller';
2
+ import { StorageController } from './infra/http/storage.controller';
3
3
 
4
4
  @Module({
5
- controllers: [StorageDownloadController],
5
+ controllers: [StorageController],
6
6
  })
7
7
  export class StorageDownloadModule {}
package/dist/index.js CHANGED
@@ -293,9 +293,11 @@ function ensureOfficialSpartanTheme(frontendRoot, theme = 'neutral') {
293
293
  if (/--radius\s*:/.test(currentStyles) && /--sidebar-background|--sidebar\s*:/.test(currentStyles)) {
294
294
  return;
295
295
  }
296
+ const officialThemes = ['gray', 'neutral', 'slate', 'stone', 'zinc'];
297
+ const resolvedTheme = officialThemes.includes(theme) ? theme : 'neutral';
296
298
  const ng = getPackageManagerCommand(frontendRoot);
297
- console.log(`[Spartan] Aplicando tema oficial "${theme}"...`);
298
- (0, child_process_1.execSync)(`${ng} g @spartan-ng/cli:ui-theme --theme=${theme} --defaults`, {
299
+ console.log(`[Spartan] Aplicando tema oficial "${resolvedTheme}" (solicitado: "${theme}")...`);
300
+ (0, child_process_1.execSync)(`${ng} g @spartan-ng/cli:ui-theme --theme=${resolvedTheme} --defaults`, {
299
301
  cwd: frontendRoot,
300
302
  stdio: 'inherit'
301
303
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devstroupe/devkit-cli",
3
- "version": "1.1.13",
3
+ "version": "1.1.15",
4
4
  "description": "DevsTroupe Development Kit CLI — scaffold NestJS+Angular projects, inject Spartan UI, generate CRUDs and audit architectural governance",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -36,7 +36,7 @@
36
36
  "dependencies": {
37
37
  "commander": "^12.0.0",
38
38
  "fs-extra": "^11.2.0",
39
- "@devstroupe/devkit-core": "1.1.13"
39
+ "@devstroupe/devkit-core": "1.1.15"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/fs-extra": "^11.0.4",
@@ -1,38 +0,0 @@
1
- import { Controller, Get, Param, Res, NotFoundException, Inject } from '@nestjs/common';
2
- import { Response } from 'express';
3
- import * as path from 'path';
4
- import * as fs from 'fs';
5
- import { STORAGE_OPTIONS_TOKEN, StorageService } from '@devstroupe/devkit-nest';
6
-
7
- @Controller('storage')
8
- export class StorageDownloadController {
9
- constructor(
10
- @Inject(STORAGE_OPTIONS_TOKEN)
11
- private readonly storageOptions: any,
12
- private readonly storageService: StorageService,
13
- ) {}
14
-
15
- @Get('download/*key')
16
- async download(@Param('key') key: string, @Res() res: Response) {
17
- if (this.storageOptions.driver === 'local') {
18
- const storagePath = path.resolve(this.storageOptions.local?.storagePath || './storage');
19
- const targetFile = path.resolve(storagePath, key);
20
- const rootPrefix = storagePath.endsWith(path.sep) ? storagePath : storagePath + path.sep;
21
-
22
- // Mitigação Directory Traversal
23
- if (!targetFile.startsWith(rootPrefix)) {
24
- throw new NotFoundException('Arquivo não encontrado ou acesso inválido.');
25
- }
26
-
27
- if (!fs.existsSync(targetFile)) {
28
- throw new NotFoundException('Arquivo não encontrado.');
29
- }
30
-
31
- return res.sendFile(targetFile);
32
- } else {
33
- // S3 / R2
34
- const url = await this.storageService.getSignedUrl(key, 300);
35
- return res.redirect(url);
36
- }
37
- }
38
- }