@unchainedshop/file-upload 4.3.4 → 4.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.
package/README.md CHANGED
@@ -1 +1,135 @@
1
- # File Upload (Unchained)
1
+ [![npm version](https://img.shields.io/npm/v/@unchainedshop/file-upload.svg)](https://npmjs.com/package/@unchainedshop/file-upload)
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/file-upload
5
+
6
+ File upload abstraction layer for the Unchained Engine. Provides a pluggable system for handling file uploads with support for signed URLs, streaming, and multiple storage backends.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @unchainedshop/file-upload
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```typescript
17
+ import { FileDirector, FileAdapter, type IFileAdapter } from '@unchainedshop/file-upload';
18
+
19
+ // Create a custom file adapter
20
+ const MyStorageAdapter: IFileAdapter = {
21
+ ...FileAdapter,
22
+ key: 'my-storage',
23
+ label: 'My Storage Backend',
24
+ version: '1.0.0',
25
+
26
+ async createSignedURL(directoryName, fileName, unchainedAPI) {
27
+ // Return signed URL for direct upload
28
+ return {
29
+ _id: 'file-id',
30
+ directoryName,
31
+ fileName,
32
+ type: 'application/octet-stream',
33
+ url: 'https://storage.example.com/file',
34
+ putURL: 'https://storage.example.com/upload',
35
+ expiryDate: new Date(Date.now() + 3600000),
36
+ };
37
+ },
38
+
39
+ async createDownloadURL(file, expiry) {
40
+ return `https://storage.example.com/${file.path}`;
41
+ },
42
+ };
43
+
44
+ // Register the adapter
45
+ FileDirector.registerAdapter(MyStorageAdapter);
46
+
47
+ // Register upload callback for a directory
48
+ FileDirector.registerFileUploadCallback('product-images', async (file, unchainedAPI) => {
49
+ // Process uploaded file
50
+ console.log('File uploaded:', file.name);
51
+ });
52
+ ```
53
+
54
+ ## API Overview
55
+
56
+ ### FileDirector
57
+
58
+ | Method | Description |
59
+ |--------|-------------|
60
+ | `registerAdapter` | Register a file storage adapter |
61
+ | `getAdapter` | Get adapter by key |
62
+ | `getAdapters` | Get all registered adapters |
63
+ | `unregisterAdapter` | Remove an adapter |
64
+ | `registerFileUploadCallback` | Register callback for upload completion |
65
+ | `getFileUploadCallback` | Get registered callback for directory |
66
+
67
+ ### FileAdapter Base
68
+
69
+ Base implementation for file adapters. Override these methods:
70
+
71
+ | Method | Description |
72
+ |--------|-------------|
73
+ | `createSignedURL` | Generate signed URL for direct upload |
74
+ | `createDownloadURL` | Generate download URL for a file |
75
+ | `createDownloadStream` | Get readable stream for file download |
76
+ | `uploadFileFromStream` | Upload file from a stream |
77
+ | `uploadFileFromURL` | Upload file from external URL |
78
+ | `removeFiles` | Delete files from storage |
79
+
80
+ ### Utility Functions
81
+
82
+ | Export | Description |
83
+ |--------|-------------|
84
+ | `buildHashedFilename` | Generate hashed filename for storage |
85
+ | `resolveExpirationDate` | Calculate expiration date for signed URLs |
86
+
87
+ ### Types
88
+
89
+ | Export | Description |
90
+ |--------|-------------|
91
+ | `IFileAdapter` | Interface for file adapter implementations |
92
+ | `UploadFileData` | Data returned after file upload |
93
+ | `UploadedFile` | Representation of an uploaded file |
94
+ | `UploadFileCallback` | Callback function type for upload events |
95
+
96
+ ## Implementing a Custom Adapter
97
+
98
+ ```typescript
99
+ import { FileAdapter, type IFileAdapter } from '@unchainedshop/file-upload';
100
+
101
+ const S3Adapter: IFileAdapter = {
102
+ ...FileAdapter,
103
+ key: 's3-adapter',
104
+ label: 'AWS S3 Storage',
105
+ version: '1.0.0',
106
+
107
+ async createSignedURL(directoryName, fileName, unchainedAPI) {
108
+ // Generate presigned S3 URL
109
+ },
110
+
111
+ async createDownloadURL(file, expiry) {
112
+ // Generate presigned download URL
113
+ },
114
+
115
+ async uploadFileFromStream(directoryName, rawFile, unchainedAPI) {
116
+ // Stream upload to S3
117
+ },
118
+
119
+ async removeFiles(files, unchainedContext) {
120
+ // Delete objects from S3
121
+ },
122
+
123
+ async createDownloadStream(file, unchainedAPI) {
124
+ // Return S3 object as stream
125
+ },
126
+
127
+ async uploadFileFromURL(directoryName, fileInput, unchainedAPI) {
128
+ // Fetch and upload from URL
129
+ },
130
+ };
131
+ ```
132
+
133
+ ## License
134
+
135
+ EUPL-1.2
@@ -1,2 +1 @@
1
1
  export default function buildHashedFilename(directoryName: string, fileName: string, expiryDate: Date): Promise<string>;
2
- //# sourceMappingURL=build-hashed-filename.d.ts.map
@@ -12,4 +12,3 @@ export default async function buildHashedFilename(directoryName, fileName, expir
12
12
  const b62converted = b62.encode(hashed);
13
13
  return `${b62converted}-${slugifiedFilenameWithExtension}`;
14
14
  }
15
- //# sourceMappingURL=build-hashed-filename.js.map
@@ -1,6 +1,6 @@
1
1
  import type { Readable } from 'node:stream';
2
- import { IBaseAdapter } from '@unchainedshop/utils';
3
- import { UploadedFile, UploadFileData } from '../types.js';
2
+ import { type IBaseAdapter } from '@unchainedshop/utils';
3
+ import type { UploadedFile, UploadFileData } from '../types.ts';
4
4
  export interface IFileAdapter<Context = unknown> extends IBaseAdapter {
5
5
  createDownloadURL: (file: UploadedFile, expiry?: number) => Promise<string | null>;
6
6
  createSignedURL: (directoryName: string, fileName: string, unchainedAPI: Context) => Promise<(UploadFileData & {
@@ -17,4 +17,3 @@ export interface IFileAdapter<Context = unknown> extends IBaseAdapter {
17
17
  createDownloadStream: (file: UploadedFile, unchainedAPI: Context) => Promise<Readable>;
18
18
  }
19
19
  export declare const FileAdapter: Omit<IFileAdapter, 'key' | 'label' | 'version'>;
20
- //# sourceMappingURL=FileAdapter.d.ts.map
@@ -20,4 +20,3 @@ export const FileAdapter = {
20
20
  throw new Error('Method not implemented');
21
21
  },
22
22
  };
23
- //# sourceMappingURL=FileAdapter.js.map
@@ -1,5 +1,5 @@
1
- import { IFileAdapter } from './FileAdapter.js';
2
- import { UploadedFile } from '../types.js';
1
+ import type { IFileAdapter } from './FileAdapter.ts';
2
+ import type { UploadedFile } from '../types.ts';
3
3
  export type UploadFileCallback<UnchainedAPI = unknown> = (file: UploadedFile, unchainedAPI: UnchainedAPI) => Promise<void>;
4
4
  export declare const FileDirector: {
5
5
  registerFileUploadCallback<UnchainedAPI>(directoryName: string, fn: UploadFileCallback<UnchainedAPI>): void;
@@ -11,4 +11,3 @@ export declare const FileDirector: {
11
11
  registerAdapter: (A: IFileAdapter<unknown>) => void;
12
12
  unregisterAdapter: (key: string) => boolean;
13
13
  };
14
- //# sourceMappingURL=FileDirector.d.ts.map
@@ -12,4 +12,3 @@ export const FileDirector = {
12
12
  return FileUploadRegistry.get(directoryName) || null;
13
13
  },
14
14
  };
15
- //# sourceMappingURL=FileDirector.js.map
@@ -1,7 +1,6 @@
1
- import buildHashedFilename from './build-hashed-filename.js';
2
- import resolveExpirationDate from './put-expiration.js';
3
- export { FileDirector } from './director/FileDirector.js';
4
- export { FileAdapter, IFileAdapter } from './director/FileAdapter.js';
1
+ import buildHashedFilename from './build-hashed-filename.ts';
2
+ import resolveExpirationDate from './put-expiration.ts';
3
+ export { FileDirector } from './director/FileDirector.ts';
4
+ export { FileAdapter, type IFileAdapter } from './director/FileAdapter.ts';
5
5
  export { buildHashedFilename, resolveExpirationDate };
6
- export type * from './types.js';
7
- //# sourceMappingURL=file-upload-index.d.ts.map
6
+ export type * from './types.ts';
@@ -1,6 +1,5 @@
1
- import buildHashedFilename from './build-hashed-filename.js';
2
- import resolveExpirationDate from './put-expiration.js';
3
- export { FileDirector } from './director/FileDirector.js';
4
- export { FileAdapter } from './director/FileAdapter.js';
1
+ import buildHashedFilename from "./build-hashed-filename.js";
2
+ import resolveExpirationDate from "./put-expiration.js";
3
+ export { FileDirector } from "./director/FileDirector.js";
4
+ export { FileAdapter } from "./director/FileAdapter.js";
5
5
  export { buildHashedFilename, resolveExpirationDate };
6
- //# sourceMappingURL=file-upload-index.js.map
@@ -1,4 +1,3 @@
1
1
  export declare const expiryOffsetInMs: () => number;
2
2
  declare const resolveExpirationDate: () => Date;
3
3
  export default resolveExpirationDate;
4
- //# sourceMappingURL=put-expiration.d.ts.map
@@ -2,4 +2,3 @@ const { UNCHAINED_PUT_URL_EXPIRY = '86400000' } = process.env;
2
2
  export const expiryOffsetInMs = () => parseInt(UNCHAINED_PUT_URL_EXPIRY, 10) || 24 * 60 * 60 * 1000;
3
3
  const resolveExpirationDate = () => new Date(new Date().getTime() + expiryOffsetInMs());
4
4
  export default resolveExpirationDate;
5
- //# sourceMappingURL=put-expiration.js.map
package/lib/types.d.ts CHANGED
@@ -16,4 +16,3 @@ export interface UploadedFile {
16
16
  type?: string;
17
17
  url?: string;
18
18
  }
19
- //# sourceMappingURL=types.d.ts.map
package/lib/types.js CHANGED
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unchainedshop/file-upload",
3
- "version": "4.3.4",
3
+ "version": "4.4.0",
4
4
  "main": "lib/file-upload-index.js",
5
5
  "types": "lib/file-upload-index.d.ts",
6
6
  "type": "module",
@@ -9,8 +9,8 @@
9
9
  "build": "tsc -b",
10
10
  "prepublishOnly": "npm run clean && npm run build",
11
11
  "watch": "tsc -w",
12
- "test": "tsx --test",
13
- "test:watch": "tsx --test --watch"
12
+ "test": "node --test",
13
+ "test:watch": "node --test --watch"
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
@@ -22,8 +22,10 @@
22
22
  "core"
23
23
  ],
24
24
  "authors": [
25
- "Joël Meiller",
26
- "Pascal Kaufmann"
25
+ "Pascal Kaufmann",
26
+ "Mikael Araya",
27
+ "Vedran Rudelj",
28
+ "Joël Meiller"
27
29
  ],
28
30
  "license": "EUPL-1.2",
29
31
  "bugs": {
@@ -31,13 +33,12 @@
31
33
  },
32
34
  "homepage": "https://github.com/unchainedshop/unchained#readme",
33
35
  "dependencies": {
34
- "@unchainedshop/logger": "^4.3.0",
35
- "@unchainedshop/utils": "^4.3.0",
36
+ "@unchainedshop/logger": "^4.4.0",
37
+ "@unchainedshop/utils": "^4.4.0",
36
38
  "base-x": "^5.0.1"
37
39
  },
38
40
  "devDependencies": {
39
- "@types/node": "^24.0.13",
40
- "tsx": "^4.20.3",
41
+ "@types/node": "^25.0.0",
41
42
  "typescript": "^5.8.3"
42
43
  }
43
44
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"build-hashed-filename.d.ts","sourceRoot":"","sources":["../src/build-hashed-filename.ts"],"names":[],"mappings":"AAKA,wBAA8B,mBAAmB,CAC/C,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,IAAI,GACf,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"build-hashed-filename.js","sourceRoot":"","sources":["../src/build-hashed-filename.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,MAAM,QAAQ,CAAC;AAE3B,MAAM,GAAG,GAAG,KAAK,CAAC,gEAAgE,CAAC,CAAC;AAEpF,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,mBAAmB,CAC/C,aAAqB,EACrB,QAAgB,EAChB,UAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAEhF,MAAM,gBAAgB,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACpC,MAAM,wBAAwB,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAClE,MAAM,8BAA8B,GAAG,CAAC,OAAO,CAAC,wBAAwB,CAAC,EAAE,GAAG,CAAC;SAC5E,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAExC,OAAO,GAAG,YAAY,IAAI,8BAA8B,EAAE,CAAC;AAC7D,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileAdapter.d.ts","sourceRoot":"","sources":["../../src/director/FileAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAe,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,WAAW,YAAY,CAAC,OAAO,GAAG,OAAO,CAAE,SAAQ,YAAY;IACnE,iBAAiB,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnF,eAAe,EAAE,CACf,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,OAAO,KAClB,OAAO,CAAC,CAAC,cAAc,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3D,WAAW,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,gBAAgB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,oBAAoB,EAAE,CACpB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,GAAG,EACZ,YAAY,EAAE,OAAO,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC1B,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,iBAAiB,EAAE,CACjB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,EACD,YAAY,EAAE,OAAO,KAClB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,oBAAoB,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxF;AACD,eAAO,MAAM,WAAW,EAAE,IAAI,CAAC,YAAY,EAAE,KAAK,GAAG,OAAO,GAAG,SAAS,CAqBvE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileAdapter.js","sourceRoot":"","sources":["../../src/director/FileAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAgB,MAAM,sBAAsB,CAAC;AA6BjE,MAAM,CAAC,MAAM,WAAW,GAAoD;IAC1E,GAAG,WAAW;IAEd,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,iBAAiB;QACrB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,oBAAoB;QACxB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,oBAAoB;QACxB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,iBAAiB;QACrB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileDirector.d.ts","sourceRoot":"","sources":["../../src/director/FileDirector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,kBAAkB,CAAC,YAAY,GAAG,OAAO,IAAI,CACvD,IAAI,EAAE,YAAY,EAClB,YAAY,EAAE,YAAY,KACvB,OAAO,CAAC,IAAI,CAAC,CAAC;AAMnB,eAAO,MAAM,YAAY;+BAGI,YAAY,iBAAiB,MAAM,MAAM,kBAAkB,CAAC,YAAY,CAAC;yCAM/D,MAAM;;;;;;;CAG5C,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileDirector.js","sourceRoot":"","sources":["../../src/director/FileDirector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AASpD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEjE,MAAM,YAAY,GAAG,YAAY,CAAe,cAAc,CAAC,CAAC;AAEhE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,GAAG,YAAY;IAEf,0BAA0B,CAAe,aAAqB,EAAE,EAAoC;QAClG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YAC3C,kBAAkB,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,qBAAqB,CAAC,aAAqB;QACzC,OAAO,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC;IACvD,CAAC;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-upload-index.d.ts","sourceRoot":"","sources":["../src/file-upload-index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,qBAAqB,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,CAAC;AACtD,mBAAmB,YAAY,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-upload-index.js","sourceRoot":"","sources":["../src/file-upload-index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,qBAAqB,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAgB,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"put-expiration.d.ts","sourceRoot":"","sources":["../src/put-expiration.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,cAAsE,CAAC;AAEpG,QAAA,MAAM,qBAAqB,YAA4D,CAAC;AAExF,eAAe,qBAAqB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"put-expiration.js","sourceRoot":"","sources":["../src/put-expiration.ts"],"names":[],"mappings":"AAAA,MAAM,EAAE,wBAAwB,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;AAE9D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEpG,MAAM,qBAAqB,GAAG,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,gBAAgB,EAAE,CAAC,CAAC;AAExF,eAAe,qBAAqB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,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"}
package/lib/types.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -1,22 +0,0 @@
1
- import { sha1, slugify } from '@unchainedshop/utils';
2
- import baseX from 'base-x';
3
-
4
- const b62 = baseX('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
5
-
6
- export default async function buildHashedFilename(
7
- directoryName: string,
8
- fileName: string,
9
- expiryDate: Date,
10
- ): Promise<string> {
11
- const hashed = await sha1(`${directoryName}${fileName}${expiryDate.getTime()}`);
12
-
13
- const splittedFilename = fileName.split('.');
14
- const ext = splittedFilename?.pop();
15
- const fileNameWithoutExtension = splittedFilename.join('.') || '';
16
- const slugifiedFilenameWithExtension = [slugify(fileNameWithoutExtension), ext]
17
- .filter(Boolean)
18
- .join('.');
19
- const b62converted = b62.encode(hashed);
20
-
21
- return `${b62converted}-${slugifiedFilenameWithExtension}`;
22
- }
@@ -1,52 +0,0 @@
1
- import type { Readable } from 'node:stream';
2
- import { BaseAdapter, IBaseAdapter } from '@unchainedshop/utils';
3
- import { UploadedFile, UploadFileData } from '../types.js';
4
-
5
- export interface IFileAdapter<Context = unknown> extends IBaseAdapter {
6
- createDownloadURL: (file: UploadedFile, expiry?: number) => Promise<string | null>;
7
- createSignedURL: (
8
- directoryName: string,
9
- fileName: string,
10
- unchainedAPI: Context,
11
- ) => Promise<(UploadFileData & { putURL: string }) | null>;
12
- removeFiles: (files: UploadedFile[], unchainedContext: Context) => Promise<void>;
13
- uploadFileFromStream: (
14
- directoryName: string,
15
- rawFile: any,
16
- unchainedAPI: Context,
17
- options?: Record<string, any>,
18
- ) => Promise<UploadFileData>;
19
- uploadFileFromURL: (
20
- directoryName: string,
21
- fileInput: {
22
- fileLink: string;
23
- fileName: string;
24
- fileId?: string;
25
- headers?: Record<string, unknown>;
26
- },
27
- unchainedAPI: Context,
28
- ) => Promise<UploadFileData>;
29
- createDownloadStream: (file: UploadedFile, unchainedAPI: Context) => Promise<Readable>;
30
- }
31
- export const FileAdapter: Omit<IFileAdapter, 'key' | 'label' | 'version'> = {
32
- ...BaseAdapter,
33
-
34
- async createSignedURL() {
35
- throw new Error('Method not implemented');
36
- },
37
- async removeFiles() {
38
- throw new Error('Method not implemented');
39
- },
40
- async createDownloadURL() {
41
- throw new Error('Method not implemented');
42
- },
43
- async uploadFileFromStream() {
44
- throw new Error('Method not implemented');
45
- },
46
- async createDownloadStream() {
47
- throw new Error('Method not implemented');
48
- },
49
- async uploadFileFromURL() {
50
- throw new Error('Method not implemented');
51
- },
52
- };
@@ -1,26 +0,0 @@
1
- import { BaseDirector } from '@unchainedshop/utils';
2
- import { IFileAdapter } from './FileAdapter.js';
3
- import { UploadedFile } from '../types.js';
4
-
5
- export type UploadFileCallback<UnchainedAPI = unknown> = (
6
- file: UploadedFile,
7
- unchainedAPI: UnchainedAPI,
8
- ) => Promise<void>;
9
-
10
- const FileUploadRegistry = new Map<string, UploadFileCallback>();
11
-
12
- const baseDirector = BaseDirector<IFileAdapter>('FileDirector');
13
-
14
- export const FileDirector = {
15
- ...baseDirector,
16
-
17
- registerFileUploadCallback<UnchainedAPI>(directoryName: string, fn: UploadFileCallback<UnchainedAPI>) {
18
- if (!FileUploadRegistry.has(directoryName)) {
19
- FileUploadRegistry.set(directoryName, fn);
20
- }
21
- },
22
-
23
- getFileUploadCallback(directoryName: string) {
24
- return FileUploadRegistry.get(directoryName) || null;
25
- },
26
- };
@@ -1,12 +0,0 @@
1
- import { describe, it } from 'node:test';
2
- import assert from 'node:assert';
3
- import buildHashedFilename from './build-hashed-filename.js';
4
-
5
- describe('File Uploader', () => {
6
- it('Generate unique file name', async () => {
7
- assert.equal(
8
- await buildHashedFilename('root', 'file1.jpg', new Date(new Date('2022-12-04T17:13:09.285Z'))),
9
- 'NFJAbVaH6tRDuGDn4IPZYqh0AP-file1.jpg',
10
- );
11
- });
12
- });
@@ -1,7 +0,0 @@
1
- import buildHashedFilename from './build-hashed-filename.js';
2
- import resolveExpirationDate from './put-expiration.js';
3
-
4
- export { FileDirector } from './director/FileDirector.js';
5
- export { FileAdapter, IFileAdapter } from './director/FileAdapter.js';
6
- export { buildHashedFilename, resolveExpirationDate };
7
- export type * from './types.js';
@@ -1,7 +0,0 @@
1
- const { UNCHAINED_PUT_URL_EXPIRY = '86400000' } = process.env;
2
-
3
- export const expiryOffsetInMs = () => parseInt(UNCHAINED_PUT_URL_EXPIRY, 10) || 24 * 60 * 60 * 1000;
4
-
5
- const resolveExpirationDate = () => new Date(new Date().getTime() + expiryOffsetInMs());
6
-
7
- export default resolveExpirationDate;
package/src/types.ts DELETED
@@ -1,19 +0,0 @@
1
- export interface UploadFileData {
2
- _id: string;
3
- directoryName: string;
4
- expiryDate: Date | null;
5
- fileName: string;
6
- size?: number;
7
- type: string;
8
- url: string;
9
- }
10
-
11
- export interface UploadedFile {
12
- _id: string;
13
- path: string;
14
- meta?: Record<string, unknown>;
15
- name: string;
16
- size?: number;
17
- type?: string;
18
- url?: string;
19
- }
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../shared/base.tsconfig.json",
3
- "compilerOptions": {
4
- "declarationDir": "./lib",
5
- "rootDir": "./src",
6
- "outDir": "./lib"
7
- },
8
- "exclude": ["**/*.test.ts", "**/*.test.js", "tests", "lib"]
9
- }