@theshelf/filestore 0.3.2 → 0.4.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/README.md +18 -29
- package/dist/FileStore.d.ts +3 -2
- package/dist/FileStore.js +75 -13
- package/dist/definitions/interfaces.d.ts +1 -0
- package/dist/drivers/Memory.d.ts +1 -0
- package/dist/drivers/Memory.js +1 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -2
- package/package.json +5 -4
- package/dist/drivers/S3.d.ts +0 -18
- package/dist/drivers/S3.js +0 -105
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
# File Store | The Shelf
|
|
2
|
+
# File Store core | The Shelf
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
This package contains the definition of the file operations. It uses a interchangeable driver system for performing the actual operations. An in-memory driver is included.
|
|
5
5
|
|
|
6
6
|
## Installation
|
|
7
7
|
|
|
@@ -9,44 +9,20 @@ The file store package provides a universal interaction layer with an actual fil
|
|
|
9
9
|
npm install @theshelf/filestore
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
## Drivers
|
|
13
|
-
|
|
14
|
-
Currently, there are two drivers available:
|
|
15
|
-
|
|
16
|
-
* **Memory** - non-persistent in memory storage (suited for testing).
|
|
17
|
-
* **S3** - persistent S3 (compatible) object storage.
|
|
18
|
-
|
|
19
12
|
## How to use
|
|
20
13
|
|
|
21
14
|
The basic set up looks like this.
|
|
22
15
|
|
|
23
16
|
```ts
|
|
24
|
-
import FileStore, { MemoryDriver
|
|
17
|
+
import FileStore, { MemoryDriver } from '@theshelf/fileStore';
|
|
25
18
|
|
|
26
|
-
const driver = new
|
|
19
|
+
const driver = new MemoryDriver();
|
|
27
20
|
const fileStore = new FileStore(driver);
|
|
28
21
|
|
|
29
22
|
// Perform operations with the fileStore instance
|
|
30
23
|
```
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
#### Memory driver
|
|
35
|
-
|
|
36
|
-
No configuration options.
|
|
37
|
-
|
|
38
|
-
#### S3 driver
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
type S3Configuration = {
|
|
42
|
-
clientConfig: S3ClientConfig;
|
|
43
|
-
bucketName: string;
|
|
44
|
-
};
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
The exact configuration of the `clientConfig` depends on your S3-compatible storage provider. See the AWS SDK documentation for details.
|
|
48
|
-
|
|
49
|
-
### Operations
|
|
25
|
+
## Operations
|
|
50
26
|
|
|
51
27
|
```ts
|
|
52
28
|
// Open connection
|
|
@@ -70,3 +46,16 @@ const data: Buffer = await fileStore.readFile('path/to/file.txt');
|
|
|
70
46
|
// Throws FileNotFound if not found
|
|
71
47
|
await fileStore.deleteFile('path/to/file.txt');
|
|
72
48
|
```
|
|
49
|
+
|
|
50
|
+
## Drivers
|
|
51
|
+
|
|
52
|
+
There is one driver included in this package. Other drivers are available in separate packages.
|
|
53
|
+
|
|
54
|
+
### Memory
|
|
55
|
+
|
|
56
|
+
In memory file store (suited for testing). It doesn't have any configuration options, but has an additional operation.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// Clear the memory
|
|
60
|
+
driver.clear();
|
|
61
|
+
```
|
package/dist/FileStore.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type Logger from '@theshelf/logging';
|
|
1
2
|
import type { Driver } from './definitions/interfaces.js';
|
|
2
|
-
export default class FileStore
|
|
3
|
+
export default class FileStore {
|
|
3
4
|
#private;
|
|
4
|
-
constructor(driver: Driver);
|
|
5
|
+
constructor(driver: Driver, logger?: Logger);
|
|
5
6
|
get connected(): boolean;
|
|
6
7
|
connect(): Promise<void>;
|
|
7
8
|
disconnect(): Promise<void>;
|
package/dist/FileStore.js
CHANGED
|
@@ -1,27 +1,89 @@
|
|
|
1
|
+
import NotConnected from './errors/NotConnected.js';
|
|
1
2
|
export default class FileStore {
|
|
2
3
|
#driver;
|
|
3
|
-
|
|
4
|
+
#logger;
|
|
5
|
+
#logPrefix;
|
|
6
|
+
constructor(driver, logger) {
|
|
4
7
|
this.#driver = driver;
|
|
8
|
+
this.#logger = logger?.for(FileStore.name);
|
|
9
|
+
this.#logPrefix = `${this.#driver.name} ->`;
|
|
5
10
|
}
|
|
6
11
|
get connected() {
|
|
7
12
|
return this.#driver.connected;
|
|
8
13
|
}
|
|
9
|
-
connect() {
|
|
10
|
-
|
|
14
|
+
async connect() {
|
|
15
|
+
if (this.connected === true) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
this.#logger?.debug(this.#logPrefix, 'Connecting');
|
|
19
|
+
try {
|
|
20
|
+
await this.#driver.connect();
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
this.#logger?.error(this.#logPrefix, 'Connect failed with error', error);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
11
26
|
}
|
|
12
|
-
disconnect() {
|
|
13
|
-
|
|
27
|
+
async disconnect() {
|
|
28
|
+
if (this.connected === false) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.#logger?.debug(this.#logPrefix, 'Disconnecting');
|
|
32
|
+
try {
|
|
33
|
+
return await this.#driver.disconnect();
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
this.#logger?.error(this.#logPrefix, 'Disconnect failed with error', error);
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
14
39
|
}
|
|
15
|
-
hasFile(path) {
|
|
16
|
-
|
|
40
|
+
async hasFile(path) {
|
|
41
|
+
this.#logger?.debug(this.#logPrefix, 'Checking has file', path);
|
|
42
|
+
try {
|
|
43
|
+
this.#validateConnection();
|
|
44
|
+
return await this.#driver.hasFile(path);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.#logger?.error(this.#logPrefix, 'Check has file', path, 'failed with error', error);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
17
50
|
}
|
|
18
|
-
writeFile(path, data) {
|
|
19
|
-
|
|
51
|
+
async writeFile(path, data) {
|
|
52
|
+
this.#logger?.debug(this.#logPrefix, 'Writing file', path);
|
|
53
|
+
try {
|
|
54
|
+
this.#validateConnection();
|
|
55
|
+
return await this.#driver.writeFile(path, data);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.#logger?.error(this.#logPrefix, 'Write file', path, 'failed with error', error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
20
61
|
}
|
|
21
|
-
readFile(path) {
|
|
22
|
-
|
|
62
|
+
async readFile(path) {
|
|
63
|
+
this.#logger?.debug(this.#logPrefix, 'Reading file', path);
|
|
64
|
+
try {
|
|
65
|
+
this.#validateConnection();
|
|
66
|
+
return await this.#driver.readFile(path);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
this.#logger?.error(this.#logPrefix, 'Read file', path, 'failed with error', error);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
23
72
|
}
|
|
24
|
-
deleteFile(path) {
|
|
25
|
-
|
|
73
|
+
async deleteFile(path) {
|
|
74
|
+
this.#logger?.debug(this.#logPrefix, 'Deleting file', path);
|
|
75
|
+
try {
|
|
76
|
+
this.#validateConnection();
|
|
77
|
+
return await this.#driver.deleteFile(path);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
this.#logger?.error(this.#logPrefix, 'Delete file', path, 'failed with error', error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
#validateConnection() {
|
|
85
|
+
if (this.connected === false) {
|
|
86
|
+
throw new NotConnected();
|
|
87
|
+
}
|
|
26
88
|
}
|
|
27
89
|
}
|
package/dist/drivers/Memory.d.ts
CHANGED
package/dist/drivers/Memory.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type { Driver } from './definitions/interfaces.js';
|
|
2
2
|
export { default as FileNotFound } from './errors/FileNotFound.js';
|
|
3
|
-
export { default as
|
|
3
|
+
export { default as FileStoreError } from './errors/FileStoreError.js';
|
|
4
4
|
export { default as NotConnected } from './errors/NotConnected.js';
|
|
5
5
|
export { default as MemoryDriver } from './drivers/Memory.js';
|
|
6
|
-
export { default as S3Driver } from './drivers/S3.js';
|
|
7
6
|
export { default } from './FileStore.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { default as FileNotFound } from './errors/FileNotFound.js';
|
|
2
|
-
export { default as
|
|
2
|
+
export { default as FileStoreError } from './errors/FileStoreError.js';
|
|
3
3
|
export { default as NotConnected } from './errors/NotConnected.js';
|
|
4
4
|
export { default as MemoryDriver } from './drivers/Memory.js';
|
|
5
|
-
export { default as S3Driver } from './drivers/S3.js';
|
|
6
5
|
export { default } from './FileStore.js';
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theshelf/filestore",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "git+https://github.com/MaskingTechnology/theshelf.git"
|
|
8
8
|
},
|
|
9
|
+
"license": "MIT",
|
|
9
10
|
"scripts": {
|
|
10
11
|
"build": "tsc",
|
|
11
12
|
"clean": "rimraf dist",
|
|
@@ -19,9 +20,9 @@
|
|
|
19
20
|
"README.md",
|
|
20
21
|
"dist"
|
|
21
22
|
],
|
|
22
|
-
"types": "dist/index.d.ts",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
23
24
|
"exports": "./dist/index.js",
|
|
24
|
-
"
|
|
25
|
-
"@
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@theshelf/logging": "^0.4.0"
|
|
26
27
|
}
|
|
27
28
|
}
|
package/dist/drivers/S3.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { S3ClientConfig } from '@aws-sdk/client-s3';
|
|
2
|
-
import type { Driver } from '../definitions/interfaces.js';
|
|
3
|
-
type S3Configuration = {
|
|
4
|
-
clientConfig: S3ClientConfig;
|
|
5
|
-
bucketName: string;
|
|
6
|
-
};
|
|
7
|
-
export default class S3 implements Driver {
|
|
8
|
-
#private;
|
|
9
|
-
constructor(configuration: S3Configuration);
|
|
10
|
-
get connected(): boolean;
|
|
11
|
-
connect(): Promise<void>;
|
|
12
|
-
disconnect(): Promise<void>;
|
|
13
|
-
hasFile(path: string): Promise<boolean>;
|
|
14
|
-
writeFile(path: string, data: Buffer): Promise<void>;
|
|
15
|
-
readFile(path: string): Promise<Buffer>;
|
|
16
|
-
deleteFile(path: string): Promise<void>;
|
|
17
|
-
}
|
|
18
|
-
export {};
|
package/dist/drivers/S3.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { CreateBucketCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, ListBucketsCommand, NotFound, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
2
|
-
import FileNotFound from '../errors/FileNotFound.js';
|
|
3
|
-
import FileStoreError from '../errors/FileStoreError.js';
|
|
4
|
-
import NotConnected from '../errors/NotConnected.js';
|
|
5
|
-
const UNKNOWN_ERROR = 'Unknown error';
|
|
6
|
-
export default class S3 {
|
|
7
|
-
#configuration;
|
|
8
|
-
#bucketName;
|
|
9
|
-
#client;
|
|
10
|
-
#connected = false;
|
|
11
|
-
constructor(configuration) {
|
|
12
|
-
this.#configuration = configuration.clientConfig;
|
|
13
|
-
this.#bucketName = configuration.bucketName;
|
|
14
|
-
}
|
|
15
|
-
get connected() { return this.#connected; }
|
|
16
|
-
async connect() {
|
|
17
|
-
try {
|
|
18
|
-
this.#client = new S3Client(this.#configuration);
|
|
19
|
-
const buckets = await this.#client.send(new ListBucketsCommand({}));
|
|
20
|
-
const bucketExists = buckets.Buckets?.some(bucket => bucket.Name === this.#bucketName);
|
|
21
|
-
if (bucketExists !== true) {
|
|
22
|
-
const createBucket = new CreateBucketCommand({ Bucket: this.#bucketName });
|
|
23
|
-
await this.#client.send(createBucket);
|
|
24
|
-
}
|
|
25
|
-
this.#connected = true;
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
const message = error instanceof Error ? error.message : UNKNOWN_ERROR;
|
|
29
|
-
throw new FileStoreError('File store connection failed: ' + message);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async disconnect() {
|
|
33
|
-
if (this.#client === undefined) {
|
|
34
|
-
throw new NotConnected();
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
this.#client.destroy();
|
|
38
|
-
this.#client = undefined;
|
|
39
|
-
this.#connected = false;
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
const message = error instanceof Error ? error.message : UNKNOWN_ERROR;
|
|
43
|
-
throw new FileStoreError('File store disconnection failed: ' + message);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
async hasFile(path) {
|
|
47
|
-
const client = this.#getClient();
|
|
48
|
-
try {
|
|
49
|
-
await client.send(new HeadObjectCommand({ Bucket: this.#bucketName, Key: path }));
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
const customError = this.#handleError(error, path);
|
|
54
|
-
if (customError instanceof FileNotFound) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
async writeFile(path, data) {
|
|
61
|
-
const client = this.#getClient();
|
|
62
|
-
try {
|
|
63
|
-
await client.send(new PutObjectCommand({ Bucket: this.#bucketName, Key: path, Body: data }));
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
throw this.#handleError(error, path);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async readFile(path) {
|
|
70
|
-
const client = this.#getClient();
|
|
71
|
-
try {
|
|
72
|
-
const response = await client.send(new GetObjectCommand({ Bucket: this.#bucketName, Key: path }));
|
|
73
|
-
const body = response.Body;
|
|
74
|
-
if (body === undefined) {
|
|
75
|
-
throw new FileNotFound(path);
|
|
76
|
-
}
|
|
77
|
-
const byteArray = await body.transformToByteArray();
|
|
78
|
-
return Buffer.from(byteArray);
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
throw this.#handleError(error, path);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async deleteFile(path) {
|
|
85
|
-
const client = this.#getClient();
|
|
86
|
-
try {
|
|
87
|
-
await client.send(new DeleteObjectCommand({ Bucket: this.#bucketName, Key: path }));
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
throw this.#handleError(error, path);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
#getClient() {
|
|
94
|
-
if (this.#client === undefined) {
|
|
95
|
-
throw new NotConnected();
|
|
96
|
-
}
|
|
97
|
-
return this.#client;
|
|
98
|
-
}
|
|
99
|
-
#handleError(error, path) {
|
|
100
|
-
if (error instanceof NotFound) {
|
|
101
|
-
return new FileNotFound(path);
|
|
102
|
-
}
|
|
103
|
-
return error;
|
|
104
|
-
}
|
|
105
|
-
}
|