@payloadcms/storage-s3 3.83.0 → 3.84.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/storage-s3",
3
- "version": "3.83.0",
3
+ "version": "3.84.0-canary.0",
4
4
  "description": "Payload storage adapter for Amazon S3",
5
5
  "homepage": "https://payloadcms.com",
6
6
  "repository": {
@@ -40,14 +40,14 @@
40
40
  "@aws-sdk/client-s3": "^3.614.0",
41
41
  "@aws-sdk/lib-storage": "^3.614.0",
42
42
  "@aws-sdk/s3-request-presigner": "^3.614.0",
43
- "@payloadcms/plugin-cloud-storage": "3.83.0"
43
+ "@payloadcms/plugin-cloud-storage": "3.84.0-canary.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@smithy/node-http-handler": "4.0.3",
47
- "payload": "3.83.0"
47
+ "payload": "3.84.0-canary.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "payload": "3.83.0"
50
+ "payload": "3.84.0-canary.0"
51
51
  },
52
52
  "engines": {
53
53
  "node": "^18.20.2 || >=20.9.0"
@@ -1,9 +0,0 @@
1
- import type * as AWS from '@aws-sdk/client-s3';
2
- import type { HandleDelete } from '@payloadcms/plugin-cloud-storage/types';
3
- interface Args {
4
- bucket: string;
5
- getStorageClient: () => AWS.S3;
6
- }
7
- export declare const getHandleDelete: ({ bucket, getStorageClient }: Args) => HandleDelete;
8
- export {};
9
- //# sourceMappingURL=handleDelete.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handleDelete.d.ts","sourceRoot":"","sources":["../src/handleDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AAI1E,UAAU,IAAI;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,GAAG,CAAC,EAAE,CAAA;CAC/B;AAED,eAAO,MAAM,eAAe,iCAAkC,IAAI,KAAG,YAOpE,CAAA"}
@@ -1,11 +0,0 @@
1
- import path from 'path';
2
- export const getHandleDelete = ({ bucket, getStorageClient })=>{
3
- return async ({ doc: { prefix = '' }, filename })=>{
4
- await getStorageClient().deleteObject({
5
- Bucket: bucket,
6
- Key: path.posix.join(prefix, filename)
7
- });
8
- };
9
- };
10
-
11
- //# sourceMappingURL=handleDelete.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/handleDelete.ts"],"sourcesContent":["import type * as AWS from '@aws-sdk/client-s3'\nimport type { HandleDelete } from '@payloadcms/plugin-cloud-storage/types'\n\nimport path from 'path'\n\ninterface Args {\n bucket: string\n getStorageClient: () => AWS.S3\n}\n\nexport const getHandleDelete = ({ bucket, getStorageClient }: Args): HandleDelete => {\n return async ({ doc: { prefix = '' }, filename }) => {\n await getStorageClient().deleteObject({\n Bucket: bucket,\n Key: path.posix.join(prefix, filename),\n })\n }\n}\n"],"names":["path","getHandleDelete","bucket","getStorageClient","doc","prefix","filename","deleteObject","Bucket","Key","posix","join"],"mappings":"AAGA,OAAOA,UAAU,OAAM;AAOvB,OAAO,MAAMC,kBAAkB,CAAC,EAAEC,MAAM,EAAEC,gBAAgB,EAAQ;IAChE,OAAO,OAAO,EAAEC,KAAK,EAAEC,SAAS,EAAE,EAAE,EAAEC,QAAQ,EAAE;QAC9C,MAAMH,mBAAmBI,YAAY,CAAC;YACpCC,QAAQN;YACRO,KAAKT,KAAKU,KAAK,CAACC,IAAI,CAACN,QAAQC;QAC/B;IACF;AACF,EAAC"}
@@ -1,13 +0,0 @@
1
- import type * as AWS from '@aws-sdk/client-s3';
2
- import type { HandleUpload } from '@payloadcms/plugin-cloud-storage/types';
3
- import type { CollectionConfig } from 'payload';
4
- interface Args {
5
- acl?: 'private' | 'public-read';
6
- bucket: string;
7
- collection: CollectionConfig;
8
- getStorageClient: () => AWS.S3;
9
- prefix?: string;
10
- }
11
- export declare const getHandleUpload: ({ acl, bucket, getStorageClient, prefix, }: Args) => HandleUpload;
12
- export {};
13
- //# sourceMappingURL=handleUpload.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handleUpload.d.ts","sourceRoot":"","sources":["../src/handleUpload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAM/C,UAAU,IAAI;IACZ,GAAG,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,EAAE,MAAM,GAAG,CAAC,EAAE,CAAA;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAID,eAAO,MAAM,eAAe,+CAKzB,IAAI,KAAG,YAqCT,CAAA"}
@@ -1,37 +0,0 @@
1
- import { Upload } from '@aws-sdk/lib-storage';
2
- import fs from 'fs';
3
- import path from 'path';
4
- const multipartThreshold = 1024 * 1024 * 50 // 50MB
5
- ;
6
- export const getHandleUpload = ({ acl, bucket, getStorageClient, prefix = '' })=>{
7
- return async ({ data, file })=>{
8
- const fileKey = path.posix.join(data.prefix || prefix, file.filename);
9
- const fileBufferOrStream = file.tempFilePath ? fs.createReadStream(file.tempFilePath) : file.buffer;
10
- if (file.buffer.length > 0 && file.buffer.length < multipartThreshold) {
11
- await getStorageClient().putObject({
12
- ACL: acl,
13
- Body: fileBufferOrStream,
14
- Bucket: bucket,
15
- ContentType: file.mimeType,
16
- Key: fileKey
17
- });
18
- return data;
19
- }
20
- const parallelUploadS3 = new Upload({
21
- client: getStorageClient(),
22
- params: {
23
- ACL: acl,
24
- Body: fileBufferOrStream,
25
- Bucket: bucket,
26
- ContentType: file.mimeType,
27
- Key: fileKey
28
- },
29
- partSize: multipartThreshold,
30
- queueSize: 4
31
- });
32
- await parallelUploadS3.done();
33
- return data;
34
- };
35
- };
36
-
37
- //# sourceMappingURL=handleUpload.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/handleUpload.ts"],"sourcesContent":["import type * as AWS from '@aws-sdk/client-s3'\nimport type { HandleUpload } from '@payloadcms/plugin-cloud-storage/types'\nimport type { CollectionConfig } from 'payload'\n\nimport { Upload } from '@aws-sdk/lib-storage'\nimport fs from 'fs'\nimport path from 'path'\n\ninterface Args {\n acl?: 'private' | 'public-read'\n bucket: string\n collection: CollectionConfig\n getStorageClient: () => AWS.S3\n prefix?: string\n}\n\nconst multipartThreshold = 1024 * 1024 * 50 // 50MB\n\nexport const getHandleUpload = ({\n acl,\n bucket,\n getStorageClient,\n prefix = '',\n}: Args): HandleUpload => {\n return async ({ data, file }) => {\n const fileKey = path.posix.join(data.prefix || prefix, file.filename)\n\n const fileBufferOrStream = file.tempFilePath\n ? fs.createReadStream(file.tempFilePath)\n : file.buffer\n\n if (file.buffer.length > 0 && file.buffer.length < multipartThreshold) {\n await getStorageClient().putObject({\n ACL: acl,\n Body: fileBufferOrStream,\n Bucket: bucket,\n ContentType: file.mimeType,\n Key: fileKey,\n })\n\n return data\n }\n\n const parallelUploadS3 = new Upload({\n client: getStorageClient(),\n params: {\n ACL: acl,\n Body: fileBufferOrStream,\n Bucket: bucket,\n ContentType: file.mimeType,\n Key: fileKey,\n },\n partSize: multipartThreshold,\n queueSize: 4,\n })\n\n await parallelUploadS3.done()\n\n return data\n }\n}\n"],"names":["Upload","fs","path","multipartThreshold","getHandleUpload","acl","bucket","getStorageClient","prefix","data","file","fileKey","posix","join","filename","fileBufferOrStream","tempFilePath","createReadStream","buffer","length","putObject","ACL","Body","Bucket","ContentType","mimeType","Key","parallelUploadS3","client","params","partSize","queueSize","done"],"mappings":"AAIA,SAASA,MAAM,QAAQ,uBAAsB;AAC7C,OAAOC,QAAQ,KAAI;AACnB,OAAOC,UAAU,OAAM;AAUvB,MAAMC,qBAAqB,OAAO,OAAO,GAAG,OAAO;;AAEnD,OAAO,MAAMC,kBAAkB,CAAC,EAC9BC,GAAG,EACHC,MAAM,EACNC,gBAAgB,EAChBC,SAAS,EAAE,EACN;IACL,OAAO,OAAO,EAAEC,IAAI,EAAEC,IAAI,EAAE;QAC1B,MAAMC,UAAUT,KAAKU,KAAK,CAACC,IAAI,CAACJ,KAAKD,MAAM,IAAIA,QAAQE,KAAKI,QAAQ;QAEpE,MAAMC,qBAAqBL,KAAKM,YAAY,GACxCf,GAAGgB,gBAAgB,CAACP,KAAKM,YAAY,IACrCN,KAAKQ,MAAM;QAEf,IAAIR,KAAKQ,MAAM,CAACC,MAAM,GAAG,KAAKT,KAAKQ,MAAM,CAACC,MAAM,GAAGhB,oBAAoB;YACrE,MAAMI,mBAAmBa,SAAS,CAAC;gBACjCC,KAAKhB;gBACLiB,MAAMP;gBACNQ,QAAQjB;gBACRkB,aAAad,KAAKe,QAAQ;gBAC1BC,KAAKf;YACP;YAEA,OAAOF;QACT;QAEA,MAAMkB,mBAAmB,IAAI3B,OAAO;YAClC4B,QAAQrB;YACRsB,QAAQ;gBACNR,KAAKhB;gBACLiB,MAAMP;gBACNQ,QAAQjB;gBACRkB,aAAad,KAAKe,QAAQ;gBAC1BC,KAAKf;YACP;YACAmB,UAAU3B;YACV4B,WAAW;QACb;QAEA,MAAMJ,iBAAiBK,IAAI;QAE3B,OAAOvB;IACT;AACF,EAAC"}
@@ -1,21 +0,0 @@
1
- import type * as AWS from '@aws-sdk/client-s3';
2
- import type { StaticHandler } from '@payloadcms/plugin-cloud-storage/types';
3
- import type { CollectionConfig, PayloadRequest } from 'payload';
4
- export type SignedDownloadsConfig = {
5
- /** @default 7200 */
6
- expiresIn?: number;
7
- shouldUseSignedURL?(args: {
8
- collection: CollectionConfig;
9
- filename: string;
10
- req: PayloadRequest;
11
- }): boolean | Promise<boolean>;
12
- } | boolean;
13
- interface Args {
14
- bucket: string;
15
- collection: CollectionConfig;
16
- getStorageClient: () => AWS.S3;
17
- signedDownloads?: SignedDownloadsConfig;
18
- }
19
- export declare const getHandler: ({ bucket, collection, getStorageClient, signedDownloads, }: Args) => StaticHandler;
20
- export {};
21
- //# sourceMappingURL=staticHandler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"staticHandler.d.ts","sourceRoot":"","sources":["../src/staticHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAU/D,MAAM,MAAM,qBAAqB,GAC7B;IACE,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kBAAkB,CAAC,CAAC,IAAI,EAAE;QACxB,UAAU,EAAE,gBAAgB,CAAA;QAC5B,QAAQ,EAAE,MAAM,CAAA;QAChB,GAAG,EAAE,cAAc,CAAA;KACpB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC/B,GACD,OAAO,CAAA;AAEX,UAAU,IAAI;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,EAAE,MAAM,GAAG,CAAC,EAAE,CAAA;IAC9B,eAAe,CAAC,EAAE,qBAAqB,CAAA;CACxC;AA8BD,eAAO,MAAM,UAAU,+DAKpB,IAAI,KAAG,aAmJT,CAAA"}
@@ -1,169 +0,0 @@
1
- import { GetObjectCommand } from '@aws-sdk/client-s3';
2
- import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
3
- import { getFilePrefix } from '@payloadcms/plugin-cloud-storage/utilities';
4
- import path from 'path';
5
- import { getRangeRequestInfo } from 'payload/internal';
6
- import { sanitizeFilename } from 'payload/shared';
7
- const isNodeReadableStream = (body)=>{
8
- return typeof body === 'object' && body !== null && 'pipe' in body && typeof body.pipe === 'function' && 'destroy' in body && typeof body.destroy === 'function';
9
- };
10
- const abortRequestAndDestroyStream = ({ abortController, object })=>{
11
- try {
12
- abortController.abort();
13
- } catch {
14
- /* noop */ }
15
- if (object?.Body && isNodeReadableStream(object.Body)) {
16
- object.Body.destroy();
17
- }
18
- };
19
- export const getHandler = ({ bucket, collection, getStorageClient, signedDownloads })=>{
20
- return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } })=>{
21
- let object = undefined;
22
- let streamed = false;
23
- const abortController = new AbortController();
24
- if (req.signal) {
25
- req.signal.addEventListener('abort', ()=>{
26
- abortRequestAndDestroyStream({
27
- abortController,
28
- object
29
- });
30
- });
31
- }
32
- try {
33
- const prefix = await getFilePrefix({
34
- clientUploadContext,
35
- collection,
36
- filename,
37
- req
38
- });
39
- const key = path.posix.join(prefix, sanitizeFilename(filename));
40
- if (signedDownloads && !clientUploadContext) {
41
- let useSignedURL = true;
42
- if (typeof signedDownloads === 'object' && typeof signedDownloads.shouldUseSignedURL === 'function') {
43
- useSignedURL = await signedDownloads.shouldUseSignedURL({
44
- collection,
45
- filename,
46
- req
47
- });
48
- }
49
- if (useSignedURL) {
50
- const command = new GetObjectCommand({
51
- Bucket: bucket,
52
- Key: key
53
- });
54
- const signedUrl = await getSignedUrl(getStorageClient(), command, typeof signedDownloads === 'object' ? signedDownloads : {
55
- expiresIn: 7200
56
- });
57
- return Response.redirect(signedUrl, 302);
58
- }
59
- }
60
- // Get file size first for range validation
61
- const headObject = await getStorageClient().headObject({
62
- Bucket: bucket,
63
- Key: key
64
- });
65
- const fileSize = headObject.ContentLength;
66
- if (!fileSize) {
67
- return new Response('Internal Server Error', {
68
- status: 500
69
- });
70
- }
71
- // Handle range request
72
- const rangeHeader = req.headers.get('range');
73
- const rangeResult = getRangeRequestInfo({
74
- fileSize,
75
- rangeHeader
76
- });
77
- if (rangeResult.type === 'invalid') {
78
- return new Response(null, {
79
- headers: new Headers(rangeResult.headers),
80
- status: rangeResult.status
81
- });
82
- }
83
- const rangeForS3 = rangeResult.type === 'partial' ? `bytes=${rangeResult.rangeStart}-${rangeResult.rangeEnd}` : undefined;
84
- object = await getStorageClient().getObject({
85
- Bucket: bucket,
86
- Key: key,
87
- Range: rangeForS3
88
- }, {
89
- abortSignal: abortController.signal
90
- });
91
- if (!object.Body) {
92
- return new Response(null, {
93
- status: 404,
94
- statusText: 'Not Found'
95
- });
96
- }
97
- let headers = new Headers(incomingHeaders);
98
- // Add range-related headers from the result
99
- for (const [key, value] of Object.entries(rangeResult.headers)){
100
- headers.append(key, value);
101
- }
102
- headers.append('Content-Type', String(object.ContentType));
103
- headers.append('ETag', String(object.ETag));
104
- // Add Content-Security-Policy header for SVG files to prevent executable code
105
- if (object.ContentType === 'image/svg+xml') {
106
- headers.append('Content-Security-Policy', "script-src 'none'");
107
- }
108
- const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match');
109
- const objectEtag = object.ETag;
110
- if (collection.upload && typeof collection.upload === 'object' && typeof collection.upload.modifyResponseHeaders === 'function') {
111
- headers = collection.upload.modifyResponseHeaders({
112
- headers
113
- }) || headers;
114
- }
115
- if (etagFromHeaders && etagFromHeaders === objectEtag) {
116
- return new Response(null, {
117
- headers,
118
- status: 304
119
- });
120
- }
121
- if (!isNodeReadableStream(object.Body)) {
122
- req.payload.logger.error({
123
- key,
124
- msg: 'S3 object body is not a readable stream'
125
- });
126
- return new Response('Internal Server Error', {
127
- status: 500
128
- });
129
- }
130
- const stream = object.Body;
131
- stream.on('error', (err)=>{
132
- req.payload.logger.error({
133
- err,
134
- key,
135
- msg: 'Error while streaming S3 object (aborting)'
136
- });
137
- abortRequestAndDestroyStream({
138
- abortController,
139
- object
140
- });
141
- });
142
- streamed = true;
143
- return new Response(stream, {
144
- headers,
145
- status: rangeResult.status
146
- });
147
- } catch (err) {
148
- if (err && typeof err === 'object' && ('name' in err && (err.name === 'NoSuchKey' || err.name === 'NotFound') || 'httpStatusCode' in err && err.httpStatusCode === 404)) {
149
- return new Response(null, {
150
- status: 404,
151
- statusText: 'Not Found'
152
- });
153
- }
154
- req.payload.logger.error(err);
155
- return new Response('Internal Server Error', {
156
- status: 500
157
- });
158
- } finally{
159
- if (!streamed) {
160
- abortRequestAndDestroyStream({
161
- abortController,
162
- object
163
- });
164
- }
165
- }
166
- };
167
- };
168
-
169
- //# sourceMappingURL=staticHandler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/staticHandler.ts"],"sourcesContent":["import type * as AWS from '@aws-sdk/client-s3'\nimport type { StaticHandler } from '@payloadcms/plugin-cloud-storage/types'\nimport type { CollectionConfig, PayloadRequest } from 'payload'\nimport type { Readable } from 'stream'\n\nimport { GetObjectCommand } from '@aws-sdk/client-s3'\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner'\nimport { getFilePrefix } from '@payloadcms/plugin-cloud-storage/utilities'\nimport path from 'path'\nimport { getRangeRequestInfo } from 'payload/internal'\nimport { sanitizeFilename } from 'payload/shared'\n\nexport type SignedDownloadsConfig =\n | {\n /** @default 7200 */\n expiresIn?: number\n shouldUseSignedURL?(args: {\n collection: CollectionConfig\n filename: string\n req: PayloadRequest\n }): boolean | Promise<boolean>\n }\n | boolean\n\ninterface Args {\n bucket: string\n collection: CollectionConfig\n getStorageClient: () => AWS.S3\n signedDownloads?: SignedDownloadsConfig\n}\n\nconst isNodeReadableStream = (body: AWS.GetObjectOutput['Body']): body is Readable => {\n return (\n typeof body === 'object' &&\n body !== null &&\n 'pipe' in body &&\n typeof body.pipe === 'function' &&\n 'destroy' in body &&\n typeof body.destroy === 'function'\n )\n}\n\nconst abortRequestAndDestroyStream = ({\n abortController,\n object,\n}: {\n abortController: AbortController\n object?: AWS.GetObjectOutput\n}) => {\n try {\n abortController.abort()\n } catch {\n /* noop */\n }\n if (object?.Body && isNodeReadableStream(object.Body)) {\n object.Body.destroy()\n }\n}\n\nexport const getHandler = ({\n bucket,\n collection,\n getStorageClient,\n signedDownloads,\n}: Args): StaticHandler => {\n return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } }) => {\n let object: AWS.GetObjectOutput | undefined = undefined\n let streamed = false\n\n const abortController = new AbortController()\n if (req.signal) {\n req.signal.addEventListener('abort', () => {\n abortRequestAndDestroyStream({ abortController, object })\n })\n }\n\n try {\n const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req })\n\n const key = path.posix.join(prefix, sanitizeFilename(filename))\n\n if (signedDownloads && !clientUploadContext) {\n let useSignedURL = true\n if (\n typeof signedDownloads === 'object' &&\n typeof signedDownloads.shouldUseSignedURL === 'function'\n ) {\n useSignedURL = await signedDownloads.shouldUseSignedURL({ collection, filename, req })\n }\n\n if (useSignedURL) {\n const command = new GetObjectCommand({ Bucket: bucket, Key: key })\n const signedUrl = await getSignedUrl(\n getStorageClient(),\n command,\n typeof signedDownloads === 'object' ? signedDownloads : { expiresIn: 7200 },\n )\n return Response.redirect(signedUrl, 302)\n }\n }\n\n // Get file size first for range validation\n const headObject = await getStorageClient().headObject({\n Bucket: bucket,\n Key: key,\n })\n const fileSize = headObject.ContentLength\n\n if (!fileSize) {\n return new Response('Internal Server Error', { status: 500 })\n }\n\n // Handle range request\n const rangeHeader = req.headers.get('range')\n const rangeResult = getRangeRequestInfo({ fileSize, rangeHeader })\n\n if (rangeResult.type === 'invalid') {\n return new Response(null, {\n headers: new Headers(rangeResult.headers),\n status: rangeResult.status,\n })\n }\n\n const rangeForS3 =\n rangeResult.type === 'partial'\n ? `bytes=${rangeResult.rangeStart}-${rangeResult.rangeEnd}`\n : undefined\n\n object = await getStorageClient().getObject(\n {\n Bucket: bucket,\n Key: key,\n Range: rangeForS3,\n },\n { abortSignal: abortController.signal },\n )\n\n if (!object.Body) {\n return new Response(null, { status: 404, statusText: 'Not Found' })\n }\n\n let headers = new Headers(incomingHeaders)\n\n // Add range-related headers from the result\n for (const [key, value] of Object.entries(rangeResult.headers)) {\n headers.append(key, value)\n }\n\n headers.append('Content-Type', String(object.ContentType))\n headers.append('ETag', String(object.ETag))\n\n // Add Content-Security-Policy header for SVG files to prevent executable code\n if (object.ContentType === 'image/svg+xml') {\n headers.append('Content-Security-Policy', \"script-src 'none'\")\n }\n\n const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match')\n const objectEtag = object.ETag\n\n if (\n collection.upload &&\n typeof collection.upload === 'object' &&\n typeof collection.upload.modifyResponseHeaders === 'function'\n ) {\n headers = collection.upload.modifyResponseHeaders({ headers }) || headers\n }\n\n if (etagFromHeaders && etagFromHeaders === objectEtag) {\n return new Response(null, {\n headers,\n status: 304,\n })\n }\n\n if (!isNodeReadableStream(object.Body)) {\n req.payload.logger.error({\n key,\n msg: 'S3 object body is not a readable stream',\n })\n return new Response('Internal Server Error', { status: 500 })\n }\n\n const stream = object.Body\n stream.on('error', (err: Error) => {\n req.payload.logger.error({\n err,\n key,\n msg: 'Error while streaming S3 object (aborting)',\n })\n abortRequestAndDestroyStream({ abortController, object })\n })\n\n streamed = true\n return new Response(stream, { headers, status: rangeResult.status })\n } catch (err) {\n if (\n err &&\n typeof err === 'object' &&\n (('name' in err && (err.name === 'NoSuchKey' || err.name === 'NotFound')) ||\n ('httpStatusCode' in err && err.httpStatusCode === 404))\n ) {\n return new Response(null, { status: 404, statusText: 'Not Found' })\n }\n req.payload.logger.error(err)\n return new Response('Internal Server Error', { status: 500 })\n } finally {\n if (!streamed) {\n abortRequestAndDestroyStream({ abortController, object })\n }\n }\n }\n}\n"],"names":["GetObjectCommand","getSignedUrl","getFilePrefix","path","getRangeRequestInfo","sanitizeFilename","isNodeReadableStream","body","pipe","destroy","abortRequestAndDestroyStream","abortController","object","abort","Body","getHandler","bucket","collection","getStorageClient","signedDownloads","req","headers","incomingHeaders","params","clientUploadContext","filename","undefined","streamed","AbortController","signal","addEventListener","prefix","key","posix","join","useSignedURL","shouldUseSignedURL","command","Bucket","Key","signedUrl","expiresIn","Response","redirect","headObject","fileSize","ContentLength","status","rangeHeader","get","rangeResult","type","Headers","rangeForS3","rangeStart","rangeEnd","getObject","Range","abortSignal","statusText","value","Object","entries","append","String","ContentType","ETag","etagFromHeaders","objectEtag","upload","modifyResponseHeaders","payload","logger","error","msg","stream","on","err","name","httpStatusCode"],"mappings":"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"}