@strapi/provider-upload-aws-s3 0.0.0-next.e1ede8c55a0e1e22ce20137bf238fc374bd5dd51 → 0.0.0-next.e21fe90bf2ab9906267ea6e6ca620bdcc729906c

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/LICENSE CHANGED
@@ -2,7 +2,21 @@ Copyright (c) 2015-present Strapi Solutions SAS
2
2
 
3
3
  Portions of the Strapi software are licensed as follows:
4
4
 
5
- * All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined in "ee/LICENSE".
5
+ * All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined below.
6
+
7
+ Enterprise License
8
+
9
+ If you or the company you represent has entered into a written agreement referencing the Enterprise Edition of the Strapi source code available at
10
+ https://github.com/strapi/strapi, then such agreement applies to your use of the Enterprise Edition of the Strapi Software. If you or the company you
11
+ represent is using the Enterprise Edition of the Strapi Software in connection with a subscription to our cloud offering, then the agreement you have
12
+ agreed to with respect to our cloud offering and the licenses included in such agreement apply to your use of the Enterprise Edition of the Strapi Software.
13
+ Otherwise, the Strapi Enterprise Software License Agreement (found here https://strapi.io/enterprise-terms) applies to your use of the Enterprise Edition of the Strapi Software.
14
+
15
+ BY ACCESSING OR USING THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE, YOU ARE AGREEING TO BE BOUND BY THE RELEVANT REFERENCED AGREEMENT.
16
+ IF YOU ARE NOT AUTHORIZED TO ACCEPT THESE TERMS ON BEHALF OF THE COMPANY YOU REPRESENT OR IF YOU DO NOT AGREE TO ALL OF THE RELEVANT TERMS AND CONDITIONS REFERENCED AND YOU
17
+ HAVE NOT OTHERWISE EXECUTED A WRITTEN AGREEMENT WITH STRAPI, YOU ARE NOT AUTHORIZED TO ACCESS OR USE OR ALLOW ANY USER TO ACCESS OR USE ANY PART OF
18
+ THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE. YOUR ACCESS RIGHTS ARE CONDITIONAL ON YOUR CONSENT TO THE RELEVANT REFERENCED TERMS TO THE EXCLUSION OF ALL OTHER TERMS;
19
+ IF THE RELEVANT REFERENCED TERMS ARE CONSIDERED AN OFFER BY YOU, ACCEPTANCE IS EXPRESSLY LIMITED TO THE RELEVANT REFERENCED TERMS.
6
20
 
7
21
  * All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below.
8
22
 
@@ -18,5 +32,6 @@ furnished to do so, subject to the following conditions:
18
32
  The above copyright notice and this permission notice shall be included in all
19
33
  copies or substantial portions of the Software.
20
34
 
21
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
35
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
37
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -49,8 +49,10 @@ module.exports = ({ env }) => ({
49
49
  baseUrl: env('CDN_URL'),
50
50
  rootPath: env('CDN_ROOT_PATH'),
51
51
  s3Options: {
52
- accessKeyId: env('AWS_ACCESS_KEY_ID'),
53
- secretAccessKey: env('AWS_ACCESS_SECRET'),
52
+ credentials: {
53
+ accessKeyId: env('AWS_ACCESS_KEY_ID'),
54
+ secretAccessKey: env('AWS_ACCESS_SECRET'),
55
+ },
54
56
  region: env('AWS_REGION'),
55
57
  params: {
56
58
  ACL: env('AWS_ACL', 'public-read'),
@@ -87,8 +89,10 @@ module.exports = ({ env }) => ({
87
89
  config: {
88
90
  provider: 'aws-s3',
89
91
  providerOptions: {
90
- accessKeyId: env('AWS_ACCESS_KEY_ID'),
91
- secretAccessKey: env('AWS_ACCESS_SECRET'),
92
+ credentials: {
93
+ accessKeyId: env('AWS_ACCESS_KEY_ID'),
94
+ secretAccessKey: env('AWS_ACCESS_SECRET'),
95
+ },
92
96
  region: env('AWS_REGION'),
93
97
  params: {
94
98
  ACL: 'private', // <== set ACL to private
@@ -109,7 +113,7 @@ module.exports = ({ env }) => ({
109
113
 
110
114
  #### Configuration for S3 compatible services
111
115
 
112
- This plugin may work with S3 compatible services by using the `endpoint` option instead of `region`. Scaleway example:
116
+ This plugin may work with S3 compatible services by using the `endpoint`. Scaleway example:
113
117
  `./config/plugins.js`
114
118
 
115
119
  ```js
@@ -119,9 +123,12 @@ module.exports = ({ env }) => ({
119
123
  config: {
120
124
  provider: 'aws-s3',
121
125
  providerOptions: {
122
- accessKeyId: env('SCALEWAY_ACCESS_KEY_ID'),
123
- secretAccessKey: env('SCALEWAY_ACCESS_SECRET'),
124
- endpoint: env('SCALEWAY_ENDPOINT'), // e.g. "s3.fr-par.scw.cloud"
126
+ credentials: {
127
+ accessKeyId: env('SCALEWAY_ACCESS_KEY_ID'),
128
+ secretAccessKey: env('SCALEWAY_ACCESS_SECRET'),
129
+ },
130
+ region: env('SCALEWAY_REGION'), // e.g "fr-par"
131
+ endpoint: env('SCALEWAY_ENDPOINT'), // e.g. "https://s3.fr-par.scw.cloud"
125
132
  params: {
126
133
  Bucket: env('SCALEWAY_BUCKET'),
127
134
  },
@@ -171,7 +178,7 @@ module.exports = [
171
178
  ];
172
179
  ```
173
180
 
174
- If you use dots in your bucket name, the url of the resource is in directory style (`s3.yourRegion.amazonaws.com/your.bucket.name/image.jpg`) instead of `yourBucketName.s3.yourRegion.amazonaws.com/image.jpg` so in that case the img-src and media-src directives to add will be `s3.yourRegion.amazonaws.com` without the bucket name in the url.
181
+ If you use dots in your bucket name (`forcePathStyle set to false`), the url of the resource is in directory style (`s3.yourRegion.amazonaws.com/your.bucket.name/image.jpg`) instead of `yourBucketName.s3.yourRegion.amazonaws.com/image.jpg` so in that case the img-src and media-src directives to add will be `s3.yourRegion.amazonaws.com` without the bucket name in the url.
175
182
 
176
183
  ## Bucket CORS Configuration
177
184
 
@@ -224,8 +231,10 @@ upload: {
224
231
  config: {
225
232
  provider: 'aws-s3',
226
233
  providerOptions: {
227
- accessKeyId: process.env.AWS_ACCESS_KEY_ID,
228
- secretAccessKey: process.env.AWS_ACCESS_SECRET,
234
+ credentials: {
235
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
236
+ secretAccessKey: process.env.AWS_ACCESS_SECRET,
237
+ },
229
238
  region: process.env.AWS_REGION,
230
239
  baseUrl: `https://s3.${region}.amazonaws.com/${bucket}`, // This line sets the custom url format
231
240
  params: {
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export interface File {
14
14
  ext?: string;
15
15
  mime: string;
16
16
  size: number;
17
+ sizeInBytes: number;
17
18
  url: string;
18
19
  previewUrl?: string;
19
20
  path?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,EAIL,yBAAyB,EAEzB,oCAAoC,EACpC,iCAAiC,EACjC,cAAc,EACd,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAK5D,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAC9B,oCAAoC,GACpC,iCAAiC,CACpC,GAAG;IACF,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAe,SAAQ,cAAc;IAEpD,WAAW,CAAC,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACnD,eAAe,CAAC,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;IAE3D,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,cAAc,GAAG;IAAE,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC,GAAG;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB,CAAC;;+DA0B2D,WAAW;;2BAwCzC,IAAI,gBAAgB,GAAG;iBAAkB,MAAM;;2BAqBrD,IAAI;qBAGV,IAAI;qBAGJ,IAAI,sBAAsB,QAAQ,yBAAyB,CAAC;;;AApE/E,wBA8EE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,EAIL,yBAAyB,EAEzB,oCAAoC,EACpC,iCAAiC,EACjC,cAAc,EACd,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAK5D,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAC9B,oCAAoC,GACpC,iCAAiC,CACpC,GAAG;IACF,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAe,SAAQ,cAAc;IAEpD,WAAW,CAAC,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACnD,eAAe,CAAC,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;IAE3D,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,cAAc,GAAG;IAAE,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC,GAAG;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB,CAAC;;+DA0B2D,WAAW;;2BAwCzC,IAAI,gBAAgB,GAAG,GAAG,QAAQ;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;2BAsBxD,IAAI;qBAGV,IAAI;qBAGJ,IAAI,sBAAsB,QAAQ,yBAAyB,CAAC;;;AArE/E,wBA+EE"}
package/dist/index.js CHANGED
@@ -1,161 +1,116 @@
1
- "use strict";
2
- const fp = require("lodash/fp");
3
- const clientS3 = require("@aws-sdk/client-s3");
4
- const s3RequestPresigner = require("@aws-sdk/s3-request-presigner");
5
- const libStorage = require("@aws-sdk/lib-storage");
6
- const ENDPOINT_PATTERN = /^(.+\.)?s3[.-]([a-z0-9-]+)\./;
7
- function isUrlFromBucket(fileUrl, bucketName, baseUrl = "") {
8
- const url = new URL(fileUrl);
9
- if (baseUrl) {
10
- return false;
11
- }
12
- const { bucket } = getBucketFromAwsUrl(fileUrl);
13
- if (bucket) {
14
- return bucket === bucketName;
15
- }
16
- return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);
17
- }
18
- function getBucketFromAwsUrl(fileUrl) {
19
- const url = new URL(fileUrl);
20
- if (url.protocol === "s3:") {
21
- const bucket = url.host;
22
- if (!bucket) {
23
- return { err: `Invalid S3 url: no bucket: ${url}` };
24
- }
25
- return { bucket };
26
- }
27
- if (!url.host) {
28
- return { err: `Invalid S3 url: no hostname: ${url}` };
29
- }
30
- const matches = url.host.match(ENDPOINT_PATTERN);
31
- if (!matches) {
32
- return { err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}` };
33
- }
34
- const prefix = matches[1];
35
- if (!prefix) {
36
- if (url.pathname === "/") {
37
- return { bucket: null };
38
- }
39
- const index2 = url.pathname.indexOf("/", 1);
40
- if (index2 === -1) {
41
- return { bucket: url.pathname.substring(1) };
42
- }
43
- if (index2 === url.pathname.length - 1) {
44
- return { bucket: url.pathname.substring(1, index2) };
1
+ 'use strict';
2
+
3
+ var fp = require('lodash/fp');
4
+ var clientS3 = require('@aws-sdk/client-s3');
5
+ var s3RequestPresigner = require('@aws-sdk/s3-request-presigner');
6
+ var libStorage = require('@aws-sdk/lib-storage');
7
+ var utils = require('./utils.js');
8
+
9
+ const assertUrlProtocol = (url)=>{
10
+ // Regex to test protocol like "http://", "https://"
11
+ return /^\w*:\/\//.test(url);
12
+ };
13
+ const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options })=>{
14
+ if (Object.keys(legacyS3Options).length > 0) {
15
+ process.emitWarning("S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property.");
45
16
  }
46
- return { bucket: url.pathname.substring(1, index2) };
47
- }
48
- return { bucket: prefix.substring(0, prefix.length - 1) };
49
- }
50
- const extractCredentials = (options) => {
51
- if (options.accessKeyId && options.secretAccessKey) {
52
- return {
53
- accessKeyId: options.accessKeyId,
54
- secretAccessKey: options.secretAccessKey
55
- };
56
- }
57
- if (options.s3Options?.accessKeyId && options.s3Options.secretAccessKey) {
58
- process.emitWarning(
59
- "Credentials passed directly to s3Options is deprecated and will be removed in a future release. Please wrap them inside a credentials object."
60
- );
61
- return {
62
- accessKeyId: options.s3Options.accessKeyId,
63
- secretAccessKey: options.s3Options.secretAccessKey
64
- };
65
- }
66
- if (options.s3Options?.credentials) {
67
- return {
68
- accessKeyId: options.s3Options.credentials.accessKeyId,
69
- secretAccessKey: options.s3Options.credentials.secretAccessKey
17
+ const credentials = utils.extractCredentials({
18
+ s3Options,
19
+ ...legacyS3Options
20
+ });
21
+ const config = {
22
+ ...s3Options,
23
+ ...legacyS3Options,
24
+ ...credentials ? {
25
+ credentials
26
+ } : {}
70
27
  };
71
- }
72
- return null;
28
+ config.params.ACL = fp.getOr(clientS3.ObjectCannedACL.public_read, [
29
+ 'params',
30
+ 'ACL'
31
+ ], config);
32
+ return config;
73
33
  };
74
- const assertUrlProtocol = (url) => {
75
- return /^\w*:\/\//.test(url);
76
- };
77
- const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) => {
78
- if (Object.keys(legacyS3Options).length > 0) {
79
- process.emitWarning(
80
- "S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property."
81
- );
82
- }
83
- const credentials = extractCredentials({ s3Options, ...legacyS3Options });
84
- const config = {
85
- ...s3Options,
86
- ...legacyS3Options,
87
- ...credentials ? { credentials } : {}
88
- };
89
- config.params.ACL = fp.getOr(clientS3.ObjectCannedACL.public_read, ["params", "ACL"], config);
90
- return config;
91
- };
92
- const index = {
93
- init({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
94
- const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });
95
- const s3Client = new clientS3.S3Client(config);
96
- const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, "")}/` : "";
97
- const getFileKey = (file) => {
98
- const path = file.path ? `${file.path}/` : "";
99
- return `${filePrefix}${path}${file.hash}${file.ext}`;
100
- };
101
- const upload = async (file, customParams = {}) => {
102
- const fileKey = getFileKey(file);
103
- const uploadObj = new libStorage.Upload({
104
- client: s3Client,
105
- params: {
106
- Bucket: config.params.Bucket,
107
- Key: fileKey,
108
- Body: file.stream || Buffer.from(file.buffer, "binary"),
109
- ACL: config.params.ACL,
110
- ContentType: file.mime,
111
- ...customParams
112
- }
113
- });
114
- const upload2 = await uploadObj.done();
115
- if (assertUrlProtocol(upload2.Location)) {
116
- file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload2.Location;
117
- } else {
118
- file.url = `https://${upload2.Location}`;
119
- }
120
- };
121
- return {
122
- isPrivate() {
123
- return config.params.ACL === "private";
124
- },
125
- async getSignedUrl(file, customParams) {
126
- if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
127
- return { url: file.url };
128
- }
129
- const fileKey = getFileKey(file);
130
- const url = await s3RequestPresigner.getSignedUrl(
131
- s3Client,
132
- new clientS3.GetObjectCommand({
133
- Bucket: config.params.Bucket,
134
- Key: fileKey,
135
- ...customParams
136
- }),
137
- {
138
- expiresIn: fp.getOr(15 * 60, ["params", "signedUrlExpires"], config)
139
- }
140
- );
141
- return { url };
142
- },
143
- uploadStream(file, customParams = {}) {
144
- return upload(file, customParams);
145
- },
146
- upload(file, customParams = {}) {
147
- return upload(file, customParams);
148
- },
149
- delete(file, customParams = {}) {
150
- const command = new clientS3.DeleteObjectCommand({
151
- Bucket: config.params.Bucket,
152
- Key: getFileKey(file),
153
- ...customParams
34
+ var index = {
35
+ init ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
36
+ // TODO V5 change config structure to avoid having to do this
37
+ const config = getConfig({
38
+ baseUrl,
39
+ rootPath,
40
+ s3Options,
41
+ ...legacyS3Options
154
42
  });
155
- return s3Client.send(command);
156
- }
157
- };
158
- }
43
+ const s3Client = new clientS3.S3Client(config);
44
+ const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, '')}/` : '';
45
+ const getFileKey = (file)=>{
46
+ const path = file.path ? `${file.path}/` : '';
47
+ return `${filePrefix}${path}${file.hash}${file.ext}`;
48
+ };
49
+ const upload = async (file, customParams = {})=>{
50
+ const fileKey = getFileKey(file);
51
+ const uploadObj = new libStorage.Upload({
52
+ client: s3Client,
53
+ params: {
54
+ Bucket: config.params.Bucket,
55
+ Key: fileKey,
56
+ Body: file.stream || Buffer.from(file.buffer, 'binary'),
57
+ ACL: config.params.ACL,
58
+ ContentType: file.mime,
59
+ ...customParams
60
+ }
61
+ });
62
+ const upload = await uploadObj.done();
63
+ if (assertUrlProtocol(upload.Location)) {
64
+ file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;
65
+ } else {
66
+ // Default protocol to https protocol
67
+ file.url = `https://${upload.Location}`;
68
+ }
69
+ };
70
+ return {
71
+ isPrivate () {
72
+ return config.params.ACL === 'private';
73
+ },
74
+ async getSignedUrl (file, customParams) {
75
+ // Do not sign the url if it does not come from the same bucket.
76
+ if (!utils.isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
77
+ return {
78
+ url: file.url
79
+ };
80
+ }
81
+ const fileKey = getFileKey(file);
82
+ const url = await s3RequestPresigner.getSignedUrl(// @ts-expect-error - TODO fix client type
83
+ s3Client, new clientS3.GetObjectCommand({
84
+ Bucket: config.params.Bucket,
85
+ Key: fileKey,
86
+ ...customParams
87
+ }), {
88
+ expiresIn: fp.getOr(15 * 60, [
89
+ 'params',
90
+ 'signedUrlExpires'
91
+ ], config)
92
+ });
93
+ return {
94
+ url
95
+ };
96
+ },
97
+ uploadStream (file, customParams = {}) {
98
+ return upload(file, customParams);
99
+ },
100
+ upload (file, customParams = {}) {
101
+ return upload(file, customParams);
102
+ },
103
+ delete (file, customParams = {}) {
104
+ const command = new clientS3.DeleteObjectCommand({
105
+ Bucket: config.params.Bucket,
106
+ Key: getFileKey(file),
107
+ ...customParams
108
+ });
109
+ return s3Client.send(command);
110
+ }
111
+ };
112
+ }
159
113
  };
114
+
160
115
  module.exports = index;
161
116
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["import type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport type { InitOptions } from '.';\n\nconst ENDPOINT_PATTERN = /^(.+\\.)?s3[.-]([a-z0-9-]+)\\./;\n\ninterface BucketInfo {\n bucket?: string | null;\n err?: string;\n}\n\nexport function isUrlFromBucket(fileUrl: string, bucketName: string, baseUrl = ''): boolean {\n const url = new URL(fileUrl);\n\n // Check if the file URL is using a base URL (e.g. a CDN).\n // In this case do not sign the URL.\n if (baseUrl) {\n return false;\n }\n\n const { bucket } = getBucketFromAwsUrl(fileUrl);\n\n if (bucket) {\n return bucket === bucketName;\n }\n\n // File URL might be of an S3-compatible provider. (or an invalid URL)\n // In this case, check if the bucket name appears in the URL host or path.\n // e.g. https://minio.example.com/bucket-name/object-key\n // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png\n return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);\n}\n\n/**\n * Parse the bucket name from a URL.\n * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html\n *\n * @param {string} fileUrl - the URL to parse\n * @returns {object} result\n * @returns {string} result.bucket - the bucket name\n * @returns {string} result.err - if any\n */\nfunction getBucketFromAwsUrl(fileUrl: string): BucketInfo {\n const url = new URL(fileUrl);\n\n // S3://<bucket-name>/<key>\n if (url.protocol === 's3:') {\n const bucket = url.host;\n\n if (!bucket) {\n return { err: `Invalid S3 url: no bucket: ${url}` };\n }\n return { bucket };\n }\n\n if (!url.host) {\n return { err: `Invalid S3 url: no hostname: ${url}` };\n }\n\n const matches = url.host.match(ENDPOINT_PATTERN);\n if (!matches) {\n return { err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}` };\n }\n\n const prefix = matches[1];\n // https://s3.amazonaws.com/<bucket-name>\n if (!prefix) {\n if (url.pathname === '/') {\n return { bucket: null };\n }\n\n const index = url.pathname.indexOf('/', 1);\n\n // https://s3.amazonaws.com/<bucket-name>\n if (index === -1) {\n return { bucket: url.pathname.substring(1) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/\n if (index === url.pathname.length - 1) {\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/key\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://<bucket-name>.s3.amazonaws.com/\n return { bucket: prefix.substring(0, prefix.length - 1) };\n}\n\n// TODO Remove this in V5 since we will only support the new config structure\nexport const extractCredentials = (options: InitOptions): AwsCredentialIdentity | null => {\n // legacy\n if (options.accessKeyId && options.secretAccessKey) {\n return {\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n };\n }\n // Legacy\n if (options.s3Options?.accessKeyId && options.s3Options.secretAccessKey) {\n process.emitWarning(\n 'Credentials passed directly to s3Options is deprecated and will be removed in a future release. Please wrap them inside a credentials object.'\n );\n return {\n accessKeyId: options.s3Options.accessKeyId,\n secretAccessKey: options.s3Options.secretAccessKey,\n };\n }\n // V5\n if (options.s3Options?.credentials) {\n return {\n accessKeyId: options.s3Options.credentials.accessKeyId,\n secretAccessKey: options.s3Options.credentials.secretAccessKey,\n };\n }\n return null;\n};\n","import type { ReadStream } from 'node:fs';\nimport { getOr } from 'lodash/fp';\nimport {\n S3Client,\n GetObjectCommand,\n DeleteObjectCommand,\n DeleteObjectCommandOutput,\n PutObjectCommandInput,\n CompleteMultipartUploadCommandOutput,\n AbortMultipartUploadCommandOutput,\n S3ClientConfig,\n ObjectCannedACL,\n} from '@aws-sdk/client-s3';\nimport type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { extractCredentials, isUrlFromBucket } from './utils';\n\nexport interface File {\n name: string;\n alternativeText?: string;\n caption?: string;\n width?: number;\n height?: number;\n formats?: Record<string, unknown>;\n hash: string;\n ext?: string;\n mime: string;\n size: number;\n url: string;\n previewUrl?: string;\n path?: string;\n provider?: string;\n provider_metadata?: Record<string, unknown>;\n stream?: ReadStream;\n buffer?: Buffer;\n}\n\nexport type UploadCommandOutput = (\n | CompleteMultipartUploadCommandOutput\n | AbortMultipartUploadCommandOutput\n) & {\n Location: string;\n};\n\nexport interface AWSParams {\n Bucket: string; // making it required\n ACL?: ObjectCannedACL;\n signedUrlExpires?: number;\n}\n\nexport interface DefaultOptions extends S3ClientConfig {\n // TODO Remove this in V5\n accessKeyId?: AwsCredentialIdentity['accessKeyId'];\n secretAccessKey?: AwsCredentialIdentity['secretAccessKey'];\n // Keep this for V5\n credentials?: AwsCredentialIdentity;\n params?: AWSParams;\n [k: string]: any;\n}\n\nexport type InitOptions = (DefaultOptions | { s3Options: DefaultOptions }) & {\n baseUrl?: string;\n rootPath?: string;\n [k: string]: any;\n};\n\nconst assertUrlProtocol = (url: string) => {\n // Regex to test protocol like \"http://\", \"https://\"\n return /^\\w*:\\/\\//.test(url);\n};\n\nconst getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) => {\n if (Object.keys(legacyS3Options).length > 0) {\n process.emitWarning(\n \"S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property.\"\n );\n }\n const credentials = extractCredentials({ s3Options, ...legacyS3Options });\n const config = {\n ...s3Options,\n ...legacyS3Options,\n ...(credentials ? { credentials } : {}),\n };\n\n config.params.ACL = getOr(ObjectCannedACL.public_read, ['params', 'ACL'], config);\n\n return config;\n};\n\nexport default {\n init({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) {\n // TODO V5 change config structure to avoid having to do this\n const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });\n const s3Client = new S3Client(config);\n const filePrefix = rootPath ? `${rootPath.replace(/\\/+$/, '')}/` : '';\n\n const getFileKey = (file: File) => {\n const path = file.path ? `${file.path}/` : '';\n return `${filePrefix}${path}${file.hash}${file.ext}`;\n };\n\n const upload = async (file: File, customParams: Partial<PutObjectCommandInput> = {}) => {\n const fileKey = getFileKey(file);\n const uploadObj = new Upload({\n client: s3Client,\n params: {\n Bucket: config.params.Bucket,\n Key: fileKey,\n Body: file.stream || Buffer.from(file.buffer as any, 'binary'),\n ACL: config.params.ACL,\n ContentType: file.mime,\n ...customParams,\n },\n });\n\n const upload = (await uploadObj.done()) as UploadCommandOutput;\n\n if (assertUrlProtocol(upload.Location)) {\n file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;\n } else {\n // Default protocol to https protocol\n file.url = `https://${upload.Location}`;\n }\n };\n\n return {\n isPrivate() {\n return config.params.ACL === 'private';\n },\n\n async getSignedUrl(file: File, customParams: any): Promise<{ url: string }> {\n // Do not sign the url if it does not come from the same bucket.\n if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {\n return { url: file.url };\n }\n const fileKey = getFileKey(file);\n\n const url = await getSignedUrl(\n s3Client,\n new GetObjectCommand({\n Bucket: config.params.Bucket,\n Key: fileKey,\n ...customParams,\n }),\n {\n expiresIn: getOr(15 * 60, ['params', 'signedUrlExpires'], config),\n }\n );\n\n return { url };\n },\n uploadStream(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n upload(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n delete(file: File, customParams = {}): Promise<DeleteObjectCommandOutput> {\n const command = new DeleteObjectCommand({\n Bucket: config.params.Bucket,\n Key: getFileKey(file),\n ...customParams,\n });\n return s3Client.send(command);\n },\n };\n },\n};\n"],"names":["index","getOr","ObjectCannedACL","S3Client","Upload","upload","getSignedUrl","GetObjectCommand","DeleteObjectCommand"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { ReadStream } from 'node:fs';\nimport { getOr } from 'lodash/fp';\nimport {\n S3Client,\n GetObjectCommand,\n DeleteObjectCommand,\n DeleteObjectCommandOutput,\n PutObjectCommandInput,\n CompleteMultipartUploadCommandOutput,\n AbortMultipartUploadCommandOutput,\n S3ClientConfig,\n ObjectCannedACL,\n} from '@aws-sdk/client-s3';\nimport type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { extractCredentials, isUrlFromBucket } from './utils';\n\nexport interface File {\n name: string;\n alternativeText?: string;\n caption?: string;\n width?: number;\n height?: number;\n formats?: Record<string, unknown>;\n hash: string;\n ext?: string;\n mime: string;\n size: number;\n sizeInBytes: number;\n url: string;\n previewUrl?: string;\n path?: string;\n provider?: string;\n provider_metadata?: Record<string, unknown>;\n stream?: ReadStream;\n buffer?: Buffer;\n}\n\nexport type UploadCommandOutput = (\n | CompleteMultipartUploadCommandOutput\n | AbortMultipartUploadCommandOutput\n) & {\n Location: string;\n};\n\nexport interface AWSParams {\n Bucket: string; // making it required\n ACL?: ObjectCannedACL;\n signedUrlExpires?: number;\n}\n\nexport interface DefaultOptions extends S3ClientConfig {\n // TODO Remove this in V5\n accessKeyId?: AwsCredentialIdentity['accessKeyId'];\n secretAccessKey?: AwsCredentialIdentity['secretAccessKey'];\n // Keep this for V5\n credentials?: AwsCredentialIdentity;\n params?: AWSParams;\n [k: string]: any;\n}\n\nexport type InitOptions = (DefaultOptions | { s3Options: DefaultOptions }) & {\n baseUrl?: string;\n rootPath?: string;\n [k: string]: any;\n};\n\nconst assertUrlProtocol = (url: string) => {\n // Regex to test protocol like \"http://\", \"https://\"\n return /^\\w*:\\/\\//.test(url);\n};\n\nconst getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) => {\n if (Object.keys(legacyS3Options).length > 0) {\n process.emitWarning(\n \"S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property.\"\n );\n }\n const credentials = extractCredentials({ s3Options, ...legacyS3Options });\n const config = {\n ...s3Options,\n ...legacyS3Options,\n ...(credentials ? { credentials } : {}),\n };\n\n config.params.ACL = getOr(ObjectCannedACL.public_read, ['params', 'ACL'], config);\n\n return config;\n};\n\nexport default {\n init({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) {\n // TODO V5 change config structure to avoid having to do this\n const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });\n const s3Client = new S3Client(config);\n const filePrefix = rootPath ? `${rootPath.replace(/\\/+$/, '')}/` : '';\n\n const getFileKey = (file: File) => {\n const path = file.path ? `${file.path}/` : '';\n return `${filePrefix}${path}${file.hash}${file.ext}`;\n };\n\n const upload = async (file: File, customParams: Partial<PutObjectCommandInput> = {}) => {\n const fileKey = getFileKey(file);\n const uploadObj = new Upload({\n client: s3Client,\n params: {\n Bucket: config.params.Bucket,\n Key: fileKey,\n Body: file.stream || Buffer.from(file.buffer as any, 'binary'),\n ACL: config.params.ACL,\n ContentType: file.mime,\n ...customParams,\n },\n });\n\n const upload = (await uploadObj.done()) as UploadCommandOutput;\n\n if (assertUrlProtocol(upload.Location)) {\n file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;\n } else {\n // Default protocol to https protocol\n file.url = `https://${upload.Location}`;\n }\n };\n\n return {\n isPrivate() {\n return config.params.ACL === 'private';\n },\n\n async getSignedUrl(file: File, customParams: any): Promise<{ url: string }> {\n // Do not sign the url if it does not come from the same bucket.\n if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {\n return { url: file.url };\n }\n const fileKey = getFileKey(file);\n\n const url = await getSignedUrl(\n // @ts-expect-error - TODO fix client type\n s3Client,\n new GetObjectCommand({\n Bucket: config.params.Bucket,\n Key: fileKey,\n ...customParams,\n }),\n {\n expiresIn: getOr(15 * 60, ['params', 'signedUrlExpires'], config),\n }\n );\n\n return { url };\n },\n uploadStream(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n upload(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n delete(file: File, customParams = {}): Promise<DeleteObjectCommandOutput> {\n const command = new DeleteObjectCommand({\n Bucket: config.params.Bucket,\n Key: getFileKey(file),\n ...customParams,\n });\n return s3Client.send(command);\n },\n };\n },\n};\n"],"names":["assertUrlProtocol","url","test","getConfig","baseUrl","rootPath","s3Options","legacyS3Options","Object","keys","length","process","emitWarning","credentials","extractCredentials","config","params","ACL","getOr","ObjectCannedACL","public_read","init","s3Client","S3Client","filePrefix","replace","getFileKey","file","path","hash","ext","upload","customParams","fileKey","uploadObj","Upload","client","Bucket","Key","Body","stream","Buffer","from","buffer","ContentType","mime","done","Location","isPrivate","getSignedUrl","isUrlFromBucket","GetObjectCommand","expiresIn","uploadStream","delete","command","DeleteObjectCommand","send"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,162 +1,114 @@
1
- import { getOr } from "lodash/fp";
2
- import { S3Client, GetObjectCommand, DeleteObjectCommand, ObjectCannedACL } from "@aws-sdk/client-s3";
3
- import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
4
- import { Upload } from "@aws-sdk/lib-storage";
5
- const ENDPOINT_PATTERN = /^(.+\.)?s3[.-]([a-z0-9-]+)\./;
6
- function isUrlFromBucket(fileUrl, bucketName, baseUrl = "") {
7
- const url = new URL(fileUrl);
8
- if (baseUrl) {
9
- return false;
10
- }
11
- const { bucket } = getBucketFromAwsUrl(fileUrl);
12
- if (bucket) {
13
- return bucket === bucketName;
14
- }
15
- return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);
16
- }
17
- function getBucketFromAwsUrl(fileUrl) {
18
- const url = new URL(fileUrl);
19
- if (url.protocol === "s3:") {
20
- const bucket = url.host;
21
- if (!bucket) {
22
- return { err: `Invalid S3 url: no bucket: ${url}` };
23
- }
24
- return { bucket };
25
- }
26
- if (!url.host) {
27
- return { err: `Invalid S3 url: no hostname: ${url}` };
28
- }
29
- const matches = url.host.match(ENDPOINT_PATTERN);
30
- if (!matches) {
31
- return { err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}` };
32
- }
33
- const prefix = matches[1];
34
- if (!prefix) {
35
- if (url.pathname === "/") {
36
- return { bucket: null };
37
- }
38
- const index2 = url.pathname.indexOf("/", 1);
39
- if (index2 === -1) {
40
- return { bucket: url.pathname.substring(1) };
41
- }
42
- if (index2 === url.pathname.length - 1) {
43
- return { bucket: url.pathname.substring(1, index2) };
1
+ import { getOr } from 'lodash/fp';
2
+ import { S3Client, GetObjectCommand, DeleteObjectCommand, ObjectCannedACL } from '@aws-sdk/client-s3';
3
+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
4
+ import { Upload } from '@aws-sdk/lib-storage';
5
+ import { isUrlFromBucket, extractCredentials } from './utils.mjs';
6
+
7
+ const assertUrlProtocol = (url)=>{
8
+ // Regex to test protocol like "http://", "https://"
9
+ return /^\w*:\/\//.test(url);
10
+ };
11
+ const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options })=>{
12
+ if (Object.keys(legacyS3Options).length > 0) {
13
+ process.emitWarning("S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property.");
44
14
  }
45
- return { bucket: url.pathname.substring(1, index2) };
46
- }
47
- return { bucket: prefix.substring(0, prefix.length - 1) };
48
- }
49
- const extractCredentials = (options) => {
50
- if (options.accessKeyId && options.secretAccessKey) {
51
- return {
52
- accessKeyId: options.accessKeyId,
53
- secretAccessKey: options.secretAccessKey
15
+ const credentials = extractCredentials({
16
+ s3Options,
17
+ ...legacyS3Options
18
+ });
19
+ const config = {
20
+ ...s3Options,
21
+ ...legacyS3Options,
22
+ ...credentials ? {
23
+ credentials
24
+ } : {}
54
25
  };
55
- }
56
- if (options.s3Options?.accessKeyId && options.s3Options.secretAccessKey) {
57
- process.emitWarning(
58
- "Credentials passed directly to s3Options is deprecated and will be removed in a future release. Please wrap them inside a credentials object."
59
- );
60
- return {
61
- accessKeyId: options.s3Options.accessKeyId,
62
- secretAccessKey: options.s3Options.secretAccessKey
63
- };
64
- }
65
- if (options.s3Options?.credentials) {
66
- return {
67
- accessKeyId: options.s3Options.credentials.accessKeyId,
68
- secretAccessKey: options.s3Options.credentials.secretAccessKey
69
- };
70
- }
71
- return null;
72
- };
73
- const assertUrlProtocol = (url) => {
74
- return /^\w*:\/\//.test(url);
26
+ config.params.ACL = getOr(ObjectCannedACL.public_read, [
27
+ 'params',
28
+ 'ACL'
29
+ ], config);
30
+ return config;
75
31
  };
76
- const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) => {
77
- if (Object.keys(legacyS3Options).length > 0) {
78
- process.emitWarning(
79
- "S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property."
80
- );
81
- }
82
- const credentials = extractCredentials({ s3Options, ...legacyS3Options });
83
- const config = {
84
- ...s3Options,
85
- ...legacyS3Options,
86
- ...credentials ? { credentials } : {}
87
- };
88
- config.params.ACL = getOr(ObjectCannedACL.public_read, ["params", "ACL"], config);
89
- return config;
90
- };
91
- const index = {
92
- init({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
93
- const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });
94
- const s3Client = new S3Client(config);
95
- const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, "")}/` : "";
96
- const getFileKey = (file) => {
97
- const path = file.path ? `${file.path}/` : "";
98
- return `${filePrefix}${path}${file.hash}${file.ext}`;
99
- };
100
- const upload = async (file, customParams = {}) => {
101
- const fileKey = getFileKey(file);
102
- const uploadObj = new Upload({
103
- client: s3Client,
104
- params: {
105
- Bucket: config.params.Bucket,
106
- Key: fileKey,
107
- Body: file.stream || Buffer.from(file.buffer, "binary"),
108
- ACL: config.params.ACL,
109
- ContentType: file.mime,
110
- ...customParams
111
- }
112
- });
113
- const upload2 = await uploadObj.done();
114
- if (assertUrlProtocol(upload2.Location)) {
115
- file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload2.Location;
116
- } else {
117
- file.url = `https://${upload2.Location}`;
118
- }
119
- };
120
- return {
121
- isPrivate() {
122
- return config.params.ACL === "private";
123
- },
124
- async getSignedUrl(file, customParams) {
125
- if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
126
- return { url: file.url };
127
- }
128
- const fileKey = getFileKey(file);
129
- const url = await getSignedUrl(
130
- s3Client,
131
- new GetObjectCommand({
132
- Bucket: config.params.Bucket,
133
- Key: fileKey,
134
- ...customParams
135
- }),
136
- {
137
- expiresIn: getOr(15 * 60, ["params", "signedUrlExpires"], config)
138
- }
139
- );
140
- return { url };
141
- },
142
- uploadStream(file, customParams = {}) {
143
- return upload(file, customParams);
144
- },
145
- upload(file, customParams = {}) {
146
- return upload(file, customParams);
147
- },
148
- delete(file, customParams = {}) {
149
- const command = new DeleteObjectCommand({
150
- Bucket: config.params.Bucket,
151
- Key: getFileKey(file),
152
- ...customParams
32
+ var index = {
33
+ init ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
34
+ // TODO V5 change config structure to avoid having to do this
35
+ const config = getConfig({
36
+ baseUrl,
37
+ rootPath,
38
+ s3Options,
39
+ ...legacyS3Options
153
40
  });
154
- return s3Client.send(command);
155
- }
156
- };
157
- }
158
- };
159
- export {
160
- index as default
41
+ const s3Client = new S3Client(config);
42
+ const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, '')}/` : '';
43
+ const getFileKey = (file)=>{
44
+ const path = file.path ? `${file.path}/` : '';
45
+ return `${filePrefix}${path}${file.hash}${file.ext}`;
46
+ };
47
+ const upload = async (file, customParams = {})=>{
48
+ const fileKey = getFileKey(file);
49
+ const uploadObj = new Upload({
50
+ client: s3Client,
51
+ params: {
52
+ Bucket: config.params.Bucket,
53
+ Key: fileKey,
54
+ Body: file.stream || Buffer.from(file.buffer, 'binary'),
55
+ ACL: config.params.ACL,
56
+ ContentType: file.mime,
57
+ ...customParams
58
+ }
59
+ });
60
+ const upload = await uploadObj.done();
61
+ if (assertUrlProtocol(upload.Location)) {
62
+ file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;
63
+ } else {
64
+ // Default protocol to https protocol
65
+ file.url = `https://${upload.Location}`;
66
+ }
67
+ };
68
+ return {
69
+ isPrivate () {
70
+ return config.params.ACL === 'private';
71
+ },
72
+ async getSignedUrl (file, customParams) {
73
+ // Do not sign the url if it does not come from the same bucket.
74
+ if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
75
+ return {
76
+ url: file.url
77
+ };
78
+ }
79
+ const fileKey = getFileKey(file);
80
+ const url = await getSignedUrl(// @ts-expect-error - TODO fix client type
81
+ s3Client, new GetObjectCommand({
82
+ Bucket: config.params.Bucket,
83
+ Key: fileKey,
84
+ ...customParams
85
+ }), {
86
+ expiresIn: getOr(15 * 60, [
87
+ 'params',
88
+ 'signedUrlExpires'
89
+ ], config)
90
+ });
91
+ return {
92
+ url
93
+ };
94
+ },
95
+ uploadStream (file, customParams = {}) {
96
+ return upload(file, customParams);
97
+ },
98
+ upload (file, customParams = {}) {
99
+ return upload(file, customParams);
100
+ },
101
+ delete (file, customParams = {}) {
102
+ const command = new DeleteObjectCommand({
103
+ Bucket: config.params.Bucket,
104
+ Key: getFileKey(file),
105
+ ...customParams
106
+ });
107
+ return s3Client.send(command);
108
+ }
109
+ };
110
+ }
161
111
  };
112
+
113
+ export { index as default };
162
114
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["import type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport type { InitOptions } from '.';\n\nconst ENDPOINT_PATTERN = /^(.+\\.)?s3[.-]([a-z0-9-]+)\\./;\n\ninterface BucketInfo {\n bucket?: string | null;\n err?: string;\n}\n\nexport function isUrlFromBucket(fileUrl: string, bucketName: string, baseUrl = ''): boolean {\n const url = new URL(fileUrl);\n\n // Check if the file URL is using a base URL (e.g. a CDN).\n // In this case do not sign the URL.\n if (baseUrl) {\n return false;\n }\n\n const { bucket } = getBucketFromAwsUrl(fileUrl);\n\n if (bucket) {\n return bucket === bucketName;\n }\n\n // File URL might be of an S3-compatible provider. (or an invalid URL)\n // In this case, check if the bucket name appears in the URL host or path.\n // e.g. https://minio.example.com/bucket-name/object-key\n // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png\n return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);\n}\n\n/**\n * Parse the bucket name from a URL.\n * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html\n *\n * @param {string} fileUrl - the URL to parse\n * @returns {object} result\n * @returns {string} result.bucket - the bucket name\n * @returns {string} result.err - if any\n */\nfunction getBucketFromAwsUrl(fileUrl: string): BucketInfo {\n const url = new URL(fileUrl);\n\n // S3://<bucket-name>/<key>\n if (url.protocol === 's3:') {\n const bucket = url.host;\n\n if (!bucket) {\n return { err: `Invalid S3 url: no bucket: ${url}` };\n }\n return { bucket };\n }\n\n if (!url.host) {\n return { err: `Invalid S3 url: no hostname: ${url}` };\n }\n\n const matches = url.host.match(ENDPOINT_PATTERN);\n if (!matches) {\n return { err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}` };\n }\n\n const prefix = matches[1];\n // https://s3.amazonaws.com/<bucket-name>\n if (!prefix) {\n if (url.pathname === '/') {\n return { bucket: null };\n }\n\n const index = url.pathname.indexOf('/', 1);\n\n // https://s3.amazonaws.com/<bucket-name>\n if (index === -1) {\n return { bucket: url.pathname.substring(1) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/\n if (index === url.pathname.length - 1) {\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/key\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://<bucket-name>.s3.amazonaws.com/\n return { bucket: prefix.substring(0, prefix.length - 1) };\n}\n\n// TODO Remove this in V5 since we will only support the new config structure\nexport const extractCredentials = (options: InitOptions): AwsCredentialIdentity | null => {\n // legacy\n if (options.accessKeyId && options.secretAccessKey) {\n return {\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n };\n }\n // Legacy\n if (options.s3Options?.accessKeyId && options.s3Options.secretAccessKey) {\n process.emitWarning(\n 'Credentials passed directly to s3Options is deprecated and will be removed in a future release. Please wrap them inside a credentials object.'\n );\n return {\n accessKeyId: options.s3Options.accessKeyId,\n secretAccessKey: options.s3Options.secretAccessKey,\n };\n }\n // V5\n if (options.s3Options?.credentials) {\n return {\n accessKeyId: options.s3Options.credentials.accessKeyId,\n secretAccessKey: options.s3Options.credentials.secretAccessKey,\n };\n }\n return null;\n};\n","import type { ReadStream } from 'node:fs';\nimport { getOr } from 'lodash/fp';\nimport {\n S3Client,\n GetObjectCommand,\n DeleteObjectCommand,\n DeleteObjectCommandOutput,\n PutObjectCommandInput,\n CompleteMultipartUploadCommandOutput,\n AbortMultipartUploadCommandOutput,\n S3ClientConfig,\n ObjectCannedACL,\n} from '@aws-sdk/client-s3';\nimport type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { extractCredentials, isUrlFromBucket } from './utils';\n\nexport interface File {\n name: string;\n alternativeText?: string;\n caption?: string;\n width?: number;\n height?: number;\n formats?: Record<string, unknown>;\n hash: string;\n ext?: string;\n mime: string;\n size: number;\n url: string;\n previewUrl?: string;\n path?: string;\n provider?: string;\n provider_metadata?: Record<string, unknown>;\n stream?: ReadStream;\n buffer?: Buffer;\n}\n\nexport type UploadCommandOutput = (\n | CompleteMultipartUploadCommandOutput\n | AbortMultipartUploadCommandOutput\n) & {\n Location: string;\n};\n\nexport interface AWSParams {\n Bucket: string; // making it required\n ACL?: ObjectCannedACL;\n signedUrlExpires?: number;\n}\n\nexport interface DefaultOptions extends S3ClientConfig {\n // TODO Remove this in V5\n accessKeyId?: AwsCredentialIdentity['accessKeyId'];\n secretAccessKey?: AwsCredentialIdentity['secretAccessKey'];\n // Keep this for V5\n credentials?: AwsCredentialIdentity;\n params?: AWSParams;\n [k: string]: any;\n}\n\nexport type InitOptions = (DefaultOptions | { s3Options: DefaultOptions }) & {\n baseUrl?: string;\n rootPath?: string;\n [k: string]: any;\n};\n\nconst assertUrlProtocol = (url: string) => {\n // Regex to test protocol like \"http://\", \"https://\"\n return /^\\w*:\\/\\//.test(url);\n};\n\nconst getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) => {\n if (Object.keys(legacyS3Options).length > 0) {\n process.emitWarning(\n \"S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property.\"\n );\n }\n const credentials = extractCredentials({ s3Options, ...legacyS3Options });\n const config = {\n ...s3Options,\n ...legacyS3Options,\n ...(credentials ? { credentials } : {}),\n };\n\n config.params.ACL = getOr(ObjectCannedACL.public_read, ['params', 'ACL'], config);\n\n return config;\n};\n\nexport default {\n init({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) {\n // TODO V5 change config structure to avoid having to do this\n const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });\n const s3Client = new S3Client(config);\n const filePrefix = rootPath ? `${rootPath.replace(/\\/+$/, '')}/` : '';\n\n const getFileKey = (file: File) => {\n const path = file.path ? `${file.path}/` : '';\n return `${filePrefix}${path}${file.hash}${file.ext}`;\n };\n\n const upload = async (file: File, customParams: Partial<PutObjectCommandInput> = {}) => {\n const fileKey = getFileKey(file);\n const uploadObj = new Upload({\n client: s3Client,\n params: {\n Bucket: config.params.Bucket,\n Key: fileKey,\n Body: file.stream || Buffer.from(file.buffer as any, 'binary'),\n ACL: config.params.ACL,\n ContentType: file.mime,\n ...customParams,\n },\n });\n\n const upload = (await uploadObj.done()) as UploadCommandOutput;\n\n if (assertUrlProtocol(upload.Location)) {\n file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;\n } else {\n // Default protocol to https protocol\n file.url = `https://${upload.Location}`;\n }\n };\n\n return {\n isPrivate() {\n return config.params.ACL === 'private';\n },\n\n async getSignedUrl(file: File, customParams: any): Promise<{ url: string }> {\n // Do not sign the url if it does not come from the same bucket.\n if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {\n return { url: file.url };\n }\n const fileKey = getFileKey(file);\n\n const url = await getSignedUrl(\n s3Client,\n new GetObjectCommand({\n Bucket: config.params.Bucket,\n Key: fileKey,\n ...customParams,\n }),\n {\n expiresIn: getOr(15 * 60, ['params', 'signedUrlExpires'], config),\n }\n );\n\n return { url };\n },\n uploadStream(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n upload(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n delete(file: File, customParams = {}): Promise<DeleteObjectCommandOutput> {\n const command = new DeleteObjectCommand({\n Bucket: config.params.Bucket,\n Key: getFileKey(file),\n ...customParams,\n });\n return s3Client.send(command);\n },\n };\n },\n};\n"],"names":["index","upload"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import type { ReadStream } from 'node:fs';\nimport { getOr } from 'lodash/fp';\nimport {\n S3Client,\n GetObjectCommand,\n DeleteObjectCommand,\n DeleteObjectCommandOutput,\n PutObjectCommandInput,\n CompleteMultipartUploadCommandOutput,\n AbortMultipartUploadCommandOutput,\n S3ClientConfig,\n ObjectCannedACL,\n} from '@aws-sdk/client-s3';\nimport type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { extractCredentials, isUrlFromBucket } from './utils';\n\nexport interface File {\n name: string;\n alternativeText?: string;\n caption?: string;\n width?: number;\n height?: number;\n formats?: Record<string, unknown>;\n hash: string;\n ext?: string;\n mime: string;\n size: number;\n sizeInBytes: number;\n url: string;\n previewUrl?: string;\n path?: string;\n provider?: string;\n provider_metadata?: Record<string, unknown>;\n stream?: ReadStream;\n buffer?: Buffer;\n}\n\nexport type UploadCommandOutput = (\n | CompleteMultipartUploadCommandOutput\n | AbortMultipartUploadCommandOutput\n) & {\n Location: string;\n};\n\nexport interface AWSParams {\n Bucket: string; // making it required\n ACL?: ObjectCannedACL;\n signedUrlExpires?: number;\n}\n\nexport interface DefaultOptions extends S3ClientConfig {\n // TODO Remove this in V5\n accessKeyId?: AwsCredentialIdentity['accessKeyId'];\n secretAccessKey?: AwsCredentialIdentity['secretAccessKey'];\n // Keep this for V5\n credentials?: AwsCredentialIdentity;\n params?: AWSParams;\n [k: string]: any;\n}\n\nexport type InitOptions = (DefaultOptions | { s3Options: DefaultOptions }) & {\n baseUrl?: string;\n rootPath?: string;\n [k: string]: any;\n};\n\nconst assertUrlProtocol = (url: string) => {\n // Regex to test protocol like \"http://\", \"https://\"\n return /^\\w*:\\/\\//.test(url);\n};\n\nconst getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) => {\n if (Object.keys(legacyS3Options).length > 0) {\n process.emitWarning(\n \"S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property.\"\n );\n }\n const credentials = extractCredentials({ s3Options, ...legacyS3Options });\n const config = {\n ...s3Options,\n ...legacyS3Options,\n ...(credentials ? { credentials } : {}),\n };\n\n config.params.ACL = getOr(ObjectCannedACL.public_read, ['params', 'ACL'], config);\n\n return config;\n};\n\nexport default {\n init({ baseUrl, rootPath, s3Options, ...legacyS3Options }: InitOptions) {\n // TODO V5 change config structure to avoid having to do this\n const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });\n const s3Client = new S3Client(config);\n const filePrefix = rootPath ? `${rootPath.replace(/\\/+$/, '')}/` : '';\n\n const getFileKey = (file: File) => {\n const path = file.path ? `${file.path}/` : '';\n return `${filePrefix}${path}${file.hash}${file.ext}`;\n };\n\n const upload = async (file: File, customParams: Partial<PutObjectCommandInput> = {}) => {\n const fileKey = getFileKey(file);\n const uploadObj = new Upload({\n client: s3Client,\n params: {\n Bucket: config.params.Bucket,\n Key: fileKey,\n Body: file.stream || Buffer.from(file.buffer as any, 'binary'),\n ACL: config.params.ACL,\n ContentType: file.mime,\n ...customParams,\n },\n });\n\n const upload = (await uploadObj.done()) as UploadCommandOutput;\n\n if (assertUrlProtocol(upload.Location)) {\n file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;\n } else {\n // Default protocol to https protocol\n file.url = `https://${upload.Location}`;\n }\n };\n\n return {\n isPrivate() {\n return config.params.ACL === 'private';\n },\n\n async getSignedUrl(file: File, customParams: any): Promise<{ url: string }> {\n // Do not sign the url if it does not come from the same bucket.\n if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {\n return { url: file.url };\n }\n const fileKey = getFileKey(file);\n\n const url = await getSignedUrl(\n // @ts-expect-error - TODO fix client type\n s3Client,\n new GetObjectCommand({\n Bucket: config.params.Bucket,\n Key: fileKey,\n ...customParams,\n }),\n {\n expiresIn: getOr(15 * 60, ['params', 'signedUrlExpires'], config),\n }\n );\n\n return { url };\n },\n uploadStream(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n upload(file: File, customParams = {}) {\n return upload(file, customParams);\n },\n delete(file: File, customParams = {}): Promise<DeleteObjectCommandOutput> {\n const command = new DeleteObjectCommand({\n Bucket: config.params.Bucket,\n Key: getFileKey(file),\n ...customParams,\n });\n return s3Client.send(command);\n },\n };\n },\n};\n"],"names":["assertUrlProtocol","url","test","getConfig","baseUrl","rootPath","s3Options","legacyS3Options","Object","keys","length","process","emitWarning","credentials","extractCredentials","config","params","ACL","getOr","ObjectCannedACL","public_read","init","s3Client","S3Client","filePrefix","replace","getFileKey","file","path","hash","ext","upload","customParams","fileKey","uploadObj","Upload","client","Bucket","Key","Body","stream","Buffer","from","buffer","ContentType","mime","done","Location","isPrivate","getSignedUrl","isUrlFromBucket","GetObjectCommand","expiresIn","uploadStream","delete","command","DeleteObjectCommand","send"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,CAAC;AASrC,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,OAAO,CAoB1F;AA6DD,eAAO,MAAM,kBAAkB,YAAa,WAAW,KAAG,qBAAqB,GAAG,IA0BjF,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,CAAC;AASrC,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,OAAO,CAoB1F;AA4DD,eAAO,MAAM,kBAAkB,YAAa,WAAW,KAAG,qBAAqB,GAAG,IAQjF,CAAC"}
package/dist/utils.js ADDED
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const ENDPOINT_PATTERN = /^(.+\.)?s3[.-]([a-z0-9-]+)\./;
4
+ function isUrlFromBucket(fileUrl, bucketName, baseUrl = '') {
5
+ const url = new URL(fileUrl);
6
+ // Check if the file URL is using a base URL (e.g. a CDN).
7
+ // In this case do not sign the URL.
8
+ if (baseUrl) {
9
+ return false;
10
+ }
11
+ const { bucket } = getBucketFromAwsUrl(fileUrl);
12
+ if (bucket) {
13
+ return bucket === bucketName;
14
+ }
15
+ // File URL might be of an S3-compatible provider. (or an invalid URL)
16
+ // In this case, check if the bucket name appears in the URL host or path.
17
+ // e.g. https://minio.example.com/bucket-name/object-key
18
+ // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png
19
+ return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);
20
+ }
21
+ /**
22
+ * Parse the bucket name from a URL.
23
+ * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html
24
+ *
25
+ * @param {string} fileUrl - the URL to parse
26
+ * @returns {object} result
27
+ * @returns {string} result.bucket - the bucket name
28
+ * @returns {string} result.err - if any
29
+ */ function getBucketFromAwsUrl(fileUrl) {
30
+ const url = new URL(fileUrl);
31
+ // S3://<bucket-name>/<key>
32
+ if (url.protocol === 's3:') {
33
+ const bucket = url.host;
34
+ if (!bucket) {
35
+ return {
36
+ err: `Invalid S3 url: no bucket: ${url}`
37
+ };
38
+ }
39
+ return {
40
+ bucket
41
+ };
42
+ }
43
+ if (!url.host) {
44
+ return {
45
+ err: `Invalid S3 url: no hostname: ${url}`
46
+ };
47
+ }
48
+ const matches = url.host.match(ENDPOINT_PATTERN);
49
+ if (!matches) {
50
+ return {
51
+ err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}`
52
+ };
53
+ }
54
+ const prefix = matches[1];
55
+ // https://s3.amazonaws.com/<bucket-name>
56
+ if (!prefix) {
57
+ if (url.pathname === '/') {
58
+ return {
59
+ bucket: null
60
+ };
61
+ }
62
+ const index = url.pathname.indexOf('/', 1);
63
+ // https://s3.amazonaws.com/<bucket-name>
64
+ if (index === -1) {
65
+ return {
66
+ bucket: url.pathname.substring(1)
67
+ };
68
+ }
69
+ // https://s3.amazonaws.com/<bucket-name>/
70
+ if (index === url.pathname.length - 1) {
71
+ return {
72
+ bucket: url.pathname.substring(1, index)
73
+ };
74
+ }
75
+ // https://s3.amazonaws.com/<bucket-name>/key
76
+ return {
77
+ bucket: url.pathname.substring(1, index)
78
+ };
79
+ }
80
+ // https://<bucket-name>.s3.amazonaws.com/
81
+ return {
82
+ bucket: prefix.substring(0, prefix.length - 1)
83
+ };
84
+ }
85
+ const extractCredentials = (options)=>{
86
+ if (options.s3Options?.credentials) {
87
+ return {
88
+ accessKeyId: options.s3Options.credentials.accessKeyId,
89
+ secretAccessKey: options.s3Options.credentials.secretAccessKey
90
+ };
91
+ }
92
+ return null;
93
+ };
94
+
95
+ exports.extractCredentials = extractCredentials;
96
+ exports.isUrlFromBucket = isUrlFromBucket;
97
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport type { InitOptions } from '.';\n\nconst ENDPOINT_PATTERN = /^(.+\\.)?s3[.-]([a-z0-9-]+)\\./;\n\ninterface BucketInfo {\n bucket?: string | null;\n err?: string;\n}\n\nexport function isUrlFromBucket(fileUrl: string, bucketName: string, baseUrl = ''): boolean {\n const url = new URL(fileUrl);\n\n // Check if the file URL is using a base URL (e.g. a CDN).\n // In this case do not sign the URL.\n if (baseUrl) {\n return false;\n }\n\n const { bucket } = getBucketFromAwsUrl(fileUrl);\n\n if (bucket) {\n return bucket === bucketName;\n }\n\n // File URL might be of an S3-compatible provider. (or an invalid URL)\n // In this case, check if the bucket name appears in the URL host or path.\n // e.g. https://minio.example.com/bucket-name/object-key\n // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png\n return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);\n}\n\n/**\n * Parse the bucket name from a URL.\n * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html\n *\n * @param {string} fileUrl - the URL to parse\n * @returns {object} result\n * @returns {string} result.bucket - the bucket name\n * @returns {string} result.err - if any\n */\nfunction getBucketFromAwsUrl(fileUrl: string): BucketInfo {\n const url = new URL(fileUrl);\n\n // S3://<bucket-name>/<key>\n if (url.protocol === 's3:') {\n const bucket = url.host;\n\n if (!bucket) {\n return { err: `Invalid S3 url: no bucket: ${url}` };\n }\n return { bucket };\n }\n\n if (!url.host) {\n return { err: `Invalid S3 url: no hostname: ${url}` };\n }\n\n const matches = url.host.match(ENDPOINT_PATTERN);\n if (!matches) {\n return { err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}` };\n }\n\n const prefix = matches[1];\n // https://s3.amazonaws.com/<bucket-name>\n if (!prefix) {\n if (url.pathname === '/') {\n return { bucket: null };\n }\n\n const index = url.pathname.indexOf('/', 1);\n\n // https://s3.amazonaws.com/<bucket-name>\n if (index === -1) {\n return { bucket: url.pathname.substring(1) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/\n if (index === url.pathname.length - 1) {\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/key\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://<bucket-name>.s3.amazonaws.com/\n return { bucket: prefix.substring(0, prefix.length - 1) };\n}\n\nexport const extractCredentials = (options: InitOptions): AwsCredentialIdentity | null => {\n if (options.s3Options?.credentials) {\n return {\n accessKeyId: options.s3Options.credentials.accessKeyId,\n secretAccessKey: options.s3Options.credentials.secretAccessKey,\n };\n }\n return null;\n};\n"],"names":["ENDPOINT_PATTERN","isUrlFromBucket","fileUrl","bucketName","baseUrl","url","URL","bucket","getBucketFromAwsUrl","host","startsWith","pathname","includes","protocol","err","matches","match","prefix","index","indexOf","substring","length","extractCredentials","options","s3Options","credentials","accessKeyId","secretAccessKey"],"mappings":";;AAGA,MAAMA,gBAAmB,GAAA,8BAAA;AAOlB,SAASC,eAAgBC,CAAAA,OAAe,EAAEC,UAAkB,EAAEC,UAAU,EAAE,EAAA;IAC/E,MAAMC,GAAAA,GAAM,IAAIC,GAAIJ,CAAAA,OAAAA,CAAAA;;;AAIpB,IAAA,IAAIE,OAAS,EAAA;QACX,OAAO,KAAA;AACT;AAEA,IAAA,MAAM,EAAEG,MAAM,EAAE,GAAGC,mBAAoBN,CAAAA,OAAAA,CAAAA;AAEvC,IAAA,IAAIK,MAAQ,EAAA;AACV,QAAA,OAAOA,MAAWJ,KAAAA,UAAAA;AACpB;;;;;IAMA,OAAOE,GAAAA,CAAII,IAAI,CAACC,UAAU,CAAC,CAAC,EAAEP,WAAW,CAAC,CAAC,KAAKE,GAAIM,CAAAA,QAAQ,CAACC,QAAQ,CAAC,CAAC,CAAC,EAAET,UAAW,CAAA,CAAC,CAAC,CAAA;AACzF;AAEA;;;;;;;;IASA,SAASK,oBAAoBN,OAAe,EAAA;IAC1C,MAAMG,GAAAA,GAAM,IAAIC,GAAIJ,CAAAA,OAAAA,CAAAA;;IAGpB,IAAIG,GAAAA,CAAIQ,QAAQ,KAAK,KAAO,EAAA;QAC1B,MAAMN,MAAAA,GAASF,IAAII,IAAI;AAEvB,QAAA,IAAI,CAACF,MAAQ,EAAA;YACX,OAAO;AAAEO,gBAAAA,GAAAA,EAAK,CAAC,2BAA2B,EAAET,GAAAA,CAAI;AAAE,aAAA;AACpD;QACA,OAAO;AAAEE,YAAAA;AAAO,SAAA;AAClB;IAEA,IAAI,CAACF,GAAII,CAAAA,IAAI,EAAE;QACb,OAAO;AAAEK,YAAAA,GAAAA,EAAK,CAAC,6BAA6B,EAAET,GAAAA,CAAI;AAAE,SAAA;AACtD;AAEA,IAAA,MAAMU,OAAUV,GAAAA,GAAAA,CAAII,IAAI,CAACO,KAAK,CAAChB,gBAAAA,CAAAA;AAC/B,IAAA,IAAI,CAACe,OAAS,EAAA;QACZ,OAAO;AAAED,YAAAA,GAAAA,EAAK,CAAC,oEAAoE,EAAET,GAAAA,CAAI;AAAE,SAAA;AAC7F;IAEA,MAAMY,MAAAA,GAASF,OAAO,CAAC,CAAE,CAAA;;AAEzB,IAAA,IAAI,CAACE,MAAQ,EAAA;QACX,IAAIZ,GAAAA,CAAIM,QAAQ,KAAK,GAAK,EAAA;YACxB,OAAO;gBAAEJ,MAAQ,EAAA;AAAK,aAAA;AACxB;AAEA,QAAA,MAAMW,QAAQb,GAAIM,CAAAA,QAAQ,CAACQ,OAAO,CAAC,GAAK,EAAA,CAAA,CAAA;;QAGxC,IAAID,KAAAA,KAAU,CAAC,CAAG,EAAA;YAChB,OAAO;AAAEX,gBAAAA,MAAAA,EAAQF,GAAIM,CAAAA,QAAQ,CAACS,SAAS,CAAC,CAAA;AAAG,aAAA;AAC7C;;AAGA,QAAA,IAAIF,UAAUb,GAAIM,CAAAA,QAAQ,CAACU,MAAM,GAAG,CAAG,EAAA;YACrC,OAAO;AAAEd,gBAAAA,MAAAA,EAAQF,GAAIM,CAAAA,QAAQ,CAACS,SAAS,CAAC,CAAGF,EAAAA,KAAAA;AAAO,aAAA;AACpD;;QAGA,OAAO;AAAEX,YAAAA,MAAAA,EAAQF,GAAIM,CAAAA,QAAQ,CAACS,SAAS,CAAC,CAAGF,EAAAA,KAAAA;AAAO,SAAA;AACpD;;IAGA,OAAO;AAAEX,QAAAA,MAAAA,EAAQU,OAAOG,SAAS,CAAC,CAAGH,EAAAA,MAAAA,CAAOI,MAAM,GAAG,CAAA;AAAG,KAAA;AAC1D;AAEO,MAAMC,qBAAqB,CAACC,OAAAA,GAAAA;IACjC,IAAIA,OAAAA,CAAQC,SAAS,EAAEC,WAAa,EAAA;QAClC,OAAO;AACLC,YAAAA,WAAAA,EAAaH,OAAQC,CAAAA,SAAS,CAACC,WAAW,CAACC,WAAW;AACtDC,YAAAA,eAAAA,EAAiBJ,OAAQC,CAAAA,SAAS,CAACC,WAAW,CAACE;AACjD,SAAA;AACF;IACA,OAAO,IAAA;AACT;;;;;"}
package/dist/utils.mjs ADDED
@@ -0,0 +1,94 @@
1
+ const ENDPOINT_PATTERN = /^(.+\.)?s3[.-]([a-z0-9-]+)\./;
2
+ function isUrlFromBucket(fileUrl, bucketName, baseUrl = '') {
3
+ const url = new URL(fileUrl);
4
+ // Check if the file URL is using a base URL (e.g. a CDN).
5
+ // In this case do not sign the URL.
6
+ if (baseUrl) {
7
+ return false;
8
+ }
9
+ const { bucket } = getBucketFromAwsUrl(fileUrl);
10
+ if (bucket) {
11
+ return bucket === bucketName;
12
+ }
13
+ // File URL might be of an S3-compatible provider. (or an invalid URL)
14
+ // In this case, check if the bucket name appears in the URL host or path.
15
+ // e.g. https://minio.example.com/bucket-name/object-key
16
+ // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png
17
+ return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);
18
+ }
19
+ /**
20
+ * Parse the bucket name from a URL.
21
+ * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html
22
+ *
23
+ * @param {string} fileUrl - the URL to parse
24
+ * @returns {object} result
25
+ * @returns {string} result.bucket - the bucket name
26
+ * @returns {string} result.err - if any
27
+ */ function getBucketFromAwsUrl(fileUrl) {
28
+ const url = new URL(fileUrl);
29
+ // S3://<bucket-name>/<key>
30
+ if (url.protocol === 's3:') {
31
+ const bucket = url.host;
32
+ if (!bucket) {
33
+ return {
34
+ err: `Invalid S3 url: no bucket: ${url}`
35
+ };
36
+ }
37
+ return {
38
+ bucket
39
+ };
40
+ }
41
+ if (!url.host) {
42
+ return {
43
+ err: `Invalid S3 url: no hostname: ${url}`
44
+ };
45
+ }
46
+ const matches = url.host.match(ENDPOINT_PATTERN);
47
+ if (!matches) {
48
+ return {
49
+ err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}`
50
+ };
51
+ }
52
+ const prefix = matches[1];
53
+ // https://s3.amazonaws.com/<bucket-name>
54
+ if (!prefix) {
55
+ if (url.pathname === '/') {
56
+ return {
57
+ bucket: null
58
+ };
59
+ }
60
+ const index = url.pathname.indexOf('/', 1);
61
+ // https://s3.amazonaws.com/<bucket-name>
62
+ if (index === -1) {
63
+ return {
64
+ bucket: url.pathname.substring(1)
65
+ };
66
+ }
67
+ // https://s3.amazonaws.com/<bucket-name>/
68
+ if (index === url.pathname.length - 1) {
69
+ return {
70
+ bucket: url.pathname.substring(1, index)
71
+ };
72
+ }
73
+ // https://s3.amazonaws.com/<bucket-name>/key
74
+ return {
75
+ bucket: url.pathname.substring(1, index)
76
+ };
77
+ }
78
+ // https://<bucket-name>.s3.amazonaws.com/
79
+ return {
80
+ bucket: prefix.substring(0, prefix.length - 1)
81
+ };
82
+ }
83
+ const extractCredentials = (options)=>{
84
+ if (options.s3Options?.credentials) {
85
+ return {
86
+ accessKeyId: options.s3Options.credentials.accessKeyId,
87
+ secretAccessKey: options.s3Options.credentials.secretAccessKey
88
+ };
89
+ }
90
+ return null;
91
+ };
92
+
93
+ export { extractCredentials, isUrlFromBucket };
94
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.mjs","sources":["../src/utils.ts"],"sourcesContent":["import type { AwsCredentialIdentity } from '@aws-sdk/types';\nimport type { InitOptions } from '.';\n\nconst ENDPOINT_PATTERN = /^(.+\\.)?s3[.-]([a-z0-9-]+)\\./;\n\ninterface BucketInfo {\n bucket?: string | null;\n err?: string;\n}\n\nexport function isUrlFromBucket(fileUrl: string, bucketName: string, baseUrl = ''): boolean {\n const url = new URL(fileUrl);\n\n // Check if the file URL is using a base URL (e.g. a CDN).\n // In this case do not sign the URL.\n if (baseUrl) {\n return false;\n }\n\n const { bucket } = getBucketFromAwsUrl(fileUrl);\n\n if (bucket) {\n return bucket === bucketName;\n }\n\n // File URL might be of an S3-compatible provider. (or an invalid URL)\n // In this case, check if the bucket name appears in the URL host or path.\n // e.g. https://minio.example.com/bucket-name/object-key\n // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png\n return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);\n}\n\n/**\n * Parse the bucket name from a URL.\n * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html\n *\n * @param {string} fileUrl - the URL to parse\n * @returns {object} result\n * @returns {string} result.bucket - the bucket name\n * @returns {string} result.err - if any\n */\nfunction getBucketFromAwsUrl(fileUrl: string): BucketInfo {\n const url = new URL(fileUrl);\n\n // S3://<bucket-name>/<key>\n if (url.protocol === 's3:') {\n const bucket = url.host;\n\n if (!bucket) {\n return { err: `Invalid S3 url: no bucket: ${url}` };\n }\n return { bucket };\n }\n\n if (!url.host) {\n return { err: `Invalid S3 url: no hostname: ${url}` };\n }\n\n const matches = url.host.match(ENDPOINT_PATTERN);\n if (!matches) {\n return { err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}` };\n }\n\n const prefix = matches[1];\n // https://s3.amazonaws.com/<bucket-name>\n if (!prefix) {\n if (url.pathname === '/') {\n return { bucket: null };\n }\n\n const index = url.pathname.indexOf('/', 1);\n\n // https://s3.amazonaws.com/<bucket-name>\n if (index === -1) {\n return { bucket: url.pathname.substring(1) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/\n if (index === url.pathname.length - 1) {\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://s3.amazonaws.com/<bucket-name>/key\n return { bucket: url.pathname.substring(1, index) };\n }\n\n // https://<bucket-name>.s3.amazonaws.com/\n return { bucket: prefix.substring(0, prefix.length - 1) };\n}\n\nexport const extractCredentials = (options: InitOptions): AwsCredentialIdentity | null => {\n if (options.s3Options?.credentials) {\n return {\n accessKeyId: options.s3Options.credentials.accessKeyId,\n secretAccessKey: options.s3Options.credentials.secretAccessKey,\n };\n }\n return null;\n};\n"],"names":["ENDPOINT_PATTERN","isUrlFromBucket","fileUrl","bucketName","baseUrl","url","URL","bucket","getBucketFromAwsUrl","host","startsWith","pathname","includes","protocol","err","matches","match","prefix","index","indexOf","substring","length","extractCredentials","options","s3Options","credentials","accessKeyId","secretAccessKey"],"mappings":"AAGA,MAAMA,gBAAmB,GAAA,8BAAA;AAOlB,SAASC,eAAgBC,CAAAA,OAAe,EAAEC,UAAkB,EAAEC,UAAU,EAAE,EAAA;IAC/E,MAAMC,GAAAA,GAAM,IAAIC,GAAIJ,CAAAA,OAAAA,CAAAA;;;AAIpB,IAAA,IAAIE,OAAS,EAAA;QACX,OAAO,KAAA;AACT;AAEA,IAAA,MAAM,EAAEG,MAAM,EAAE,GAAGC,mBAAoBN,CAAAA,OAAAA,CAAAA;AAEvC,IAAA,IAAIK,MAAQ,EAAA;AACV,QAAA,OAAOA,MAAWJ,KAAAA,UAAAA;AACpB;;;;;IAMA,OAAOE,GAAAA,CAAII,IAAI,CAACC,UAAU,CAAC,CAAC,EAAEP,WAAW,CAAC,CAAC,KAAKE,GAAIM,CAAAA,QAAQ,CAACC,QAAQ,CAAC,CAAC,CAAC,EAAET,UAAW,CAAA,CAAC,CAAC,CAAA;AACzF;AAEA;;;;;;;;IASA,SAASK,oBAAoBN,OAAe,EAAA;IAC1C,MAAMG,GAAAA,GAAM,IAAIC,GAAIJ,CAAAA,OAAAA,CAAAA;;IAGpB,IAAIG,GAAAA,CAAIQ,QAAQ,KAAK,KAAO,EAAA;QAC1B,MAAMN,MAAAA,GAASF,IAAII,IAAI;AAEvB,QAAA,IAAI,CAACF,MAAQ,EAAA;YACX,OAAO;AAAEO,gBAAAA,GAAAA,EAAK,CAAC,2BAA2B,EAAET,GAAAA,CAAI;AAAE,aAAA;AACpD;QACA,OAAO;AAAEE,YAAAA;AAAO,SAAA;AAClB;IAEA,IAAI,CAACF,GAAII,CAAAA,IAAI,EAAE;QACb,OAAO;AAAEK,YAAAA,GAAAA,EAAK,CAAC,6BAA6B,EAAET,GAAAA,CAAI;AAAE,SAAA;AACtD;AAEA,IAAA,MAAMU,OAAUV,GAAAA,GAAAA,CAAII,IAAI,CAACO,KAAK,CAAChB,gBAAAA,CAAAA;AAC/B,IAAA,IAAI,CAACe,OAAS,EAAA;QACZ,OAAO;AAAED,YAAAA,GAAAA,EAAK,CAAC,oEAAoE,EAAET,GAAAA,CAAI;AAAE,SAAA;AAC7F;IAEA,MAAMY,MAAAA,GAASF,OAAO,CAAC,CAAE,CAAA;;AAEzB,IAAA,IAAI,CAACE,MAAQ,EAAA;QACX,IAAIZ,GAAAA,CAAIM,QAAQ,KAAK,GAAK,EAAA;YACxB,OAAO;gBAAEJ,MAAQ,EAAA;AAAK,aAAA;AACxB;AAEA,QAAA,MAAMW,QAAQb,GAAIM,CAAAA,QAAQ,CAACQ,OAAO,CAAC,GAAK,EAAA,CAAA,CAAA;;QAGxC,IAAID,KAAAA,KAAU,CAAC,CAAG,EAAA;YAChB,OAAO;AAAEX,gBAAAA,MAAAA,EAAQF,GAAIM,CAAAA,QAAQ,CAACS,SAAS,CAAC,CAAA;AAAG,aAAA;AAC7C;;AAGA,QAAA,IAAIF,UAAUb,GAAIM,CAAAA,QAAQ,CAACU,MAAM,GAAG,CAAG,EAAA;YACrC,OAAO;AAAEd,gBAAAA,MAAAA,EAAQF,GAAIM,CAAAA,QAAQ,CAACS,SAAS,CAAC,CAAGF,EAAAA,KAAAA;AAAO,aAAA;AACpD;;QAGA,OAAO;AAAEX,YAAAA,MAAAA,EAAQF,GAAIM,CAAAA,QAAQ,CAACS,SAAS,CAAC,CAAGF,EAAAA,KAAAA;AAAO,SAAA;AACpD;;IAGA,OAAO;AAAEX,QAAAA,MAAAA,EAAQU,OAAOG,SAAS,CAAC,CAAGH,EAAAA,MAAAA,CAAOI,MAAM,GAAG,CAAA;AAAG,KAAA;AAC1D;AAEO,MAAMC,qBAAqB,CAACC,OAAAA,GAAAA;IACjC,IAAIA,OAAAA,CAAQC,SAAS,EAAEC,WAAa,EAAA;QAClC,OAAO;AACLC,YAAAA,WAAAA,EAAaH,OAAQC,CAAAA,SAAS,CAACC,WAAW,CAACC,WAAW;AACtDC,YAAAA,eAAAA,EAAiBJ,OAAQC,CAAAA,SAAS,CAACC,WAAW,CAACE;AACjD,SAAA;AACF;IACA,OAAO,IAAA;AACT;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/provider-upload-aws-s3",
3
- "version": "0.0.0-next.e1ede8c55a0e1e22ce20137bf238fc374bd5dd51",
3
+ "version": "0.0.0-next.e21fe90bf2ab9906267ea6e6ca620bdcc729906c",
4
4
  "description": "AWS S3 provider for strapi upload",
5
5
  "keywords": [
6
6
  "upload",
@@ -34,32 +34,32 @@
34
34
  "source": "./src/index.ts",
35
35
  "types": "./dist/index.d.ts",
36
36
  "files": [
37
- "./dist"
37
+ "dist/"
38
38
  ],
39
39
  "scripts": {
40
- "build": "pack-up build",
40
+ "build": "run -T npm-run-all clean --parallel build:code build:types",
41
+ "build:code": "run -T rollup -c",
42
+ "build:types": "run -T tsc -p tsconfig.build.json --emitDeclarationOnly",
41
43
  "clean": "run -T rimraf ./dist",
42
44
  "lint": "run -T eslint .",
43
45
  "test:unit": "run -T jest",
44
46
  "test:unit:watch": "run -T jest --watch",
45
- "watch": "pack-up watch"
47
+ "watch": "run -T rollup -c -w"
46
48
  },
47
49
  "dependencies": {
48
- "@aws-sdk/client-s3": "3.433.0",
50
+ "@aws-sdk/client-s3": "3.600.0",
49
51
  "@aws-sdk/lib-storage": "3.433.0",
50
52
  "@aws-sdk/s3-request-presigner": "3.433.0",
51
53
  "@aws-sdk/types": "3.433.0",
52
54
  "lodash": "4.17.21"
53
55
  },
54
56
  "devDependencies": {
55
- "@strapi/pack-up": "0.0.0-next.e1ede8c55a0e1e22ce20137bf238fc374bd5dd51",
56
57
  "@types/jest": "29.5.2",
57
- "eslint-config-custom": "0.0.0-next.e1ede8c55a0e1e22ce20137bf238fc374bd5dd51",
58
- "tsconfig": "0.0.0-next.e1ede8c55a0e1e22ce20137bf238fc374bd5dd51"
58
+ "eslint-config-custom": "0.0.0-next.e21fe90bf2ab9906267ea6e6ca620bdcc729906c",
59
+ "tsconfig": "0.0.0-next.e21fe90bf2ab9906267ea6e6ca620bdcc729906c"
59
60
  },
60
61
  "engines": {
61
- "node": ">=18.0.0 <=20.x.x",
62
+ "node": ">=18.0.0 <=22.x.x",
62
63
  "npm": ">=6.0.0"
63
- },
64
- "gitHead": "e1ede8c55a0e1e22ce20137bf238fc374bd5dd51"
64
+ }
65
65
  }