@unchainedshop/core-files 4.3.4 → 4.5.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.
Files changed (34) hide show
  1. package/README.md +110 -1
  2. package/lib/db/MediaObjectsCollection.d.ts +1 -2
  3. package/lib/db/MediaObjectsCollection.js +1 -2
  4. package/lib/files-index.d.ts +5 -6
  5. package/lib/files-index.js +5 -6
  6. package/lib/files-settings.d.ts +0 -1
  7. package/lib/files-settings.js +1 -2
  8. package/lib/module/configureFilesModule.d.ts +12 -5
  9. package/lib/module/configureFilesModule.js +25 -6
  10. package/lib/utils/getFileAdapter.d.ts +0 -1
  11. package/lib/utils/getFileAdapter.js +0 -2
  12. package/lib/utils/getFileFromFileData.d.ts +1 -2
  13. package/lib/utils/getFileFromFileData.js +0 -1
  14. package/package.json +13 -11
  15. package/lib/db/MediaObjectsCollection.d.ts.map +0 -1
  16. package/lib/db/MediaObjectsCollection.js.map +0 -1
  17. package/lib/files-index.d.ts.map +0 -1
  18. package/lib/files-index.js.map +0 -1
  19. package/lib/files-settings.d.ts.map +0 -1
  20. package/lib/files-settings.js.map +0 -1
  21. package/lib/module/configureFilesModule.d.ts.map +0 -1
  22. package/lib/module/configureFilesModule.js.map +0 -1
  23. package/lib/utils/getFileAdapter.d.ts.map +0 -1
  24. package/lib/utils/getFileAdapter.js.map +0 -1
  25. package/lib/utils/getFileFromFileData.d.ts.map +0 -1
  26. package/lib/utils/getFileFromFileData.js.map +0 -1
  27. package/src/db/MediaObjectsCollection.ts +0 -28
  28. package/src/files-index.ts +0 -5
  29. package/src/files-settings.ts +0 -19
  30. package/src/module/configureFilesModule.ts +0 -100
  31. package/src/utils/getFileAdapter.ts +0 -9
  32. package/src/utils/getFileFromFileData.ts +0 -14
  33. package/tests/files-index.test.ts +0 -8
  34. package/tsconfig.json +0 -10
package/README.md CHANGED
@@ -1 +1,110 @@
1
- # Files (Unchained)
1
+ [![npm version](https://img.shields.io/npm/v/@unchainedshop/core-files.svg)](https://npmjs.com/package/@unchainedshop/core-files)
2
+ [![License: EUPL-1.2](https://img.shields.io/badge/License-EUPL--1.2-blue.svg)](https://opensource.org/licenses/EUPL-1.2)
3
+
4
+ # @unchainedshop/core-files
5
+
6
+ File management module for the Unchained Engine. Handles media file metadata storage and URL normalization.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @unchainedshop/core-files
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```typescript
17
+ import { configureFilesModule } from '@unchainedshop/core-files';
18
+
19
+ const filesModule = await configureFilesModule({
20
+ db,
21
+ options: {
22
+ transformUrl: (url, params) => url, // Optional URL transformation
23
+ },
24
+ });
25
+
26
+ // Create a file record
27
+ const fileId = await filesModule.create({
28
+ name: 'product-image.jpg',
29
+ type: 'image/jpeg',
30
+ path: 'products/123',
31
+ url: '/uploads/product-image.jpg',
32
+ });
33
+
34
+ // Find file and normalize URL
35
+ const file = await filesModule.findFile({ fileId });
36
+ const normalizedUrl = filesModule.normalizeUrl(file.url, {});
37
+ ```
38
+
39
+ ## API Overview
40
+
41
+ ### Module Configuration
42
+
43
+ | Export | Description |
44
+ |--------|-------------|
45
+ | `configureFilesModule` | Configure and return the files module |
46
+
47
+ ### Queries
48
+
49
+ | Method | Description |
50
+ |--------|-------------|
51
+ | `findFile` | Find file by ID or URL |
52
+ | `findFiles` | Find files with custom selector |
53
+
54
+ ### Mutations
55
+
56
+ | Method | Description |
57
+ |--------|-------------|
58
+ | `create` | Create a new file record |
59
+ | `update` | Update an existing file |
60
+ | `delete` | Delete a file record |
61
+ | `deleteMany` | Delete multiple file records |
62
+ | `unexpire` | Remove expiration from a file |
63
+
64
+ ### Helper Methods
65
+
66
+ | Method | Description |
67
+ |--------|-------------|
68
+ | `normalizeUrl` | Normalize and transform file URL |
69
+
70
+ ### Utilities
71
+
72
+ | Export | Description |
73
+ |--------|-------------|
74
+ | `getFileAdapter` | Get configured file storage adapter |
75
+ | `getFileFromFileData` | Convert file data to File object |
76
+ | `filesSettings` | Access file module settings |
77
+
78
+ ### Types
79
+
80
+ | Export | Description |
81
+ |--------|-------------|
82
+ | `File` | File document type |
83
+ | `FilesModule` | Module interface type |
84
+ | `FilesSettingsOptions` | Configuration options type |
85
+
86
+ ## Configuration
87
+
88
+ ```typescript
89
+ const filesModule = await configureFilesModule({
90
+ db,
91
+ options: {
92
+ transformUrl: (url, params) => {
93
+ // Transform URLs for CDN, thumbnails, etc.
94
+ return `https://cdn.example.com${url}`;
95
+ },
96
+ },
97
+ });
98
+ ```
99
+
100
+ ## Events
101
+
102
+ | Event | Description |
103
+ |-------|-------------|
104
+ | `FILE_CREATE` | Emitted when a file is created |
105
+ | `FILE_UPDATE` | Emitted when a file is updated |
106
+ | `FILE_REMOVE` | Emitted when a file is removed |
107
+
108
+ ## License
109
+
110
+ EUPL-1.2
@@ -1,5 +1,5 @@
1
1
  import { mongodb } from '@unchainedshop/mongodb';
2
- import { TimestampFields } from '@unchainedshop/mongodb';
2
+ import type { TimestampFields } from '@unchainedshop/mongodb';
3
3
  export type File = {
4
4
  _id: string;
5
5
  expires: Date | null;
@@ -14,4 +14,3 @@ export type SignedFileUpload = File & {
14
14
  putURL: string;
15
15
  };
16
16
  export declare const MediaObjectsCollection: (db: mongodb.Db) => Promise<mongodb.Collection<File>>;
17
- //# sourceMappingURL=MediaObjectsCollection.d.ts.map
@@ -1,4 +1,4 @@
1
- import { buildDbIndexes } from '@unchainedshop/mongodb';
1
+ import { mongodb, buildDbIndexes } from '@unchainedshop/mongodb';
2
2
  export const MediaObjectsCollection = async (db) => {
3
3
  const MediaObjects = db.collection('media_objects');
4
4
  await buildDbIndexes(MediaObjects, [
@@ -8,4 +8,3 @@ export const MediaObjectsCollection = async (db) => {
8
8
  ]);
9
9
  return MediaObjects;
10
10
  };
11
- //# sourceMappingURL=MediaObjectsCollection.js.map
@@ -1,6 +1,5 @@
1
- export * from './module/configureFilesModule.js';
2
- export * from './db/MediaObjectsCollection.js';
3
- export * from './files-settings.js';
4
- export * from './utils/getFileAdapter.js';
5
- export * from './utils/getFileFromFileData.js';
6
- //# sourceMappingURL=files-index.d.ts.map
1
+ export * from './module/configureFilesModule.ts';
2
+ export * from './db/MediaObjectsCollection.ts';
3
+ export * from './files-settings.ts';
4
+ export * from './utils/getFileAdapter.ts';
5
+ export * from './utils/getFileFromFileData.ts';
@@ -1,6 +1,5 @@
1
- export * from './module/configureFilesModule.js';
2
- export * from './db/MediaObjectsCollection.js';
3
- export * from './files-settings.js';
4
- export * from './utils/getFileAdapter.js';
5
- export * from './utils/getFileFromFileData.js';
6
- //# sourceMappingURL=files-index.js.map
1
+ export * from "./module/configureFilesModule.js";
2
+ export * from "./db/MediaObjectsCollection.js";
3
+ export * from "./files-settings.js";
4
+ export * from "./utils/getFileAdapter.js";
5
+ export * from "./utils/getFileFromFileData.js";
@@ -7,4 +7,3 @@ export type FilesSettingsOptions = Omit<Partial<FilesSettings>, 'configureSettin
7
7
  export declare const defaultTransformUrl: (url: any) => any;
8
8
  export declare const PRIVATE_FILE_SHARING_MAX_AGE = 86400000;
9
9
  export declare const filesSettings: FilesSettings;
10
- //# sourceMappingURL=files-settings.d.ts.map
@@ -1,5 +1,5 @@
1
1
  export const defaultTransformUrl = (url) => url;
2
- export const PRIVATE_FILE_SHARING_MAX_AGE = 86400000; // 24 hours in milliseconds
2
+ export const PRIVATE_FILE_SHARING_MAX_AGE = 86400000;
3
3
  export const filesSettings = {
4
4
  transformUrl: defaultTransformUrl,
5
5
  privateFileSharingMaxAge: PRIVATE_FILE_SHARING_MAX_AGE,
@@ -8,4 +8,3 @@ export const filesSettings = {
8
8
  filesSettings.privateFileSharingMaxAge = privateFileSharingMaxAge || PRIVATE_FILE_SHARING_MAX_AGE;
9
9
  },
10
10
  };
11
- //# sourceMappingURL=files-settings.js.map
@@ -1,7 +1,15 @@
1
- import { ModuleInput } from '@unchainedshop/mongodb';
1
+ import type { ModuleInput } from '@unchainedshop/mongodb';
2
2
  import { mongodb } from '@unchainedshop/mongodb';
3
- import { File } from '../db/MediaObjectsCollection.js';
4
- import { FilesSettingsOptions } from '../files-settings.js';
3
+ import { type File } from '../db/MediaObjectsCollection.ts';
4
+ import { type FilesSettingsOptions } from '../files-settings.ts';
5
+ export interface FileQuery {
6
+ fileIds?: string[];
7
+ excludeFileId?: string;
8
+ path?: string;
9
+ paths?: string[];
10
+ meta?: Record<string, any>;
11
+ createdBefore?: Date;
12
+ }
5
13
  export declare const configureFilesModule: ({ db, options: filesOptions, }: ModuleInput<FilesSettingsOptions>) => Promise<{
6
14
  normalizeUrl: (url: string, params: Record<string, any>) => string;
7
15
  findFile: (params: {
@@ -9,7 +17,7 @@ export declare const configureFilesModule: ({ db, options: filesOptions, }: Modu
9
17
  } | {
10
18
  url: string;
11
19
  }, options?: mongodb.FindOptions) => Promise<File | null>;
12
- findFiles: (selector: mongodb.Filter<File>, options?: mongodb.FindOptions) => Promise<File[]>;
20
+ findFiles: (query: FileQuery, options?: mongodb.FindOptions) => Promise<File[]>;
13
21
  deleteMany: (fileIds: string[]) => Promise<number>;
14
22
  create: (doc: Omit<File, "_id" | "created"> & Pick<Partial<File>, "_id" | "created">) => Promise<string>;
15
23
  update: (fileId: string, doc: Partial<File>) => Promise<string>;
@@ -17,4 +25,3 @@ export declare const configureFilesModule: ({ db, options: filesOptions, }: Modu
17
25
  delete: (fileId: string) => Promise<number>;
18
26
  }>;
19
27
  export type FilesModule = Awaited<ReturnType<typeof configureFilesModule>>;
20
- //# sourceMappingURL=configureFilesModule.d.ts.map
@@ -1,12 +1,11 @@
1
1
  import { emit, registerEvents } from '@unchainedshop/events';
2
- import { generateDbFilterById, generateDbObjectId } from '@unchainedshop/mongodb';
3
- import { MediaObjectsCollection } from '../db/MediaObjectsCollection.js';
4
- import { filesSettings } from '../files-settings.js';
2
+ import { generateDbFilterById, generateDbObjectId, mongodb } from '@unchainedshop/mongodb';
3
+ import { MediaObjectsCollection } from "../db/MediaObjectsCollection.js";
4
+ import { filesSettings } from "../files-settings.js";
5
5
  const FILE_EVENTS = ['FILE_CREATE', 'FILE_UPDATE', 'FILE_REMOVE'];
6
6
  const { ROOT_URL = 'http://localhost:4010' } = process.env;
7
7
  export const configureFilesModule = async ({ db, options: filesOptions = {}, }) => {
8
8
  registerEvents(FILE_EVENTS);
9
- // Settings
10
9
  await filesSettings.configureSettings(filesOptions);
11
10
  const Files = await MediaObjectsCollection(db);
12
11
  return {
@@ -28,7 +27,28 @@ export const configureFilesModule = async ({ db, options: filesOptions = {}, })
28
27
  }
29
28
  return Files.findOne(generateDbFilterById(params.fileId), options);
30
29
  },
31
- findFiles: async (selector, options) => {
30
+ findFiles: async (query, options) => {
31
+ const selector = {};
32
+ if (query.fileIds) {
33
+ selector._id = { $in: query.fileIds };
34
+ }
35
+ if (query.excludeFileId) {
36
+ selector._id = { $ne: query.excludeFileId };
37
+ }
38
+ if (query.path) {
39
+ selector.path = query.path;
40
+ }
41
+ if (query.paths) {
42
+ selector.path = { $in: query.paths };
43
+ }
44
+ if (query.meta) {
45
+ Object.entries(query.meta).forEach(([key, value]) => {
46
+ selector[`meta.${key}`] = value;
47
+ });
48
+ }
49
+ if (query.createdBefore) {
50
+ selector.created = { $lt: query.createdBefore };
51
+ }
32
52
  return Files.find(selector, options).toArray();
33
53
  },
34
54
  deleteMany: async (fileIds) => {
@@ -71,4 +91,3 @@ export const configureFilesModule = async ({ db, options: filesOptions = {}, })
71
91
  },
72
92
  };
73
93
  };
74
- //# sourceMappingURL=configureFilesModule.js.map
@@ -1,2 +1 @@
1
1
  export declare const getFileAdapter: () => import("@unchainedshop/file-upload").IFileAdapter<unknown>;
2
- //# sourceMappingURL=getFileAdapter.d.ts.map
@@ -3,7 +3,5 @@ export const getFileAdapter = () => {
3
3
  const adapters = FileDirector.getAdapters();
4
4
  if (adapters.length === 0)
5
5
  throw Error('No file adapter found.');
6
- // For now we return the first file upload adapter without further filter options
7
6
  return adapters[0];
8
7
  };
9
- //# sourceMappingURL=getFileAdapter.js.map
@@ -1,4 +1,4 @@
1
- import { UploadFileData } from '@unchainedshop/file-upload';
1
+ import type { UploadFileData } from '@unchainedshop/file-upload';
2
2
  export declare const getFileFromFileData: (fileData: UploadFileData, meta: any) => {
3
3
  _id: string;
4
4
  path: string;
@@ -10,4 +10,3 @@ export declare const getFileFromFileData: (fileData: UploadFileData, meta: any)
10
10
  meta: any;
11
11
  };
12
12
  export default getFileFromFileData;
13
- //# sourceMappingURL=getFileFromFileData.d.ts.map
@@ -9,4 +9,3 @@ export const getFileFromFileData = (fileData, meta) => ({
9
9
  meta,
10
10
  });
11
11
  export default getFileFromFileData;
12
- //# sourceMappingURL=getFileFromFileData.js.map
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@unchainedshop/core-files",
3
- "version": "4.3.4",
3
+ "version": "4.5.0",
4
4
  "main": "lib/files-index.js",
5
5
  "types": "lib/files-index.d.ts",
6
6
  "type": "module",
7
+ "sideEffects": false,
7
8
  "scripts": {
8
9
  "clean": "tsc -b --clean",
9
10
  "build": "tsc -b",
10
11
  "prepublishOnly": "npm run clean && npm run build",
11
12
  "watch": "tsc -w",
12
- "test": "tsx --test",
13
- "test:watch": "tsx --test --watch"
13
+ "test": "node --test",
14
+ "test:watch": "node --test --watch"
14
15
  },
15
16
  "repository": {
16
17
  "type": "git",
@@ -22,8 +23,10 @@
22
23
  "core"
23
24
  ],
24
25
  "authors": [
25
- "Joël Meiller",
26
- "Pascal Kaufmann"
26
+ "Pascal Kaufmann",
27
+ "Mikael Araya",
28
+ "Vedran Rudelj",
29
+ "Joël Meiller"
27
30
  ],
28
31
  "license": "EUPL-1.2",
29
32
  "bugs": {
@@ -31,14 +34,13 @@
31
34
  },
32
35
  "homepage": "https://github.com/unchainedshop/unchained#readme",
33
36
  "dependencies": {
34
- "@unchainedshop/events": "^4.3.0",
35
- "@unchainedshop/file-upload": "^4.3.0",
36
- "@unchainedshop/logger": "^4.3.0",
37
- "@unchainedshop/utils": "^4.3.0"
37
+ "@unchainedshop/events": "^4.5.0",
38
+ "@unchainedshop/file-upload": "^4.5.0",
39
+ "@unchainedshop/logger": "^4.5.0",
40
+ "@unchainedshop/utils": "^4.5.0"
38
41
  },
39
42
  "devDependencies": {
40
- "@types/node": "^24.0.13",
41
- "tsx": "^4.20.3",
43
+ "@types/node": "^25.0.0",
42
44
  "typescript": "^5.8.3"
43
45
  }
44
46
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"MediaObjectsCollection.d.ts","sourceRoot":"","sources":["../../src/db/MediaObjectsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,MAAM,IAAI,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,eAAe,CAAC;AAEpB,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG;IACpC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,eAAO,MAAM,sBAAsB,GAAU,IAAI,OAAO,CAAC,EAAE,sCAU1D,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"MediaObjectsCollection.js","sourceRoot":"","sources":["../../src/db/MediaObjectsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAiBjE,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EAAE,EAAc,EAAE,EAAE;IAC7D,MAAM,YAAY,GAAG,EAAE,CAAC,UAAU,CAAO,eAAe,CAAC,CAAC;IAE1D,MAAM,cAAc,CAAO,YAAY,EAAE;QACvC,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;QACrB,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,kBAAkB,EAAE,CAAC,EAAE,EAAE;QAC7D,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;KAC3B,CAAC,CAAC;IAEH,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"files-index.d.ts","sourceRoot":"","sources":["../src/files-index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"files-index.js","sourceRoot":"","sources":["../src/files-index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"files-settings.d.ts","sourceRoot":"","sources":["../src/files-settings.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,MAAM,CAAC;IACnE,wBAAwB,EAAE,MAAM,CAAC;IACjC,iBAAiB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC5D;AAED,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,mBAAmB,CAAC,CAAC;AAErF,eAAO,MAAM,mBAAmB,GAAI,QAAG,QAAQ,CAAC;AAChD,eAAO,MAAM,4BAA4B,WAAW,CAAC;AAErD,eAAO,MAAM,aAAa,EAAE,aAO3B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"files-settings.js","sourceRoot":"","sources":["../src/files-settings.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC;AAChD,MAAM,CAAC,MAAM,4BAA4B,GAAG,QAAQ,CAAC,CAAC,2BAA2B;AAEjF,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,YAAY,EAAE,mBAAmB;IACjC,wBAAwB,EAAE,4BAA4B;IACtD,iBAAiB,EAAE,CAAC,EAAE,YAAY,EAAE,wBAAwB,EAAE,GAAG,EAAE,EAAE,EAAE;QACrE,aAAa,CAAC,YAAY,GAAG,YAAY,IAAI,mBAAmB,CAAC;QACjE,aAAa,CAAC,wBAAwB,GAAG,wBAAwB,IAAI,4BAA4B,CAAC;IACpG,CAAC;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"configureFilesModule.d.ts","sourceRoot":"","sources":["../../src/module/configureFilesModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAA4C,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAA0B,IAAI,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAAiB,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAM3E,eAAO,MAAM,oBAAoB,GAAU,gCAGxC,WAAW,CAAC,oBAAoB,CAAC;wBASZ,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAAM;uBAYvC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,YAAY,OAAO,CAAC,WAAW;0BAQhF,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YACpB,OAAO,CAAC,WAAW,KAC5B,OAAO,CAAC,IAAI,EAAE,CAAC;0BAIU,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAAC;kBAKlC,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;qBAUnE,MAAM,OAAO,OAAO,CAAC,IAAI,CAAC;uBAcxB,MAAM;qBAcR,MAAM;EAMhC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"configureFilesModule.js","sourceRoot":"","sources":["../../src/module/configureFilesModule.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAW,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,sBAAsB,EAAQ,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAwB,MAAM,sBAAsB,CAAC;AAE3E,MAAM,WAAW,GAAa,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;AAE5E,MAAM,EAAE,QAAQ,GAAG,uBAAuB,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;AAE3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,EACzC,EAAE,EACF,OAAO,EAAE,YAAY,GAAG,EAAE,GACQ,EAAE,EAAE;IACtC,cAAc,CAAC,WAAW,CAAC,CAAC;IAE5B,WAAW;IACX,MAAM,aAAa,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAEpD,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,EAAE,CAAC,CAAC;IAE/C,OAAO;QACL,YAAY,EAAE,CAAC,GAAW,EAAE,MAA2B,EAAU,EAAE;YACjE,MAAM,oBAAoB,GAAG,aAAa,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACrE,IAAI,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBAC/C,OAAO,QAAQ,CAAC,IAAI,CAAC;YACvB,CAAC;iBAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,oBAAoB,EAAE,QAAQ,CAAC,EAAE,CAAC;gBACxD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;gBACzD,OAAO,QAAQ,CAAC,IAAI,CAAC;YACvB,CAAC;YACD,OAAO,oBAAoB,CAAC;QAC9B,CAAC;QAED,QAAQ,EAAE,KAAK,EAAE,MAA4C,EAAE,OAA6B,EAAE,EAAE;YAC9F,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;gBACpB,OAAO,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;YACrD,CAAC;YACD,OAAO,KAAK,CAAC,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;QACrE,CAAC;QAED,SAAS,EAAE,KAAK,EACd,QAA8B,EAC9B,OAA6B,EACZ,EAAE;YACnB,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;QACjD,CAAC;QAED,UAAU,EAAE,KAAK,EAAE,OAAiB,EAAmB,EAAE;YACvD,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YACzE,OAAO,cAAc,CAAC,YAAY,CAAC;QACrC,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,GAA2E,EAAE,EAAE;YAC5F,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC;gBACnD,GAAG,EAAE,kBAAkB,EAAE;gBACzB,OAAO,EAAE,IAAI,IAAI,EAAE;gBACnB,GAAG,GAAG;aACP,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACtC,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,MAAc,EAAE,GAAkB,EAAE,EAAE;YACnD,MAAM,KAAK,CAAC,SAAS,CACnB,EAAE,GAAG,EAAE,MAAM,EAAE,EACf;gBACE,IAAI,EAAE;oBACJ,OAAO,EAAE,IAAI,IAAI,EAAE;oBACnB,GAAG,GAAG;iBACP;aACF,CACF,CAAC;YACF,MAAM,IAAI,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACtC,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAE,EAAE;YACjC,MAAM,KAAK,CAAC,SAAS,CACnB,EAAE,GAAG,EAAE,MAAM,EAAE,EACf;gBACE,IAAI,EAAE;oBACJ,OAAO,EAAE,IAAI,IAAI,EAAE;iBACpB;gBACD,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;aACvB,CACF,CAAC;YACF,MAAM,IAAI,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACtC,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,MAAc,EAAE,EAAE;YAC/B,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YAChE,MAAM,IAAI,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACtC,OAAO,YAAY,CAAC;QACtB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFileAdapter.d.ts","sourceRoot":"","sources":["../../src/utils/getFileAdapter.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,kEAM1B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFileAdapter.js","sourceRoot":"","sources":["../../src/utils/getFileAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE;IACjC,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAEjE,iFAAiF;IACjF,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrB,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFileFromFileData.d.ts","sourceRoot":"","sources":["../../src/utils/getFileFromFileData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,eAAO,MAAM,mBAAmB,GAAI,UAAU,cAAc,EAAE,MAAM,GAAG;;;;;;;;;CASrE,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFileFromFileData.js","sourceRoot":"","sources":["../../src/utils/getFileFromFileData.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,QAAwB,EAAE,IAAS,EAAE,EAAE,CAAC,CAAC;IAC3E,GAAG,EAAE,QAAQ,CAAC,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAC,aAAa;IAC5B,OAAO,EAAE,QAAQ,CAAC,UAAU,IAAI,IAAI;IACpC,IAAI,EAAE,QAAQ,CAAC,QAAQ;IACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,0BAA0B;IACjD,GAAG,EAAE,QAAQ,CAAC,GAAG;IACjB,IAAI;CACL,CAAC,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
@@ -1,28 +0,0 @@
1
- import { mongodb, buildDbIndexes } from '@unchainedshop/mongodb';
2
- import { TimestampFields } from '@unchainedshop/mongodb';
3
-
4
- export type File = {
5
- _id: string;
6
- expires: Date | null;
7
- path: string;
8
- meta?: Record<string, unknown>;
9
- name: string;
10
- size?: number;
11
- type?: string;
12
- url?: string;
13
- } & TimestampFields;
14
-
15
- export type SignedFileUpload = File & {
16
- putURL: string;
17
- };
18
- export const MediaObjectsCollection = async (db: mongodb.Db) => {
19
- const MediaObjects = db.collection<File>('media_objects');
20
-
21
- await buildDbIndexes<File>(MediaObjects, [
22
- { index: { url: 1 } },
23
- { index: { expires: 1 }, options: { expireAfterSeconds: 0 } },
24
- { index: { created: -1 } },
25
- ]);
26
-
27
- return MediaObjects;
28
- };
@@ -1,5 +0,0 @@
1
- export * from './module/configureFilesModule.js';
2
- export * from './db/MediaObjectsCollection.js';
3
- export * from './files-settings.js';
4
- export * from './utils/getFileAdapter.js';
5
- export * from './utils/getFileFromFileData.js';
@@ -1,19 +0,0 @@
1
- export interface FilesSettings {
2
- transformUrl: (url: string, params: Record<string, any>) => string;
3
- privateFileSharingMaxAge: number;
4
- configureSettings: (options: FilesSettingsOptions) => void;
5
- }
6
-
7
- export type FilesSettingsOptions = Omit<Partial<FilesSettings>, 'configureSettings'>;
8
-
9
- export const defaultTransformUrl = (url) => url;
10
- export const PRIVATE_FILE_SHARING_MAX_AGE = 86400000; // 24 hours in milliseconds
11
-
12
- export const filesSettings: FilesSettings = {
13
- transformUrl: defaultTransformUrl,
14
- privateFileSharingMaxAge: PRIVATE_FILE_SHARING_MAX_AGE,
15
- configureSettings: ({ transformUrl, privateFileSharingMaxAge } = {}) => {
16
- filesSettings.transformUrl = transformUrl || defaultTransformUrl;
17
- filesSettings.privateFileSharingMaxAge = privateFileSharingMaxAge || PRIVATE_FILE_SHARING_MAX_AGE;
18
- },
19
- };
@@ -1,100 +0,0 @@
1
- import { ModuleInput } from '@unchainedshop/mongodb';
2
- import { emit, registerEvents } from '@unchainedshop/events';
3
- import { generateDbFilterById, generateDbObjectId, mongodb } from '@unchainedshop/mongodb';
4
- import { MediaObjectsCollection, File } from '../db/MediaObjectsCollection.js';
5
- import { filesSettings, FilesSettingsOptions } from '../files-settings.js';
6
-
7
- const FILE_EVENTS: string[] = ['FILE_CREATE', 'FILE_UPDATE', 'FILE_REMOVE'];
8
-
9
- const { ROOT_URL = 'http://localhost:4010' } = process.env;
10
-
11
- export const configureFilesModule = async ({
12
- db,
13
- options: filesOptions = {},
14
- }: ModuleInput<FilesSettingsOptions>) => {
15
- registerEvents(FILE_EVENTS);
16
-
17
- // Settings
18
- await filesSettings.configureSettings(filesOptions);
19
-
20
- const Files = await MediaObjectsCollection(db);
21
-
22
- return {
23
- normalizeUrl: (url: string, params: Record<string, any>): string => {
24
- const transformedURLString = filesSettings.transformUrl(url, params);
25
- if (URL.canParse(transformedURLString)) {
26
- const finalURL = new URL(transformedURLString);
27
- return finalURL.href;
28
- } else if (URL.canParse(transformedURLString, ROOT_URL)) {
29
- const finalURL = new URL(transformedURLString, ROOT_URL);
30
- return finalURL.href;
31
- }
32
- return transformedURLString;
33
- },
34
-
35
- findFile: async (params: { fileId: string } | { url: string }, options?: mongodb.FindOptions) => {
36
- if ('url' in params) {
37
- return Files.findOne({ url: params.url }, options);
38
- }
39
- return Files.findOne(generateDbFilterById(params.fileId), options);
40
- },
41
-
42
- findFiles: async (
43
- selector: mongodb.Filter<File>,
44
- options?: mongodb.FindOptions,
45
- ): Promise<File[]> => {
46
- return Files.find(selector, options).toArray();
47
- },
48
-
49
- deleteMany: async (fileIds: string[]): Promise<number> => {
50
- const deletionResult = await Files.deleteMany({ _id: { $in: fileIds } });
51
- return deletionResult.deletedCount;
52
- },
53
-
54
- create: async (doc: Omit<File, '_id' | 'created'> & Pick<Partial<File>, '_id' | 'created'>) => {
55
- const { insertedId: fileId } = await Files.insertOne({
56
- _id: generateDbObjectId(),
57
- created: new Date(),
58
- ...doc,
59
- });
60
- await emit('FILE_CREATE', { fileId });
61
- return fileId;
62
- },
63
-
64
- update: async (fileId: string, doc: Partial<File>) => {
65
- await Files.updateOne(
66
- { _id: fileId },
67
- {
68
- $set: {
69
- updated: new Date(),
70
- ...doc,
71
- },
72
- },
73
- );
74
- await emit('FILE_UPDATE', { fileId });
75
- return fileId;
76
- },
77
-
78
- unexpire: async (fileId: string) => {
79
- await Files.updateOne(
80
- { _id: fileId },
81
- {
82
- $set: {
83
- updated: new Date(),
84
- },
85
- $unset: { expires: 1 },
86
- },
87
- );
88
- await emit('FILE_UPDATE', { fileId });
89
- return fileId;
90
- },
91
-
92
- delete: async (fileId: string) => {
93
- const { deletedCount } = await Files.deleteOne({ _id: fileId });
94
- await emit('FILE_REMOVE', { fileId });
95
- return deletedCount;
96
- },
97
- };
98
- };
99
-
100
- export type FilesModule = Awaited<ReturnType<typeof configureFilesModule>>;
@@ -1,9 +0,0 @@
1
- import { FileDirector } from '@unchainedshop/file-upload';
2
-
3
- export const getFileAdapter = () => {
4
- const adapters = FileDirector.getAdapters();
5
- if (adapters.length === 0) throw Error('No file adapter found.');
6
-
7
- // For now we return the first file upload adapter without further filter options
8
- return adapters[0];
9
- };
@@ -1,14 +0,0 @@
1
- import { UploadFileData } from '@unchainedshop/file-upload';
2
-
3
- export const getFileFromFileData = (fileData: UploadFileData, meta: any) => ({
4
- _id: fileData._id,
5
- path: fileData.directoryName,
6
- expires: fileData.expiryDate || null,
7
- name: fileData.fileName,
8
- size: fileData.size,
9
- type: fileData.type || 'application/octet-stream',
10
- url: fileData.url,
11
- meta,
12
- });
13
-
14
- export default getFileFromFileData;
@@ -1,8 +0,0 @@
1
- import { describe, it } from 'node:test';
2
- import assert from 'node:assert';
3
-
4
- describe('Files', () => {
5
- it('Init', () => {
6
- assert(true);
7
- });
8
- });
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../shared/base.tsconfig.json",
3
- "compilerOptions": {
4
- "declarationDir": "./lib",
5
- "rootDir": "./src",
6
- "outDir": "./lib",
7
-
8
- },
9
- "exclude": ["**/*.test.ts", "**/*.test.js", "tests", "lib"]
10
- }