@drax/media-back 3.10.0 → 3.12.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.
@@ -1,20 +1,10 @@
1
- import { CommonController, StoreManager, DraxConfig, CommonConfig, } from "@drax/common-back";
2
- import { join } from "path";
1
+ import { CommonController, } from "@drax/common-back";
3
2
  import { MediaPermissions } from "../permissions/MediaPermissions.js";
4
- import { FileServiceFactory } from "../factory/services/FileServiceFactory.js";
5
- import path from 'node:path';
6
- const BASE_FILE_DIR = DraxConfig.getOrLoad(CommonConfig.FileDir) || 'files';
7
- const BASE_URL = DraxConfig.getOrLoad(CommonConfig.BaseUrl) ? DraxConfig.get(CommonConfig.BaseUrl).replace(/\/$/, '') : '';
3
+ import { MediaService } from "../services/MediaService.js";
8
4
  class MediaController extends CommonController {
9
5
  constructor() {
10
6
  super();
11
- }
12
- validateDir(dir) {
13
- let dirRegExp = /^[a-zA-Z0-9_-]+$/;
14
- if (!dir || dirRegExp.test(dir) === false) {
15
- return false;
16
- }
17
- return true;
7
+ this.mediaService = new MediaService();
18
8
  }
19
9
  async uploadFile(request, reply) {
20
10
  try {
@@ -24,56 +14,23 @@ class MediaController extends CommonController {
24
14
  username: request.rbac.username,
25
15
  };
26
16
  const dir = request.params.dir;
27
- if (!this.validateDir(dir)) {
28
- reply.statusCode = 400;
29
- reply.send({ error: 'Invalid directory name' });
30
- return;
31
- }
32
17
  const data = await request.file();
33
- const file = {
34
- filename: data.filename,
35
- fileStream: data.file,
36
- mimetype: data.mimetype
37
- };
38
- const year = (new Date().getFullYear()).toString();
39
- const month = (new Date().getMonth() + 1).toString().padStart(2, '0');
40
- const destinationPath = join(BASE_FILE_DIR, dir, year, month);
41
- const storedFile = await StoreManager.saveFile(file, destinationPath);
42
- const urlFile = `${BASE_URL}/api/file/${dir}/${year}/${month}/${storedFile.filename}`;
43
- const relativePath = storedFile.path;
44
- const absolutePath = path.resolve(process.cwd(), relativePath);
45
- const extension = StoreManager.getExtension(storedFile.filename);
46
- const fileService = FileServiceFactory.instance;
47
- const FILE_METADATA = process.env.DRAX_FILE_METADATA ? (/true|yes|enable/i).test(process.env.DRAX_FILE_METADATA) : true;
48
- if (FILE_METADATA === true) {
49
- try {
50
- await fileService.registerUploadedFile({
51
- filename: storedFile.filename,
52
- relativePath: relativePath,
53
- absolutePath: absolutePath,
54
- size: storedFile.size,
55
- mimetype: storedFile.mimetype || data.mimetype,
56
- encoding: storedFile.encoding || data.encoding || '',
57
- extension,
58
- type: storedFile.mimetype?.split('/')[0] || '',
59
- lastAccess: new Date(),
60
- ttlSeconds: 0,
61
- hits: 0,
62
- url: urlFile,
63
- createdBy,
64
- });
65
- }
66
- catch (e) {
67
- await StoreManager.deleteFile(destinationPath, storedFile.filename).catch(() => undefined);
68
- throw e;
69
- }
70
- }
18
+ const storedFile = await this.mediaService.saveFile({
19
+ dir,
20
+ file: {
21
+ filename: data.filename,
22
+ fileStream: data.file,
23
+ mimetype: data.mimetype,
24
+ encoding: data.encoding,
25
+ },
26
+ createdBy,
27
+ });
71
28
  let theFile = {
72
29
  filename: storedFile.filename,
73
- filepath: storedFile.path,
30
+ filepath: storedFile.relativePath,
74
31
  size: storedFile.size,
75
32
  mimetype: storedFile.mimetype,
76
- url: urlFile,
33
+ url: storedFile.url,
77
34
  };
78
35
  return theFile;
79
36
  }
@@ -87,31 +44,8 @@ class MediaController extends CommonController {
87
44
  const year = request.params.year;
88
45
  const month = request.params.month;
89
46
  const filename = request.params.filename;
90
- //console.log("dir: ", dir, " year: ", year, " month: ", month, " filename: ", filename)
91
- if (this.validateDir(dir) == false) {
92
- reply.statusCode = 400;
93
- reply.send({ error: 'Invalid directory name' });
94
- return;
95
- }
96
- if (/[0-9]{4}/.test(year) == false) {
97
- reply.statusCode = 400;
98
- reply.send({ error: 'Invalid year' });
99
- return;
100
- }
101
- if (/[0-9]{2}/.test(month) == false) {
102
- reply.statusCode = 400;
103
- reply.send({ error: 'Invalid month' });
104
- return;
105
- }
106
- const fileDir = join(BASE_FILE_DIR, dir, year, month);
107
- //console.log("FILE_DIR: ", fileDir, " FILENAME:", filename)
108
- //Agregar hit al archivo
109
- const FILE_METADATA = process.env.DRAX_FILE_METADATA ? (/true|yes|enable/i).test(process.env.DRAX_FILE_METADATA) : true;
110
- if (FILE_METADATA === true) {
111
- const fileService = FileServiceFactory.instance;
112
- await fileService.registerDownloadHit(join(fileDir, filename));
113
- }
114
- return reply.sendFile(filename, fileDir);
47
+ const file = await this.mediaService.getFile({ dir, year, month, filename });
48
+ return reply.sendFile(file.filename, file.fileDir);
115
49
  }
116
50
  catch (e) {
117
51
  this.handleError(e, reply);
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ import FileModel from "./models/FileModel.js";
7
7
  import FileMongoRepository from "./repository/mongo/FileMongoRepository.js";
8
8
  import FileSqliteRepository from "./repository/sqlite/FileSqliteRepository.js";
9
9
  import FileService from "./services/FileService.js";
10
+ import MediaService from "./services/MediaService.js";
10
11
  import FileServiceFactory from "./factory/services/FileServiceFactory.js";
11
12
  import FileController from "./controllers/FileController.js";
12
13
  export {
@@ -15,4 +16,4 @@ MediaRoutes, FileRoutes,
15
16
  //Permissions
16
17
  MediaPermissions, FilePermissions,
17
18
  //File
18
- FileSchema, FileModel, FileMongoRepository, FileSqliteRepository, FileService, FileServiceFactory, FileController };
19
+ FileSchema, FileModel, FileMongoRepository, FileSqliteRepository, FileService, MediaService, FileServiceFactory, FileController };
@@ -0,0 +1,123 @@
1
+ import { BadRequestError, CommonConfig, DraxConfig, NotFoundError, StoreManager, } from "@drax/common-back";
2
+ import { join, resolve } from "node:path";
3
+ import { access } from "node:fs/promises";
4
+ import { FileServiceFactory } from "../factory/services/FileServiceFactory.js";
5
+ class MediaService {
6
+ getBaseFileDir() {
7
+ return DraxConfig.getOrLoad(CommonConfig.FileDir) || "files";
8
+ }
9
+ getBaseUrl() {
10
+ return DraxConfig.getOrLoad(CommonConfig.BaseUrl)
11
+ ? DraxConfig.get(CommonConfig.BaseUrl).replace(/\/$/, "")
12
+ : "";
13
+ }
14
+ validateDir(dir) {
15
+ const dirRegExp = /^[a-zA-Z0-9_-]+$/;
16
+ return !!dir && dirRegExp.test(dir);
17
+ }
18
+ validateYear(year) {
19
+ return /^[0-9]{4}$/.test(year);
20
+ }
21
+ validateMonth(month) {
22
+ return /^[0-9]{2}$/.test(month);
23
+ }
24
+ assertDir(dir) {
25
+ if (!this.validateDir(dir)) {
26
+ throw new BadRequestError("Invalid directory name");
27
+ }
28
+ }
29
+ assertYear(year) {
30
+ if (!this.validateYear(year)) {
31
+ throw new BadRequestError("Invalid year");
32
+ }
33
+ }
34
+ assertMonth(month) {
35
+ if (!this.validateMonth(month)) {
36
+ throw new BadRequestError("Invalid month");
37
+ }
38
+ }
39
+ isMetadataEnabled() {
40
+ return process.env.DRAX_FILE_METADATA
41
+ ? /true|yes|enable/i.test(process.env.DRAX_FILE_METADATA)
42
+ : true;
43
+ }
44
+ buildDatePathParts(date) {
45
+ return {
46
+ year: date.getFullYear().toString(),
47
+ month: (date.getMonth() + 1).toString().padStart(2, "0"),
48
+ };
49
+ }
50
+ async saveFile(params) {
51
+ const { dir, file, createdBy, date = new Date() } = params;
52
+ this.assertDir(dir);
53
+ const { year, month } = this.buildDatePathParts(date);
54
+ const fileDir = join(this.getBaseFileDir(), dir, year, month);
55
+ const storedFile = await StoreManager.saveFile(file, fileDir);
56
+ const relativePath = storedFile.path;
57
+ const absolutePath = resolve(process.cwd(), relativePath);
58
+ const extension = StoreManager.getExtension(storedFile.filename);
59
+ const url = `${this.getBaseUrl()}/api/file/${dir}/${year}/${month}/${storedFile.filename}`;
60
+ const type = storedFile.mimetype?.split("/")[0] || "";
61
+ if (this.isMetadataEnabled()) {
62
+ try {
63
+ await FileServiceFactory.instance.registerUploadedFile({
64
+ filename: storedFile.filename,
65
+ relativePath,
66
+ absolutePath,
67
+ size: storedFile.size,
68
+ mimetype: storedFile.mimetype || file.mimetype,
69
+ encoding: storedFile.encoding || file.encoding || "",
70
+ extension,
71
+ type,
72
+ lastAccess: new Date(),
73
+ ttlSeconds: 0,
74
+ hits: 0,
75
+ url,
76
+ createdBy,
77
+ });
78
+ }
79
+ catch (e) {
80
+ await StoreManager.deleteFile(fileDir, storedFile.filename).catch(() => undefined);
81
+ throw e;
82
+ }
83
+ }
84
+ return {
85
+ ...storedFile,
86
+ fileDir,
87
+ relativePath,
88
+ absolutePath,
89
+ extension,
90
+ type,
91
+ url,
92
+ };
93
+ }
94
+ async getFile(params) {
95
+ const { dir, year, month, filename, registerHit = true } = params;
96
+ this.assertDir(dir);
97
+ this.assertYear(year);
98
+ this.assertMonth(month);
99
+ const fileDir = join(this.getBaseFileDir(), dir, year, month);
100
+ const relativePath = join(fileDir, filename);
101
+ const absolutePath = resolve(process.cwd(), relativePath);
102
+ try {
103
+ await access(absolutePath);
104
+ }
105
+ catch {
106
+ throw new NotFoundError("File not found");
107
+ }
108
+ if (registerHit && this.isMetadataEnabled()) {
109
+ await FileServiceFactory.instance.registerDownloadHit(relativePath);
110
+ }
111
+ return {
112
+ dir,
113
+ year,
114
+ month,
115
+ filename,
116
+ fileDir,
117
+ relativePath,
118
+ absolutePath,
119
+ };
120
+ }
121
+ }
122
+ export default MediaService;
123
+ export { MediaService, };
package/env.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ interface ImportMetaEnv {
4
+ readonly VITE_HTTP_TRANSPORT: string
5
+ // Add other env variables here
6
+ }
7
+
8
+ interface ImportMeta {
9
+ readonly env: ImportMetaEnv
10
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "3.10.0",
6
+ "version": "3.12.0",
7
7
  "description": "Media files",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  "license": "ISC",
22
22
  "dependencies": {
23
23
  "@drax/common-back": "^3.10.0",
24
- "@drax/identity-back": "^3.10.0"
24
+ "@drax/identity-back": "^3.12.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@fastify/multipart": "^9.0.3",
@@ -39,5 +39,5 @@
39
39
  "tsc-alias": "^1.8.10",
40
40
  "typescript": "^5.4.5"
41
41
  },
42
- "gitHead": "063b6aba11e891c5374c2d3de6546a3ff120b4c9"
42
+ "gitHead": "5395a022d01165f5c4cd11adbae6ed8b5d8b670a"
43
43
  }
@@ -1,28 +1,15 @@
1
1
  import {
2
2
  CommonController,
3
- StoreManager,
4
- DraxConfig,
5
- CommonConfig,
6
3
  } from "@drax/common-back";
7
- import {join} from "path";
8
4
  import {MediaPermissions} from "../permissions/MediaPermissions.js";
9
- import {FileServiceFactory} from "../factory/services/FileServiceFactory.js";
10
- import path from 'node:path';
11
- const BASE_FILE_DIR = DraxConfig.getOrLoad(CommonConfig.FileDir) || 'files';
12
- const BASE_URL = DraxConfig.getOrLoad(CommonConfig.BaseUrl) ? DraxConfig.get(CommonConfig.BaseUrl).replace(/\/$/, '') : ''
5
+ import {MediaService} from "../services/MediaService.js";
13
6
 
14
7
  class MediaController extends CommonController {
8
+ protected mediaService: MediaService;
15
9
 
16
10
  constructor() {
17
11
  super()
18
- }
19
-
20
- validateDir(dir: string) {
21
- let dirRegExp = /^[a-zA-Z0-9_-]+$/
22
- if (!dir || dirRegExp.test(dir) === false) {
23
- return false
24
- }
25
- return true
12
+ this.mediaService = new MediaService()
26
13
  }
27
14
 
28
15
  async uploadFile(request: any, reply: any) {
@@ -35,61 +22,24 @@ class MediaController extends CommonController {
35
22
  }
36
23
 
37
24
  const dir = request.params.dir
38
- if (!this.validateDir(dir)) {
39
- reply.statusCode = 400
40
- reply.send({error: 'Invalid directory name'})
41
- return
42
- }
43
-
44
25
  const data = await request.file()
45
- const file = {
46
- filename: data.filename,
47
- fileStream: data.file,
48
- mimetype: data.mimetype
49
- }
50
-
51
- const year = (new Date().getFullYear()).toString()
52
- const month = (new Date().getMonth() + 1).toString().padStart(2, '0')
53
- const destinationPath = join(BASE_FILE_DIR, dir, year, month)
54
-
55
- const storedFile = await StoreManager.saveFile(file, destinationPath)
56
- const urlFile = `${BASE_URL}/api/file/${dir}/${year}/${month}/${storedFile.filename}`
57
- const relativePath = storedFile.path
58
- const absolutePath = path.resolve(process.cwd(), relativePath);
59
- const extension = StoreManager.getExtension(storedFile.filename)
60
- const fileService = FileServiceFactory.instance
61
-
62
-
63
- const FILE_METADATA = process.env.DRAX_FILE_METADATA ? (/true|yes|enable/i).test(process.env.DRAX_FILE_METADATA) : true
64
- if (FILE_METADATA === true) {
65
- try {
66
- await fileService.registerUploadedFile({
67
- filename: storedFile.filename,
68
- relativePath: relativePath,
69
- absolutePath: absolutePath,
70
- size: storedFile.size,
71
- mimetype: storedFile.mimetype || data.mimetype,
72
- encoding: storedFile.encoding || data.encoding || '',
73
- extension,
74
- type: storedFile.mimetype?.split('/')[0] || '',
75
- lastAccess: new Date(),
76
- ttlSeconds: 0,
77
- hits: 0,
78
- url: urlFile,
79
- createdBy,
80
- })
81
- } catch (e) {
82
- await StoreManager.deleteFile(destinationPath, storedFile.filename).catch(() => undefined)
83
- throw e
84
- }
85
- }
26
+ const storedFile = await this.mediaService.saveFile({
27
+ dir,
28
+ file: {
29
+ filename: data.filename,
30
+ fileStream: data.file,
31
+ mimetype: data.mimetype,
32
+ encoding: data.encoding,
33
+ },
34
+ createdBy,
35
+ })
86
36
 
87
37
  let theFile = {
88
38
  filename: storedFile.filename,
89
- filepath: storedFile.path,
39
+ filepath: storedFile.relativePath,
90
40
  size: storedFile.size,
91
41
  mimetype: storedFile.mimetype,
92
- url: urlFile,
42
+ url: storedFile.url,
93
43
  }
94
44
 
95
45
  return theFile
@@ -106,38 +56,8 @@ class MediaController extends CommonController {
106
56
  const year = request.params.year
107
57
  const month = request.params.month
108
58
  const filename = request.params.filename
109
-
110
- //console.log("dir: ", dir, " year: ", year, " month: ", month, " filename: ", filename)
111
-
112
- if (this.validateDir(dir) == false) {
113
- reply.statusCode = 400
114
- reply.send({error: 'Invalid directory name'})
115
- return
116
- }
117
-
118
- if (/[0-9]{4}/.test(year) == false) {
119
- reply.statusCode = 400
120
- reply.send({error: 'Invalid year'})
121
- return
122
- }
123
-
124
- if (/[0-9]{2}/.test(month) == false) {
125
- reply.statusCode = 400
126
- reply.send({error: 'Invalid month'})
127
- return
128
- }
129
-
130
- const fileDir = join(BASE_FILE_DIR, dir, year, month)
131
- //console.log("FILE_DIR: ", fileDir, " FILENAME:", filename)
132
-
133
- //Agregar hit al archivo
134
- const FILE_METADATA = process.env.DRAX_FILE_METADATA ? (/true|yes|enable/i).test(process.env.DRAX_FILE_METADATA) : true
135
- if (FILE_METADATA === true) {
136
- const fileService = FileServiceFactory.instance
137
- await fileService.registerDownloadHit(join(fileDir, filename))
138
- }
139
-
140
- return reply.sendFile(filename, fileDir)
59
+ const file = await this.mediaService.getFile({dir, year, month, filename})
60
+ return reply.sendFile(file.filename, file.fileDir)
141
61
  } catch (e) {
142
62
  this.handleError(e, reply)
143
63
  }
package/src/index.ts CHANGED
@@ -7,15 +7,28 @@ import FileModel from "./models/FileModel.js";
7
7
  import FileMongoRepository from "./repository/mongo/FileMongoRepository.js";
8
8
  import FileSqliteRepository from "./repository/sqlite/FileSqliteRepository.js";
9
9
  import FileService from "./services/FileService.js";
10
+ import MediaService from "./services/MediaService.js";
10
11
  import FileServiceFactory from "./factory/services/FileServiceFactory.js";
11
12
  import FileController from "./controllers/FileController.js";
12
13
  import type { IFile, IFileBase } from "./interfaces/IFile";
13
14
  import type { IFileRepository } from "./interfaces/IFileRepository";
15
+ import type {
16
+ IMediaCreatedBy,
17
+ IMediaSaveFileParams,
18
+ IMediaSaveFileResult,
19
+ IMediaGetFileParams,
20
+ IMediaGetFileResult,
21
+ } from "./services/MediaService.js";
14
22
 
15
23
  export type {
16
24
  IFile,
17
25
  IFileBase,
18
- IFileRepository
26
+ IFileRepository,
27
+ IMediaCreatedBy,
28
+ IMediaSaveFileParams,
29
+ IMediaSaveFileResult,
30
+ IMediaGetFileParams,
31
+ IMediaGetFileResult,
19
32
  }
20
33
 
21
34
  export {
@@ -33,6 +46,7 @@ export {
33
46
  FileMongoRepository,
34
47
  FileSqliteRepository,
35
48
  FileService,
49
+ MediaService,
36
50
  FileServiceFactory,
37
51
  FileController
38
52
  }
@@ -0,0 +1,198 @@
1
+ import {
2
+ BadRequestError,
3
+ CommonConfig,
4
+ DraxConfig,
5
+ NotFoundError,
6
+ StoreManager,
7
+ } from "@drax/common-back";
8
+ import type {IUploadFile, IUploadFileResult} from "@drax/common-back";
9
+ import {join, resolve} from "node:path";
10
+ import {access} from "node:fs/promises";
11
+ import {FileServiceFactory} from "../factory/services/FileServiceFactory.js";
12
+
13
+ interface IMediaCreatedBy {
14
+ id: string;
15
+ username: string;
16
+ }
17
+
18
+ interface IMediaSaveFileParams {
19
+ dir: string;
20
+ file: IUploadFile;
21
+ createdBy?: IMediaCreatedBy;
22
+ date?: Date;
23
+ }
24
+
25
+ interface IMediaSaveFileResult extends IUploadFileResult {
26
+ fileDir: string;
27
+ relativePath: string;
28
+ absolutePath: string;
29
+ extension: string;
30
+ type: string;
31
+ url: string;
32
+ }
33
+
34
+ interface IMediaGetFileParams {
35
+ dir: string;
36
+ year: string;
37
+ month: string;
38
+ filename: string;
39
+ registerHit?: boolean;
40
+ }
41
+
42
+ interface IMediaGetFileResult {
43
+ dir: string;
44
+ year: string;
45
+ month: string;
46
+ filename: string;
47
+ fileDir: string;
48
+ relativePath: string;
49
+ absolutePath: string;
50
+ }
51
+
52
+ class MediaService {
53
+ protected getBaseFileDir(): string {
54
+ return DraxConfig.getOrLoad(CommonConfig.FileDir) || "files";
55
+ }
56
+
57
+ protected getBaseUrl(): string {
58
+ return DraxConfig.getOrLoad(CommonConfig.BaseUrl)
59
+ ? DraxConfig.get(CommonConfig.BaseUrl).replace(/\/$/, "")
60
+ : "";
61
+ }
62
+
63
+ validateDir(dir: string): boolean {
64
+ const dirRegExp = /^[a-zA-Z0-9_-]+$/;
65
+ return !!dir && dirRegExp.test(dir);
66
+ }
67
+
68
+ validateYear(year: string): boolean {
69
+ return /^[0-9]{4}$/.test(year);
70
+ }
71
+
72
+ validateMonth(month: string): boolean {
73
+ return /^[0-9]{2}$/.test(month);
74
+ }
75
+
76
+ protected assertDir(dir: string): void {
77
+ if (!this.validateDir(dir)) {
78
+ throw new BadRequestError("Invalid directory name");
79
+ }
80
+ }
81
+
82
+ protected assertYear(year: string): void {
83
+ if (!this.validateYear(year)) {
84
+ throw new BadRequestError("Invalid year");
85
+ }
86
+ }
87
+
88
+ protected assertMonth(month: string): void {
89
+ if (!this.validateMonth(month)) {
90
+ throw new BadRequestError("Invalid month");
91
+ }
92
+ }
93
+
94
+ protected isMetadataEnabled(): boolean {
95
+ return process.env.DRAX_FILE_METADATA
96
+ ? /true|yes|enable/i.test(process.env.DRAX_FILE_METADATA)
97
+ : true;
98
+ }
99
+
100
+ protected buildDatePathParts(date: Date): {year: string; month: string} {
101
+ return {
102
+ year: date.getFullYear().toString(),
103
+ month: (date.getMonth() + 1).toString().padStart(2, "0"),
104
+ };
105
+ }
106
+
107
+ async saveFile(params: IMediaSaveFileParams): Promise<IMediaSaveFileResult> {
108
+ const {dir, file, createdBy, date = new Date()} = params;
109
+
110
+ this.assertDir(dir);
111
+
112
+ const {year, month} = this.buildDatePathParts(date);
113
+ const fileDir = join(this.getBaseFileDir(), dir, year, month);
114
+ const storedFile = await StoreManager.saveFile(file, fileDir);
115
+ const relativePath = storedFile.path;
116
+ const absolutePath = resolve(process.cwd(), relativePath);
117
+ const extension = StoreManager.getExtension(storedFile.filename);
118
+ const url = `${this.getBaseUrl()}/api/file/${dir}/${year}/${month}/${storedFile.filename}`;
119
+ const type = storedFile.mimetype?.split("/")[0] || "";
120
+
121
+ if (this.isMetadataEnabled()) {
122
+ try {
123
+ await FileServiceFactory.instance.registerUploadedFile({
124
+ filename: storedFile.filename,
125
+ relativePath,
126
+ absolutePath,
127
+ size: storedFile.size,
128
+ mimetype: storedFile.mimetype || file.mimetype,
129
+ encoding: storedFile.encoding || file.encoding || "",
130
+ extension,
131
+ type,
132
+ lastAccess: new Date(),
133
+ ttlSeconds: 0,
134
+ hits: 0,
135
+ url,
136
+ createdBy,
137
+ });
138
+ } catch (e) {
139
+ await StoreManager.deleteFile(fileDir, storedFile.filename).catch(() => undefined);
140
+ throw e;
141
+ }
142
+ }
143
+
144
+ return {
145
+ ...storedFile,
146
+ fileDir,
147
+ relativePath,
148
+ absolutePath,
149
+ extension,
150
+ type,
151
+ url,
152
+ };
153
+ }
154
+
155
+ async getFile(params: IMediaGetFileParams): Promise<IMediaGetFileResult> {
156
+ const {dir, year, month, filename, registerHit = true} = params;
157
+
158
+ this.assertDir(dir);
159
+ this.assertYear(year);
160
+ this.assertMonth(month);
161
+
162
+ const fileDir = join(this.getBaseFileDir(), dir, year, month);
163
+ const relativePath = join(fileDir, filename);
164
+ const absolutePath = resolve(process.cwd(), relativePath);
165
+
166
+ try {
167
+ await access(absolutePath);
168
+ } catch {
169
+ throw new NotFoundError("File not found");
170
+ }
171
+
172
+ if (registerHit && this.isMetadataEnabled()) {
173
+ await FileServiceFactory.instance.registerDownloadHit(relativePath);
174
+ }
175
+
176
+ return {
177
+ dir,
178
+ year,
179
+ month,
180
+ filename,
181
+ fileDir,
182
+ relativePath,
183
+ absolutePath,
184
+ };
185
+ }
186
+ }
187
+
188
+ export default MediaService;
189
+ export {
190
+ MediaService,
191
+ };
192
+ export type {
193
+ IMediaCreatedBy,
194
+ IMediaSaveFileParams,
195
+ IMediaSaveFileResult,
196
+ IMediaGetFileParams,
197
+ IMediaGetFileResult,
198
+ };