@directus/storage-driver-s3 10.0.11 → 10.0.13

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/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import type { Driver, Range } from '@directus/storage';
3
- import type { Readable } from 'node:stream';
4
- export type DriverS3Config = {
1
+ import { Driver, Range } from '@directus/storage';
2
+ import { Readable } from 'node:stream';
3
+
4
+ type DriverS3Config = {
5
5
  root?: string;
6
6
  key?: string;
7
7
  secret?: string;
@@ -12,7 +12,7 @@ export type DriverS3Config = {
12
12
  region?: string;
13
13
  forcePathStyle?: boolean;
14
14
  };
15
- export declare class DriverS3 implements Driver {
15
+ declare class DriverS3 implements Driver {
16
16
  private config;
17
17
  private client;
18
18
  private root;
@@ -31,4 +31,5 @@ export declare class DriverS3 implements Driver {
31
31
  delete(filepath: string): Promise<void>;
32
32
  list(prefix?: string): AsyncGenerator<string, void, unknown>;
33
33
  }
34
- export default DriverS3;
34
+
35
+ export { DriverS3, DriverS3Config, DriverS3 as default };
package/dist/index.js CHANGED
@@ -1,163 +1,171 @@
1
- import { CopyObjectCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, S3Client, } from '@aws-sdk/client-s3';
2
- import { Upload } from '@aws-sdk/lib-storage';
3
- import { NodeHttpHandler } from '@aws-sdk/node-http-handler';
4
- import { normalizePath } from '@directus/utils';
5
- import { isReadableStream } from '@directus/utils/node';
6
- import { Agent as HttpAgent } from 'node:http';
7
- import { Agent as HttpsAgent } from 'node:https';
8
- import { join } from 'node:path';
9
- export class DriverS3 {
10
- config;
11
- client;
12
- root;
13
- constructor(config) {
14
- this.config = config;
15
- this.client = this.getClient();
16
- this.root = this.config.root ? normalizePath(this.config.root, { removeLeading: true }) : '';
1
+ // src/index.ts
2
+ import {
3
+ CopyObjectCommand,
4
+ DeleteObjectCommand,
5
+ GetObjectCommand,
6
+ HeadObjectCommand,
7
+ ListObjectsV2Command,
8
+ S3Client
9
+ } from "@aws-sdk/client-s3";
10
+ import { Upload } from "@aws-sdk/lib-storage";
11
+ import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
12
+ import { normalizePath } from "@directus/utils";
13
+ import { isReadableStream } from "@directus/utils/node";
14
+ import { Agent as HttpAgent } from "http";
15
+ import { Agent as HttpsAgent } from "https";
16
+ import { join } from "path";
17
+ var DriverS3 = class {
18
+ config;
19
+ client;
20
+ root;
21
+ constructor(config) {
22
+ this.config = config;
23
+ this.client = this.getClient();
24
+ this.root = this.config.root ? normalizePath(this.config.root, { removeLeading: true }) : "";
25
+ }
26
+ getClient() {
27
+ const connectionTimeout = 5e3;
28
+ const socketTimeout = 12e4;
29
+ const maxSockets = 500;
30
+ const keepAlive = true;
31
+ const s3ClientConfig = {
32
+ requestHandler: new NodeHttpHandler({
33
+ connectionTimeout,
34
+ socketTimeout,
35
+ httpAgent: new HttpAgent({ maxSockets, keepAlive }),
36
+ httpsAgent: new HttpsAgent({ maxSockets, keepAlive })
37
+ })
38
+ };
39
+ if (this.config.key && !this.config.secret || this.config.secret && !this.config.key) {
40
+ throw new Error("Both `key` and `secret` are required when defined");
17
41
  }
18
- getClient() {
19
- /*
20
- * AWS' client default socket reusing can cause performance issues when using it very
21
- * often in rapid succession, hitting the maxSockets limit of 50.
22
- * The requestHandler is customized to get around this.
23
- */
24
- const connectionTimeout = 5000;
25
- const socketTimeout = 120000;
26
- const maxSockets = 500;
27
- const keepAlive = true;
28
- const s3ClientConfig = {
29
- requestHandler: new NodeHttpHandler({
30
- connectionTimeout,
31
- socketTimeout,
32
- httpAgent: new HttpAgent({ maxSockets, keepAlive }),
33
- httpsAgent: new HttpsAgent({ maxSockets, keepAlive }),
34
- }),
35
- };
36
- if ((this.config.key && !this.config.secret) || (this.config.secret && !this.config.key)) {
37
- throw new Error('Both `key` and `secret` are required when defined');
38
- }
39
- if (this.config.key && this.config.secret) {
40
- s3ClientConfig.credentials = {
41
- accessKeyId: this.config.key,
42
- secretAccessKey: this.config.secret,
43
- };
44
- }
45
- if (this.config.endpoint) {
46
- const protocol = this.config.endpoint.startsWith('http://') ? 'http:' : 'https:';
47
- const hostname = this.config.endpoint.replace('https://', '').replace('http://', '');
48
- s3ClientConfig.endpoint = {
49
- hostname,
50
- protocol,
51
- path: '/',
52
- };
53
- }
54
- if (this.config.region) {
55
- s3ClientConfig.region = this.config.region;
56
- }
57
- if (this.config.forcePathStyle !== undefined) {
58
- s3ClientConfig.forcePathStyle = this.config.forcePathStyle;
59
- }
60
- return new S3Client(s3ClientConfig);
42
+ if (this.config.key && this.config.secret) {
43
+ s3ClientConfig.credentials = {
44
+ accessKeyId: this.config.key,
45
+ secretAccessKey: this.config.secret
46
+ };
61
47
  }
62
- fullPath(filepath) {
63
- return normalizePath(join(this.root, filepath));
48
+ if (this.config.endpoint) {
49
+ const protocol = this.config.endpoint.startsWith("http://") ? "http:" : "https:";
50
+ const hostname = this.config.endpoint.replace("https://", "").replace("http://", "");
51
+ s3ClientConfig.endpoint = {
52
+ hostname,
53
+ protocol,
54
+ path: "/"
55
+ };
64
56
  }
65
- async read(filepath, range) {
66
- const commandInput = {
67
- Key: this.fullPath(filepath),
68
- Bucket: this.config.bucket,
69
- };
70
- if (range) {
71
- commandInput.Range = `bytes=${range.start ?? ''}-${range.end ?? ''}`;
72
- }
73
- const { Body: stream } = await this.client.send(new GetObjectCommand(commandInput));
74
- if (!stream || !isReadableStream(stream)) {
75
- throw new Error(`No stream returned for file "${filepath}"`);
76
- }
77
- return stream;
57
+ if (this.config.region) {
58
+ s3ClientConfig.region = this.config.region;
78
59
  }
79
- async stat(filepath) {
80
- const { ContentLength, LastModified } = await this.client.send(new HeadObjectCommand({
81
- Key: this.fullPath(filepath),
82
- Bucket: this.config.bucket,
83
- }));
84
- return {
85
- size: ContentLength,
86
- modified: LastModified,
87
- };
60
+ if (this.config.forcePathStyle !== void 0) {
61
+ s3ClientConfig.forcePathStyle = this.config.forcePathStyle;
88
62
  }
89
- async exists(filepath) {
90
- try {
91
- await this.stat(filepath);
92
- return true;
93
- }
94
- catch {
95
- return false;
96
- }
63
+ return new S3Client(s3ClientConfig);
64
+ }
65
+ fullPath(filepath) {
66
+ return normalizePath(join(this.root, filepath));
67
+ }
68
+ async read(filepath, range) {
69
+ const commandInput = {
70
+ Key: this.fullPath(filepath),
71
+ Bucket: this.config.bucket
72
+ };
73
+ if (range) {
74
+ commandInput.Range = `bytes=${range.start ?? ""}-${range.end ?? ""}`;
97
75
  }
98
- async move(src, dest) {
99
- await this.copy(src, dest);
100
- await this.delete(src);
76
+ const { Body: stream } = await this.client.send(new GetObjectCommand(commandInput));
77
+ if (!stream || !isReadableStream(stream)) {
78
+ throw new Error(`No stream returned for file "${filepath}"`);
101
79
  }
102
- async copy(src, dest) {
103
- const params = {
104
- Key: this.fullPath(dest),
105
- Bucket: this.config.bucket,
106
- CopySource: `/${this.config.bucket}/${this.fullPath(src)}`,
107
- };
108
- if (this.config.serverSideEncryption) {
109
- params.ServerSideEncryption = this.config.serverSideEncryption;
110
- }
111
- if (this.config.acl) {
112
- params.ACL = this.config.acl;
113
- }
114
- await this.client.send(new CopyObjectCommand(params));
80
+ return stream;
81
+ }
82
+ async stat(filepath) {
83
+ const { ContentLength, LastModified } = await this.client.send(
84
+ new HeadObjectCommand({
85
+ Key: this.fullPath(filepath),
86
+ Bucket: this.config.bucket
87
+ })
88
+ );
89
+ return {
90
+ size: ContentLength,
91
+ modified: LastModified
92
+ };
93
+ }
94
+ async exists(filepath) {
95
+ try {
96
+ await this.stat(filepath);
97
+ return true;
98
+ } catch {
99
+ return false;
115
100
  }
116
- async write(filepath, content, type) {
117
- const params = {
118
- Key: this.fullPath(filepath),
119
- Body: content,
120
- Bucket: this.config.bucket,
121
- };
122
- if (type) {
123
- params.ContentType = type;
124
- }
125
- if (this.config.acl) {
126
- params.ACL = this.config.acl;
127
- }
128
- if (this.config.serverSideEncryption) {
129
- params.ServerSideEncryption = this.config.serverSideEncryption;
130
- }
131
- const upload = new Upload({
132
- client: this.client,
133
- params,
134
- });
135
- await upload.done();
101
+ }
102
+ async move(src, dest) {
103
+ await this.copy(src, dest);
104
+ await this.delete(src);
105
+ }
106
+ async copy(src, dest) {
107
+ const params = {
108
+ Key: this.fullPath(dest),
109
+ Bucket: this.config.bucket,
110
+ CopySource: `/${this.config.bucket}/${this.fullPath(src)}`
111
+ };
112
+ if (this.config.serverSideEncryption) {
113
+ params.ServerSideEncryption = this.config.serverSideEncryption;
114
+ }
115
+ if (this.config.acl) {
116
+ params.ACL = this.config.acl;
136
117
  }
137
- async delete(filepath) {
138
- await this.client.send(new DeleteObjectCommand({ Key: this.fullPath(filepath), Bucket: this.config.bucket }));
118
+ await this.client.send(new CopyObjectCommand(params));
119
+ }
120
+ async write(filepath, content, type) {
121
+ const params = {
122
+ Key: this.fullPath(filepath),
123
+ Body: content,
124
+ Bucket: this.config.bucket
125
+ };
126
+ if (type) {
127
+ params.ContentType = type;
139
128
  }
140
- async *list(prefix = '') {
141
- let continuationToken = undefined;
142
- do {
143
- const listObjectsV2CommandInput = {
144
- Bucket: this.config.bucket,
145
- Prefix: this.fullPath(prefix),
146
- MaxKeys: 1000,
147
- };
148
- if (continuationToken) {
149
- listObjectsV2CommandInput.ContinuationToken = continuationToken;
150
- }
151
- const response = await this.client.send(new ListObjectsV2Command(listObjectsV2CommandInput));
152
- continuationToken = response.NextContinuationToken;
153
- if (response.Contents) {
154
- for (const file of response.Contents) {
155
- if (file.Key) {
156
- yield file.Key.substring(this.root.length);
157
- }
158
- }
159
- }
160
- } while (continuationToken);
129
+ if (this.config.acl) {
130
+ params.ACL = this.config.acl;
161
131
  }
162
- }
163
- export default DriverS3;
132
+ if (this.config.serverSideEncryption) {
133
+ params.ServerSideEncryption = this.config.serverSideEncryption;
134
+ }
135
+ const upload = new Upload({
136
+ client: this.client,
137
+ params
138
+ });
139
+ await upload.done();
140
+ }
141
+ async delete(filepath) {
142
+ await this.client.send(new DeleteObjectCommand({ Key: this.fullPath(filepath), Bucket: this.config.bucket }));
143
+ }
144
+ async *list(prefix = "") {
145
+ let continuationToken = void 0;
146
+ do {
147
+ const listObjectsV2CommandInput = {
148
+ Bucket: this.config.bucket,
149
+ Prefix: this.fullPath(prefix),
150
+ MaxKeys: 1e3
151
+ };
152
+ if (continuationToken) {
153
+ listObjectsV2CommandInput.ContinuationToken = continuationToken;
154
+ }
155
+ const response = await this.client.send(new ListObjectsV2Command(listObjectsV2CommandInput));
156
+ continuationToken = response.NextContinuationToken;
157
+ if (response.Contents) {
158
+ for (const file of response.Contents) {
159
+ if (file.Key) {
160
+ yield file.Key.substring(this.root.length);
161
+ }
162
+ }
163
+ }
164
+ } while (continuationToken);
165
+ }
166
+ };
167
+ var src_default = DriverS3;
168
+ export {
169
+ DriverS3,
170
+ src_default as default
171
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/storage-driver-s3",
3
- "version": "10.0.11",
3
+ "version": "10.0.13",
4
4
  "description": "S3 file storage abstraction for `@directus/storage`",
5
5
  "homepage": "https://directus.io",
6
6
  "repository": {
@@ -25,19 +25,20 @@
25
25
  "@aws-sdk/client-s3": "3.332.0",
26
26
  "@aws-sdk/lib-storage": "3.332.0",
27
27
  "@aws-sdk/node-http-handler": "3.344.0",
28
- "@directus/storage": "10.0.5",
29
- "@directus/utils": "10.0.11"
28
+ "@directus/storage": "10.0.7",
29
+ "@directus/utils": "11.0.1"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@ngneat/falso": "6.4.0",
33
33
  "@vitest/coverage-c8": "0.31.1",
34
- "typescript": "5.0.4",
34
+ "tsup": "7.2.0",
35
+ "typescript": "5.2.2",
35
36
  "vitest": "0.31.1",
36
- "@directus/tsconfig": "1.0.0"
37
+ "@directus/tsconfig": "1.0.1"
37
38
  },
38
39
  "scripts": {
39
- "build": "tsc --project tsconfig.prod.json",
40
- "dev": "tsc --watch",
40
+ "build": "tsup src/index.ts --format=esm --dts",
41
+ "dev": "tsup src/index.ts --format=esm --dts --watch",
41
42
  "test": "vitest --watch=false"
42
43
  }
43
44
  }