@strapi/provider-upload-aws-s3 0.0.0-next.39c0188c3aa01bec7b64b948211571d5159e811d → 0.0.0-next.3a1d87a9c3b1d4d89f741c6ecd7f501230fd8d76

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.js CHANGED
@@ -1,207 +1,147 @@
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
-
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");
8
6
  const ENDPOINT_PATTERN = /^(.+\.)?s3[.-]([a-z0-9-]+)\./;
9
- function isUrlFromBucket(fileUrl, bucketName, baseUrl = '') {
10
- const url = new URL(fileUrl);
11
- // Check if the file URL is using a base URL (e.g. a CDN).
12
- // In this case do not sign the URL.
13
- if (baseUrl) {
14
- return false;
15
- }
16
- const { bucket } = getBucketFromAwsUrl(fileUrl);
17
- if (bucket) {
18
- return bucket === bucketName;
19
- }
20
- // File URL might be of an S3-compatible provider. (or an invalid URL)
21
- // In this case, check if the bucket name appears in the URL host or path.
22
- // e.g. https://minio.example.com/bucket-name/object-key
23
- // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png
24
- return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);
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}/`);
25
17
  }
26
- /**
27
- * Parse the bucket name from a URL.
28
- * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html
29
- *
30
- * @param {string} fileUrl - the URL to parse
31
- * @returns {object} result
32
- * @returns {string} result.bucket - the bucket name
33
- * @returns {string} result.err - if any
34
- */ function getBucketFromAwsUrl(fileUrl) {
35
- const url = new URL(fileUrl);
36
- // S3://<bucket-name>/<key>
37
- if (url.protocol === 's3:') {
38
- const bucket = url.host;
39
- if (!bucket) {
40
- return {
41
- err: `Invalid S3 url: no bucket: ${url}`
42
- };
43
- }
44
- return {
45
- bucket
46
- };
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}` };
47
24
  }
48
- if (!url.host) {
49
- return {
50
- err: `Invalid S3 url: no hostname: ${url}`
51
- };
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 };
52
38
  }
53
- const matches = url.host.match(ENDPOINT_PATTERN);
54
- if (!matches) {
55
- return {
56
- err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}`
57
- };
39
+ const index2 = url.pathname.indexOf("/", 1);
40
+ if (index2 === -1) {
41
+ return { bucket: url.pathname.substring(1) };
58
42
  }
59
- const prefix = matches[1];
60
- // https://s3.amazonaws.com/<bucket-name>
61
- if (!prefix) {
62
- if (url.pathname === '/') {
63
- return {
64
- bucket: null
65
- };
66
- }
67
- const index = url.pathname.indexOf('/', 1);
68
- // https://s3.amazonaws.com/<bucket-name>
69
- if (index === -1) {
70
- return {
71
- bucket: url.pathname.substring(1)
72
- };
73
- }
74
- // https://s3.amazonaws.com/<bucket-name>/
75
- if (index === url.pathname.length - 1) {
76
- return {
77
- bucket: url.pathname.substring(1, index)
78
- };
79
- }
80
- // https://s3.amazonaws.com/<bucket-name>/key
81
- return {
82
- bucket: url.pathname.substring(1, index)
83
- };
43
+ if (index2 === url.pathname.length - 1) {
44
+ return { bucket: url.pathname.substring(1, index2) };
84
45
  }
85
- // https://<bucket-name>.s3.amazonaws.com/
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.s3Options?.credentials) {
86
52
  return {
87
- bucket: prefix.substring(0, prefix.length - 1)
53
+ accessKeyId: options.s3Options.credentials.accessKeyId,
54
+ secretAccessKey: options.s3Options.credentials.secretAccessKey
88
55
  };
89
- }
90
- const extractCredentials = (options)=>{
91
- if (options.s3Options?.credentials) {
92
- return {
93
- accessKeyId: options.s3Options.credentials.accessKeyId,
94
- secretAccessKey: options.s3Options.credentials.secretAccessKey
95
- };
96
- }
97
- return null;
56
+ }
57
+ return null;
98
58
  };
99
-
100
- const assertUrlProtocol = (url)=>{
101
- // Regex to test protocol like "http://", "https://"
102
- return /^\w*:\/\//.test(url);
59
+ const assertUrlProtocol = (url) => {
60
+ return /^\w*:\/\//.test(url);
103
61
  };
104
- const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options })=>{
105
- if (Object.keys(legacyS3Options).length > 0) {
106
- 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.");
107
- }
108
- const credentials = extractCredentials({
109
- s3Options,
110
- ...legacyS3Options
111
- });
112
- const config = {
113
- ...s3Options,
114
- ...legacyS3Options,
115
- ...credentials ? {
116
- credentials
117
- } : {}
118
- };
119
- config.params.ACL = fp.getOr(clientS3.ObjectCannedACL.public_read, [
120
- 'params',
121
- 'ACL'
122
- ], config);
123
- return config;
62
+ const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) => {
63
+ if (Object.keys(legacyS3Options).length > 0) {
64
+ process.emitWarning(
65
+ "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."
66
+ );
67
+ }
68
+ const credentials = extractCredentials({ s3Options, ...legacyS3Options });
69
+ const config = {
70
+ ...s3Options,
71
+ ...legacyS3Options,
72
+ ...credentials ? { credentials } : {}
73
+ };
74
+ config.params.ACL = fp.getOr(clientS3.ObjectCannedACL.public_read, ["params", "ACL"], config);
75
+ return config;
124
76
  };
125
- var index = {
126
- init ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
127
- // TODO V5 change config structure to avoid having to do this
128
- const config = getConfig({
129
- baseUrl,
130
- rootPath,
131
- s3Options,
132
- ...legacyS3Options
77
+ const index = {
78
+ init({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
79
+ const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });
80
+ const s3Client = new clientS3.S3Client(config);
81
+ const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, "")}/` : "";
82
+ const getFileKey = (file) => {
83
+ const path = file.path ? `${file.path}/` : "";
84
+ return `${filePrefix}${path}${file.hash}${file.ext}`;
85
+ };
86
+ const upload = async (file, customParams = {}) => {
87
+ const fileKey = getFileKey(file);
88
+ const uploadObj = new libStorage.Upload({
89
+ client: s3Client,
90
+ params: {
91
+ Bucket: config.params.Bucket,
92
+ Key: fileKey,
93
+ Body: file.stream || Buffer.from(file.buffer, "binary"),
94
+ ACL: config.params.ACL,
95
+ ContentType: file.mime,
96
+ ...customParams
97
+ }
98
+ });
99
+ const upload2 = await uploadObj.done();
100
+ if (assertUrlProtocol(upload2.Location)) {
101
+ file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload2.Location;
102
+ } else {
103
+ file.url = `https://${upload2.Location}`;
104
+ }
105
+ };
106
+ return {
107
+ isPrivate() {
108
+ return config.params.ACL === "private";
109
+ },
110
+ async getSignedUrl(file, customParams) {
111
+ if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
112
+ return { url: file.url };
113
+ }
114
+ const fileKey = getFileKey(file);
115
+ const url = await s3RequestPresigner.getSignedUrl(
116
+ // @ts-expect-error - TODO fix client type
117
+ s3Client,
118
+ new clientS3.GetObjectCommand({
119
+ Bucket: config.params.Bucket,
120
+ Key: fileKey,
121
+ ...customParams
122
+ }),
123
+ {
124
+ expiresIn: fp.getOr(15 * 60, ["params", "signedUrlExpires"], config)
125
+ }
126
+ );
127
+ return { url };
128
+ },
129
+ uploadStream(file, customParams = {}) {
130
+ return upload(file, customParams);
131
+ },
132
+ upload(file, customParams = {}) {
133
+ return upload(file, customParams);
134
+ },
135
+ delete(file, customParams = {}) {
136
+ const command = new clientS3.DeleteObjectCommand({
137
+ Bucket: config.params.Bucket,
138
+ Key: getFileKey(file),
139
+ ...customParams
133
140
  });
134
- const s3Client = new clientS3.S3Client(config);
135
- const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, '')}/` : '';
136
- const getFileKey = (file)=>{
137
- const path = file.path ? `${file.path}/` : '';
138
- return `${filePrefix}${path}${file.hash}${file.ext}`;
139
- };
140
- const upload = async (file, customParams = {})=>{
141
- const fileKey = getFileKey(file);
142
- const uploadObj = new libStorage.Upload({
143
- client: s3Client,
144
- params: {
145
- Bucket: config.params.Bucket,
146
- Key: fileKey,
147
- Body: file.stream || Buffer.from(file.buffer, 'binary'),
148
- ACL: config.params.ACL,
149
- ContentType: file.mime,
150
- ...customParams
151
- }
152
- });
153
- const upload = await uploadObj.done();
154
- if (assertUrlProtocol(upload.Location)) {
155
- file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;
156
- } else {
157
- // Default protocol to https protocol
158
- file.url = `https://${upload.Location}`;
159
- }
160
- };
161
- return {
162
- isPrivate () {
163
- return config.params.ACL === 'private';
164
- },
165
- async getSignedUrl (file, customParams) {
166
- // Do not sign the url if it does not come from the same bucket.
167
- if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
168
- return {
169
- url: file.url
170
- };
171
- }
172
- const fileKey = getFileKey(file);
173
- const url = await s3RequestPresigner.getSignedUrl(// @ts-expect-error - TODO fix client type
174
- s3Client, new clientS3.GetObjectCommand({
175
- Bucket: config.params.Bucket,
176
- Key: fileKey,
177
- ...customParams
178
- }), {
179
- expiresIn: fp.getOr(15 * 60, [
180
- 'params',
181
- 'signedUrlExpires'
182
- ], config)
183
- });
184
- return {
185
- url
186
- };
187
- },
188
- uploadStream (file, customParams = {}) {
189
- return upload(file, customParams);
190
- },
191
- upload (file, customParams = {}) {
192
- return upload(file, customParams);
193
- },
194
- delete (file, customParams = {}) {
195
- const command = new clientS3.DeleteObjectCommand({
196
- Bucket: config.params.Bucket,
197
- Key: getFileKey(file),
198
- ...customParams
199
- });
200
- return s3Client.send(command);
201
- }
202
- };
203
- }
141
+ return s3Client.send(command);
142
+ }
143
+ };
144
+ }
204
145
  };
205
-
206
146
  module.exports = index;
207
147
  //# 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\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","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":["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","assertUrlProtocol","test","getConfig","rootPath","legacyS3Options","Object","keys","process","emitWarning","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","GetObjectCommand","expiresIn","uploadStream","delete","command","DeleteObjectCommand","send"],"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,CAAE;;AC9BF,MAAMC,oBAAoB,CAACvB,GAAAA,GAAAA;;IAEzB,OAAO,WAAA,CAAYwB,IAAI,CAACxB,GAAAA,CAAAA;AAC1B,CAAA;AAEA,MAAMyB,SAAAA,GAAY,CAAC,EAAE1B,OAAO,EAAE2B,QAAQ,EAAEP,SAAS,EAAE,GAAGQ,eAA8B,EAAA,GAAA;AAClF,IAAA,IAAIC,OAAOC,IAAI,CAACF,eAAiBX,CAAAA,CAAAA,MAAM,GAAG,CAAG,EAAA;AAC3Cc,QAAAA,OAAAA,CAAQC,WAAW,CACjB,2LAAA,CAAA;AAEJ;AACA,IAAA,MAAMX,cAAcH,kBAAmB,CAAA;AAAEE,QAAAA,SAAAA;AAAW,QAAA,GAAGQ;AAAgB,KAAA,CAAA;AACvE,IAAA,MAAMK,MAAS,GAAA;AACb,QAAA,GAAGb,SAAS;AACZ,QAAA,GAAGQ,eAAe;AAClB,QAAA,GAAIP,WAAc,GAAA;AAAEA,YAAAA;AAAY,SAAA,GAAI;AACtC,KAAA;AAEAY,IAAAA,MAAAA,CAAOC,MAAM,CAACC,GAAG,GAAGC,QAAMC,CAAAA,wBAAAA,CAAgBC,WAAW,EAAE;AAAC,QAAA,QAAA;AAAU,QAAA;KAAM,EAAEL,MAAAA,CAAAA;IAE1E,OAAOA,MAAAA;AACT,CAAA;AAEA,YAAe;IACbM,IAAK,CAAA,CAAA,EAAEvC,OAAO,EAAE2B,QAAQ,EAAEP,SAAS,EAAE,GAAGQ,eAA8B,EAAA,EAAA;;AAEpE,QAAA,MAAMK,SAASP,SAAU,CAAA;AAAE1B,YAAAA,OAAAA;AAAS2B,YAAAA,QAAAA;AAAUP,YAAAA,SAAAA;AAAW,YAAA,GAAGQ;AAAgB,SAAA,CAAA;QAC5E,MAAMY,QAAAA,GAAW,IAAIC,iBAASR,CAAAA,MAAAA,CAAAA;QAC9B,MAAMS,UAAAA,GAAaf,QAAW,GAAA,CAAC,EAAEA,QAAAA,CAASgB,OAAO,CAAC,MAAQ,EAAA,EAAA,CAAA,CAAI,CAAC,CAAC,GAAG,EAAA;AAEnE,QAAA,MAAMC,aAAa,CAACC,IAAAA,GAAAA;YAClB,MAAMC,IAAAA,GAAOD,IAAKC,CAAAA,IAAI,GAAG,CAAC,EAAED,IAAAA,CAAKC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAA;AAC3C,YAAA,OAAO,CAAC,EAAEJ,UAAW,CAAA,EAAEI,IAAK,CAAA,EAAED,IAAKE,CAAAA,IAAI,CAAC,EAAEF,IAAKG,CAAAA,GAAG,CAAC,CAAC;AACtD,SAAA;AAEA,QAAA,MAAMC,MAAS,GAAA,OAAOJ,IAAYK,EAAAA,YAAAA,GAA+C,EAAE,GAAA;AACjF,YAAA,MAAMC,UAAUP,UAAWC,CAAAA,IAAAA,CAAAA;YAC3B,MAAMO,SAAAA,GAAY,IAAIC,iBAAO,CAAA;gBAC3BC,MAAQd,EAAAA,QAAAA;gBACRN,MAAQ,EAAA;oBACNqB,MAAQtB,EAAAA,MAAAA,CAAOC,MAAM,CAACqB,MAAM;oBAC5BC,GAAKL,EAAAA,OAAAA;oBACLM,IAAMZ,EAAAA,IAAAA,CAAKa,MAAM,IAAIC,MAAAA,CAAOC,IAAI,CAACf,IAAAA,CAAKgB,MAAM,EAAS,QAAA,CAAA;oBACrD1B,GAAKF,EAAAA,MAAAA,CAAOC,MAAM,CAACC,GAAG;AACtB2B,oBAAAA,WAAAA,EAAajB,KAAKkB,IAAI;AACtB,oBAAA,GAAGb;AACL;AACF,aAAA,CAAA;YAEA,MAAMD,MAAAA,GAAU,MAAMG,SAAAA,CAAUY,IAAI,EAAA;YAEpC,IAAIxC,iBAAAA,CAAkByB,MAAOgB,CAAAA,QAAQ,CAAG,EAAA;AACtCpB,gBAAAA,IAAAA,CAAK5C,GAAG,GAAGD,OAAU,GAAA,CAAC,EAAEA,OAAAA,CAAQ,CAAC,EAAEmD,OAAQ,CAAA,CAAC,GAAGF,MAAAA,CAAOgB,QAAQ;aACzD,MAAA;;gBAELpB,IAAK5C,CAAAA,GAAG,GAAG,CAAC,QAAQ,EAAEgD,MAAOgB,CAAAA,QAAQ,CAAC,CAAC;AACzC;AACF,SAAA;QAEA,OAAO;AACLC,YAAAA,SAAAA,CAAAA,GAAAA;AACE,gBAAA,OAAOjC,MAAOC,CAAAA,MAAM,CAACC,GAAG,KAAK,SAAA;AAC/B,aAAA;YAEA,MAAMgC,YAAAA,CAAAA,CAAatB,IAAU,EAAEK,YAAiB,EAAA;;gBAE9C,IAAI,CAACrD,eAAgBgD,CAAAA,IAAAA,CAAK5C,GAAG,EAAEgC,OAAOC,MAAM,CAACqB,MAAM,EAAEvD,OAAU,CAAA,EAAA;oBAC7D,OAAO;AAAEC,wBAAAA,GAAAA,EAAK4C,KAAK5C;AAAI,qBAAA;AACzB;AACA,gBAAA,MAAMkD,UAAUP,UAAWC,CAAAA,IAAAA,CAAAA;gBAE3B,MAAM5C,GAAAA,GAAM,MAAMkE,+BAAAA;AAEhB3B,gBAAAA,QAAAA,EACA,IAAI4B,yBAAiB,CAAA;oBACnBb,MAAQtB,EAAAA,MAAAA,CAAOC,MAAM,CAACqB,MAAM;oBAC5BC,GAAKL,EAAAA,OAAAA;AACL,oBAAA,GAAGD;iBAEL,CAAA,EAAA;oBACEmB,SAAWjC,EAAAA,QAAAA,CAAM,KAAK,EAAI,EAAA;AAAC,wBAAA,QAAA;AAAU,wBAAA;qBAAmB,EAAEH,MAAAA;AAC5D,iBAAA,CAAA;gBAGF,OAAO;AAAEhC,oBAAAA;AAAI,iBAAA;AACf,aAAA;AACAqE,YAAAA,YAAAA,CAAAA,CAAazB,IAAU,EAAEK,YAAe,GAAA,EAAE,EAAA;AACxC,gBAAA,OAAOD,OAAOJ,IAAMK,EAAAA,YAAAA,CAAAA;AACtB,aAAA;AACAD,YAAAA,MAAAA,CAAAA,CAAOJ,IAAU,EAAEK,YAAe,GAAA,EAAE,EAAA;AAClC,gBAAA,OAAOD,OAAOJ,IAAMK,EAAAA,YAAAA,CAAAA;AACtB,aAAA;AACAqB,YAAAA,MAAAA,CAAAA,CAAO1B,IAAU,EAAEK,YAAe,GAAA,EAAE,EAAA;gBAClC,MAAMsB,OAAAA,GAAU,IAAIC,4BAAoB,CAAA;oBACtClB,MAAQtB,EAAAA,MAAAA,CAAOC,MAAM,CAACqB,MAAM;AAC5BC,oBAAAA,GAAAA,EAAKZ,UAAWC,CAAAA,IAAAA,CAAAA;AAChB,oBAAA,GAAGK;AACL,iBAAA,CAAA;gBACA,OAAOV,QAAAA,CAASkC,IAAI,CAACF,OAAAA,CAAAA;AACvB;AACF,SAAA;AACF;AACF,CAAE;;;;"}
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\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","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":["index","getOr","ObjectCannedACL","S3Client","Upload","upload","getSignedUrl","GetObjectCommand","DeleteObjectCommand"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,205 +1,148 @@
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
-
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";
6
5
  const ENDPOINT_PATTERN = /^(.+\.)?s3[.-]([a-z0-9-]+)\./;
7
- function isUrlFromBucket(fileUrl, bucketName, baseUrl = '') {
8
- const url = new URL(fileUrl);
9
- // Check if the file URL is using a base URL (e.g. a CDN).
10
- // In this case do not sign the URL.
11
- if (baseUrl) {
12
- return false;
13
- }
14
- const { bucket } = getBucketFromAwsUrl(fileUrl);
15
- if (bucket) {
16
- return bucket === bucketName;
17
- }
18
- // File URL might be of an S3-compatible provider. (or an invalid URL)
19
- // In this case, check if the bucket name appears in the URL host or path.
20
- // e.g. https://minio.example.com/bucket-name/object-key
21
- // e.g. https://bucket.nyc3.digitaloceanspaces.com/folder/img.png
22
- return url.host.startsWith(`${bucketName}.`) || url.pathname.includes(`/${bucketName}/`);
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}/`);
23
16
  }
24
- /**
25
- * Parse the bucket name from a URL.
26
- * See all URL formats in https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html
27
- *
28
- * @param {string} fileUrl - the URL to parse
29
- * @returns {object} result
30
- * @returns {string} result.bucket - the bucket name
31
- * @returns {string} result.err - if any
32
- */ function getBucketFromAwsUrl(fileUrl) {
33
- const url = new URL(fileUrl);
34
- // S3://<bucket-name>/<key>
35
- if (url.protocol === 's3:') {
36
- const bucket = url.host;
37
- if (!bucket) {
38
- return {
39
- err: `Invalid S3 url: no bucket: ${url}`
40
- };
41
- }
42
- return {
43
- bucket
44
- };
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}` };
45
23
  }
46
- if (!url.host) {
47
- return {
48
- err: `Invalid S3 url: no hostname: ${url}`
49
- };
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 };
50
37
  }
51
- const matches = url.host.match(ENDPOINT_PATTERN);
52
- if (!matches) {
53
- return {
54
- err: `Invalid S3 url: hostname does not appear to be a valid S3 endpoint: ${url}`
55
- };
38
+ const index2 = url.pathname.indexOf("/", 1);
39
+ if (index2 === -1) {
40
+ return { bucket: url.pathname.substring(1) };
56
41
  }
57
- const prefix = matches[1];
58
- // https://s3.amazonaws.com/<bucket-name>
59
- if (!prefix) {
60
- if (url.pathname === '/') {
61
- return {
62
- bucket: null
63
- };
64
- }
65
- const index = url.pathname.indexOf('/', 1);
66
- // https://s3.amazonaws.com/<bucket-name>
67
- if (index === -1) {
68
- return {
69
- bucket: url.pathname.substring(1)
70
- };
71
- }
72
- // https://s3.amazonaws.com/<bucket-name>/
73
- if (index === url.pathname.length - 1) {
74
- return {
75
- bucket: url.pathname.substring(1, index)
76
- };
77
- }
78
- // https://s3.amazonaws.com/<bucket-name>/key
79
- return {
80
- bucket: url.pathname.substring(1, index)
81
- };
42
+ if (index2 === url.pathname.length - 1) {
43
+ return { bucket: url.pathname.substring(1, index2) };
82
44
  }
83
- // https://<bucket-name>.s3.amazonaws.com/
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.s3Options?.credentials) {
84
51
  return {
85
- bucket: prefix.substring(0, prefix.length - 1)
52
+ accessKeyId: options.s3Options.credentials.accessKeyId,
53
+ secretAccessKey: options.s3Options.credentials.secretAccessKey
86
54
  };
87
- }
88
- const extractCredentials = (options)=>{
89
- if (options.s3Options?.credentials) {
90
- return {
91
- accessKeyId: options.s3Options.credentials.accessKeyId,
92
- secretAccessKey: options.s3Options.credentials.secretAccessKey
93
- };
94
- }
95
- return null;
55
+ }
56
+ return null;
96
57
  };
97
-
98
- const assertUrlProtocol = (url)=>{
99
- // Regex to test protocol like "http://", "https://"
100
- return /^\w*:\/\//.test(url);
58
+ const assertUrlProtocol = (url) => {
59
+ return /^\w*:\/\//.test(url);
101
60
  };
102
- const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options })=>{
103
- if (Object.keys(legacyS3Options).length > 0) {
104
- 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.");
105
- }
106
- const credentials = extractCredentials({
107
- s3Options,
108
- ...legacyS3Options
109
- });
110
- const config = {
111
- ...s3Options,
112
- ...legacyS3Options,
113
- ...credentials ? {
114
- credentials
115
- } : {}
116
- };
117
- config.params.ACL = getOr(ObjectCannedACL.public_read, [
118
- 'params',
119
- 'ACL'
120
- ], config);
121
- return config;
61
+ const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) => {
62
+ if (Object.keys(legacyS3Options).length > 0) {
63
+ process.emitWarning(
64
+ "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."
65
+ );
66
+ }
67
+ const credentials = extractCredentials({ s3Options, ...legacyS3Options });
68
+ const config = {
69
+ ...s3Options,
70
+ ...legacyS3Options,
71
+ ...credentials ? { credentials } : {}
72
+ };
73
+ config.params.ACL = getOr(ObjectCannedACL.public_read, ["params", "ACL"], config);
74
+ return config;
122
75
  };
123
- var index = {
124
- init ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
125
- // TODO V5 change config structure to avoid having to do this
126
- const config = getConfig({
127
- baseUrl,
128
- rootPath,
129
- s3Options,
130
- ...legacyS3Options
76
+ const index = {
77
+ init({ baseUrl, rootPath, s3Options, ...legacyS3Options }) {
78
+ const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options });
79
+ const s3Client = new S3Client(config);
80
+ const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, "")}/` : "";
81
+ const getFileKey = (file) => {
82
+ const path = file.path ? `${file.path}/` : "";
83
+ return `${filePrefix}${path}${file.hash}${file.ext}`;
84
+ };
85
+ const upload = async (file, customParams = {}) => {
86
+ const fileKey = getFileKey(file);
87
+ const uploadObj = new Upload({
88
+ client: s3Client,
89
+ params: {
90
+ Bucket: config.params.Bucket,
91
+ Key: fileKey,
92
+ Body: file.stream || Buffer.from(file.buffer, "binary"),
93
+ ACL: config.params.ACL,
94
+ ContentType: file.mime,
95
+ ...customParams
96
+ }
97
+ });
98
+ const upload2 = await uploadObj.done();
99
+ if (assertUrlProtocol(upload2.Location)) {
100
+ file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload2.Location;
101
+ } else {
102
+ file.url = `https://${upload2.Location}`;
103
+ }
104
+ };
105
+ return {
106
+ isPrivate() {
107
+ return config.params.ACL === "private";
108
+ },
109
+ async getSignedUrl(file, customParams) {
110
+ if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
111
+ return { url: file.url };
112
+ }
113
+ const fileKey = getFileKey(file);
114
+ const url = await getSignedUrl(
115
+ // @ts-expect-error - TODO fix client type
116
+ s3Client,
117
+ new GetObjectCommand({
118
+ Bucket: config.params.Bucket,
119
+ Key: fileKey,
120
+ ...customParams
121
+ }),
122
+ {
123
+ expiresIn: getOr(15 * 60, ["params", "signedUrlExpires"], config)
124
+ }
125
+ );
126
+ return { url };
127
+ },
128
+ uploadStream(file, customParams = {}) {
129
+ return upload(file, customParams);
130
+ },
131
+ upload(file, customParams = {}) {
132
+ return upload(file, customParams);
133
+ },
134
+ delete(file, customParams = {}) {
135
+ const command = new DeleteObjectCommand({
136
+ Bucket: config.params.Bucket,
137
+ Key: getFileKey(file),
138
+ ...customParams
131
139
  });
132
- const s3Client = new S3Client(config);
133
- const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, '')}/` : '';
134
- const getFileKey = (file)=>{
135
- const path = file.path ? `${file.path}/` : '';
136
- return `${filePrefix}${path}${file.hash}${file.ext}`;
137
- };
138
- const upload = async (file, customParams = {})=>{
139
- const fileKey = getFileKey(file);
140
- const uploadObj = new Upload({
141
- client: s3Client,
142
- params: {
143
- Bucket: config.params.Bucket,
144
- Key: fileKey,
145
- Body: file.stream || Buffer.from(file.buffer, 'binary'),
146
- ACL: config.params.ACL,
147
- ContentType: file.mime,
148
- ...customParams
149
- }
150
- });
151
- const upload = await uploadObj.done();
152
- if (assertUrlProtocol(upload.Location)) {
153
- file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location;
154
- } else {
155
- // Default protocol to https protocol
156
- file.url = `https://${upload.Location}`;
157
- }
158
- };
159
- return {
160
- isPrivate () {
161
- return config.params.ACL === 'private';
162
- },
163
- async getSignedUrl (file, customParams) {
164
- // Do not sign the url if it does not come from the same bucket.
165
- if (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
166
- return {
167
- url: file.url
168
- };
169
- }
170
- const fileKey = getFileKey(file);
171
- const url = await getSignedUrl(// @ts-expect-error - TODO fix client type
172
- s3Client, new GetObjectCommand({
173
- Bucket: config.params.Bucket,
174
- Key: fileKey,
175
- ...customParams
176
- }), {
177
- expiresIn: getOr(15 * 60, [
178
- 'params',
179
- 'signedUrlExpires'
180
- ], config)
181
- });
182
- return {
183
- url
184
- };
185
- },
186
- uploadStream (file, customParams = {}) {
187
- return upload(file, customParams);
188
- },
189
- upload (file, customParams = {}) {
190
- return upload(file, customParams);
191
- },
192
- delete (file, customParams = {}) {
193
- const command = new DeleteObjectCommand({
194
- Bucket: config.params.Bucket,
195
- Key: getFileKey(file),
196
- ...customParams
197
- });
198
- return s3Client.send(command);
199
- }
200
- };
201
- }
140
+ return s3Client.send(command);
141
+ }
142
+ };
143
+ }
144
+ };
145
+ export {
146
+ index as default
202
147
  };
203
-
204
- export { index as default };
205
148
  //# 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\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","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":["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","assertUrlProtocol","test","getConfig","rootPath","legacyS3Options","Object","keys","process","emitWarning","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","GetObjectCommand","expiresIn","uploadStream","delete","command","DeleteObjectCommand","send"],"mappings":"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"}
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\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","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":["index","upload"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/provider-upload-aws-s3",
3
- "version": "0.0.0-next.39c0188c3aa01bec7b64b948211571d5159e811d",
3
+ "version": "0.0.0-next.3a1d87a9c3b1d4d89f741c6ecd7f501230fd8d76",
4
4
  "description": "AWS S3 provider for strapi upload",
5
5
  "keywords": [
6
6
  "upload",
@@ -37,14 +37,12 @@
37
37
  "dist/"
38
38
  ],
39
39
  "scripts": {
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",
40
+ "build": "pack-up build",
43
41
  "clean": "run -T rimraf ./dist",
44
42
  "lint": "run -T eslint .",
45
43
  "test:unit": "run -T jest",
46
44
  "test:unit:watch": "run -T jest --watch",
47
- "watch": "run -T rollup -c -w"
45
+ "watch": "pack-up watch"
48
46
  },
49
47
  "dependencies": {
50
48
  "@aws-sdk/client-s3": "3.600.0",
@@ -54,9 +52,10 @@
54
52
  "lodash": "4.17.21"
55
53
  },
56
54
  "devDependencies": {
55
+ "@strapi/pack-up": "5.0.2",
57
56
  "@types/jest": "29.5.2",
58
- "eslint-config-custom": "0.0.0-next.39c0188c3aa01bec7b64b948211571d5159e811d",
59
- "tsconfig": "0.0.0-next.39c0188c3aa01bec7b64b948211571d5159e811d"
57
+ "eslint-config-custom": "0.0.0-next.3a1d87a9c3b1d4d89f741c6ecd7f501230fd8d76",
58
+ "tsconfig": "0.0.0-next.3a1d87a9c3b1d4d89f741c6ecd7f501230fd8d76"
60
59
  },
61
60
  "engines": {
62
61
  "node": ">=18.0.0 <=22.x.x",