@payloadcms/storage-s3 3.53.0-canary.3 → 3.53.0-canary.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"staticHandler.d.ts","sourceRoot":"","sources":["../src/staticHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG/D,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAA;AAMzC,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,aAmGT,CAAA"}
1
+ {"version":3,"file":"staticHandler.d.ts","sourceRoot":"","sources":["../src/staticHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG/D,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAA;AAMzC,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,aAkHT,CAAA"}
@@ -3,27 +3,31 @@ import { GetObjectCommand } from '@aws-sdk/client-s3';
3
3
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
4
4
  import { getFilePrefix } from '@payloadcms/plugin-cloud-storage/utilities';
5
5
  import path from 'path';
6
- // Type guard for NodeJS.Readable streams
7
6
  const isNodeReadableStream = (body)=>{
8
7
  return typeof body === 'object' && body !== null && 'pipe' in body && typeof body.pipe === 'function' && 'destroy' in body && typeof body.destroy === 'function';
9
8
  };
10
- const destroyStream = (object)=>{
9
+ const abortRequestAndDestroyStream = ({ abortController, object })=>{
10
+ try {
11
+ abortController.abort();
12
+ } catch {
13
+ /* noop */ }
11
14
  if (object?.Body && isNodeReadableStream(object.Body)) {
12
15
  object.Body.destroy();
13
16
  }
14
17
  };
15
- // Convert a stream into a promise that resolves with a Buffer
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- const streamToBuffer = async (readableStream)=>{
18
- const chunks = [];
19
- for await (const chunk of readableStream){
20
- chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
21
- }
22
- return Buffer.concat(chunks);
23
- };
24
18
  export const getHandler = ({ bucket, collection, getStorageClient, signedDownloads })=>{
25
19
  return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } })=>{
26
20
  let object = undefined;
21
+ let streamed = false;
22
+ const abortController = new AbortController();
23
+ if (req.signal) {
24
+ req.signal.addEventListener('abort', ()=>{
25
+ abortRequestAndDestroyStream({
26
+ abortController,
27
+ object
28
+ });
29
+ });
30
+ }
27
31
  try {
28
32
  const prefix = await getFilePrefix({
29
33
  clientUploadContext,
@@ -56,6 +60,8 @@ export const getHandler = ({ bucket, collection, getStorageClient, signedDownloa
56
60
  object = await getStorageClient().getObject({
57
61
  Bucket: bucket,
58
62
  Key: key
63
+ }, {
64
+ abortSignal: abortController.signal
59
65
  });
60
66
  if (!object.Body) {
61
67
  return new Response(null, {
@@ -87,20 +93,29 @@ export const getHandler = ({ bucket, collection, getStorageClient, signedDownloa
87
93
  status: 304
88
94
  });
89
95
  }
90
- // On error, manually destroy stream to close socket
91
- if (object.Body && isNodeReadableStream(object.Body)) {
92
- const stream = object.Body;
93
- stream.on('error', (err)=>{
94
- req.payload.logger.error({
95
- err,
96
- key,
97
- msg: 'Error streaming S3 object, destroying stream'
98
- });
99
- stream.destroy();
96
+ if (!isNodeReadableStream(object.Body)) {
97
+ req.payload.logger.error({
98
+ key,
99
+ msg: 'S3 object body is not a readable stream'
100
+ });
101
+ return new Response('Internal Server Error', {
102
+ status: 500
100
103
  });
101
104
  }
102
- const bodyBuffer = await streamToBuffer(object.Body);
103
- return new Response(bodyBuffer, {
105
+ const stream = object.Body;
106
+ stream.on('error', (err)=>{
107
+ req.payload.logger.error({
108
+ err,
109
+ key,
110
+ msg: 'Error while streaming S3 object (aborting)'
111
+ });
112
+ abortRequestAndDestroyStream({
113
+ abortController,
114
+ object
115
+ });
116
+ });
117
+ streamed = true;
118
+ return new Response(stream, {
104
119
  headers,
105
120
  status: 200
106
121
  });
@@ -116,7 +131,12 @@ export const getHandler = ({ bucket, collection, getStorageClient, signedDownloa
116
131
  status: 500
117
132
  });
118
133
  } finally{
119
- destroyStream(object);
134
+ if (!streamed) {
135
+ abortRequestAndDestroyStream({
136
+ abortController,
137
+ object
138
+ });
139
+ }
120
140
  }
121
141
  };
122
142
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/staticHandler.ts"],"sourcesContent":["import type { StaticHandler } from '@payloadcms/plugin-cloud-storage/types'\nimport type { CollectionConfig, PayloadRequest } from 'payload'\nimport type { Readable } from 'stream'\n\nimport * as AWS from '@aws-sdk/client-s3'\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'\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\n// Type guard for NodeJS.Readable streams\nconst isNodeReadableStream = (body: unknown): body is Readable => {\n return (\n typeof body === 'object' &&\n body !== null &&\n 'pipe' in body &&\n typeof (body as any).pipe === 'function' &&\n 'destroy' in body &&\n typeof (body as any).destroy === 'function'\n )\n}\n\nconst destroyStream = (object: AWS.GetObjectOutput | undefined) => {\n if (object?.Body && isNodeReadableStream(object.Body)) {\n object.Body.destroy()\n }\n}\n\n// Convert a stream into a promise that resolves with a Buffer\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst streamToBuffer = async (readableStream: any) => {\n const chunks = []\n for await (const chunk of readableStream) {\n chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk)\n }\n return Buffer.concat(chunks)\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 try {\n const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req })\n\n const key = path.posix.join(prefix, 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 // @ts-expect-error mismatch versions\n getStorageClient(),\n command,\n typeof signedDownloads === 'object' ? signedDownloads : { expiresIn: 7200 },\n )\n return Response.redirect(signedUrl, 302)\n }\n }\n\n object = await getStorageClient().getObject({\n Bucket: bucket,\n Key: key,\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 // Only include Content-Length when it’s present and strictly numeric.\n // This prevents \"Parse Error: Invalid character in Content-Length\" when providers (e.g., MinIO)\n // return undefined or a non-numeric value.\n const contentLength = String(object.ContentLength);\n if (contentLength && !isNaN(Number(contentLength))) {\n headers.append('Content-Length', contentLength);\n }\n\n headers.append('Content-Type', String(object.ContentType))\n headers.append('Accept-Ranges', String(object.AcceptRanges))\n headers.append('ETag', String(object.ETag))\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 // On error, manually destroy stream to close socket\n if (object.Body && isNodeReadableStream(object.Body)) {\n const stream = object.Body\n stream.on('error', (err) => {\n req.payload.logger.error({\n err,\n key,\n msg: 'Error streaming S3 object, destroying stream',\n })\n stream.destroy()\n })\n }\n\n const bodyBuffer = await streamToBuffer(object.Body)\n\n return new Response(bodyBuffer, {\n headers,\n status: 200,\n })\n } catch (err) {\n if (err instanceof AWS.NoSuchKey) {\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 destroyStream(object)\n }\n }\n}\n"],"names":["AWS","GetObjectCommand","getSignedUrl","getFilePrefix","path","isNodeReadableStream","body","pipe","destroy","destroyStream","object","Body","streamToBuffer","readableStream","chunks","chunk","push","Buffer","from","concat","getHandler","bucket","collection","getStorageClient","signedDownloads","req","headers","incomingHeaders","params","clientUploadContext","filename","undefined","prefix","key","posix","join","useSignedURL","shouldUseSignedURL","command","Bucket","Key","signedUrl","expiresIn","Response","redirect","getObject","status","statusText","Headers","contentLength","String","ContentLength","isNaN","Number","append","ContentType","AcceptRanges","ETag","etagFromHeaders","get","objectEtag","upload","modifyResponseHeaders","stream","on","err","payload","logger","error","msg","bodyBuffer","NoSuchKey"],"mappings":"AAIA,YAAYA,SAAS,qBAAoB;AACzC,SAASC,gBAAgB,QAAQ,qBAAoB;AACrD,SAASC,YAAY,QAAQ,gCAA+B;AAC5D,SAASC,aAAa,QAAQ,6CAA4C;AAC1E,OAAOC,UAAU,OAAM;AAqBvB,yCAAyC;AACzC,MAAMC,uBAAuB,CAACC;IAC5B,OACE,OAAOA,SAAS,YAChBA,SAAS,QACT,UAAUA,QACV,OAAO,AAACA,KAAaC,IAAI,KAAK,cAC9B,aAAaD,QACb,OAAO,AAACA,KAAaE,OAAO,KAAK;AAErC;AAEA,MAAMC,gBAAgB,CAACC;IACrB,IAAIA,QAAQC,QAAQN,qBAAqBK,OAAOC,IAAI,GAAG;QACrDD,OAAOC,IAAI,CAACH,OAAO;IACrB;AACF;AAEA,8DAA8D;AAC9D,8DAA8D;AAC9D,MAAMI,iBAAiB,OAAOC;IAC5B,MAAMC,SAAS,EAAE;IACjB,WAAW,MAAMC,SAASF,eAAgB;QACxCC,OAAOE,IAAI,CAAC,OAAOD,UAAU,WAAWE,OAAOC,IAAI,CAACH,SAASA;IAC/D;IACA,OAAOE,OAAOE,MAAM,CAACL;AACvB;AAEA,OAAO,MAAMM,aAAa,CAAC,EACzBC,MAAM,EACNC,UAAU,EACVC,gBAAgB,EAChBC,eAAe,EACV;IACL,OAAO,OAAOC,KAAK,EAAEC,SAASC,eAAe,EAAEC,QAAQ,EAAEC,mBAAmB,EAAEC,QAAQ,EAAE,EAAE;QACxF,IAAIpB,SAA0CqB;QAC9C,IAAI;YACF,MAAMC,SAAS,MAAM7B,cAAc;gBAAE0B;gBAAqBP;gBAAYQ;gBAAUL;YAAI;YAEpF,MAAMQ,MAAM7B,KAAK8B,KAAK,CAACC,IAAI,CAACH,QAAQF;YAEpC,IAAIN,mBAAmB,CAACK,qBAAqB;gBAC3C,IAAIO,eAAe;gBACnB,IACE,OAAOZ,oBAAoB,YAC3B,OAAOA,gBAAgBa,kBAAkB,KAAK,YAC9C;oBACAD,eAAe,MAAMZ,gBAAgBa,kBAAkB,CAAC;wBAAEf;wBAAYQ;wBAAUL;oBAAI;gBACtF;gBAEA,IAAIW,cAAc;oBAChB,MAAME,UAAU,IAAIrC,iBAAiB;wBAAEsC,QAAQlB;wBAAQmB,KAAKP;oBAAI;oBAChE,MAAMQ,YAAY,MAAMvC,aACtB,qCAAqC;oBACrCqB,oBACAe,SACA,OAAOd,oBAAoB,WAAWA,kBAAkB;wBAAEkB,WAAW;oBAAK;oBAE5E,OAAOC,SAASC,QAAQ,CAACH,WAAW;gBACtC;YACF;YAEA/B,SAAS,MAAMa,mBAAmBsB,SAAS,CAAC;gBAC1CN,QAAQlB;gBACRmB,KAAKP;YACP;YAEA,IAAI,CAACvB,OAAOC,IAAI,EAAE;gBAChB,OAAO,IAAIgC,SAAS,MAAM;oBAAEG,QAAQ;oBAAKC,YAAY;gBAAY;YACnE;YAEA,IAAIrB,UAAU,IAAIsB,QAAQrB;YAE1B,sEAAsE;YACtE,gGAAgG;YAChG,2CAA2C;YAC3C,MAAMsB,gBAAgBC,OAAOxC,OAAOyC,aAAa;YACjD,IAAIF,iBAAiB,CAACG,MAAMC,OAAOJ,iBAAiB;gBAClDvB,QAAQ4B,MAAM,CAAC,kBAAkBL;YACnC;YAEAvB,QAAQ4B,MAAM,CAAC,gBAAgBJ,OAAOxC,OAAO6C,WAAW;YACxD7B,QAAQ4B,MAAM,CAAC,iBAAiBJ,OAAOxC,OAAO8C,YAAY;YAC1D9B,QAAQ4B,MAAM,CAAC,QAAQJ,OAAOxC,OAAO+C,IAAI;YAEzC,MAAMC,kBAAkBjC,IAAIC,OAAO,CAACiC,GAAG,CAAC,WAAWlC,IAAIC,OAAO,CAACiC,GAAG,CAAC;YACnE,MAAMC,aAAalD,OAAO+C,IAAI;YAE9B,IACEnC,WAAWuC,MAAM,IACjB,OAAOvC,WAAWuC,MAAM,KAAK,YAC7B,OAAOvC,WAAWuC,MAAM,CAACC,qBAAqB,KAAK,YACnD;gBACApC,UAAUJ,WAAWuC,MAAM,CAACC,qBAAqB,CAAC;oBAAEpC;gBAAQ,MAAMA;YACpE;YAEA,IAAIgC,mBAAmBA,oBAAoBE,YAAY;gBACrD,OAAO,IAAIjB,SAAS,MAAM;oBACxBjB;oBACAoB,QAAQ;gBACV;YACF;YAEA,oDAAoD;YACpD,IAAIpC,OAAOC,IAAI,IAAIN,qBAAqBK,OAAOC,IAAI,GAAG;gBACpD,MAAMoD,SAASrD,OAAOC,IAAI;gBAC1BoD,OAAOC,EAAE,CAAC,SAAS,CAACC;oBAClBxC,IAAIyC,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;wBACvBH;wBACAhC;wBACAoC,KAAK;oBACP;oBACAN,OAAOvD,OAAO;gBAChB;YACF;YAEA,MAAM8D,aAAa,MAAM1D,eAAeF,OAAOC,IAAI;YAEnD,OAAO,IAAIgC,SAAS2B,YAAY;gBAC9B5C;gBACAoB,QAAQ;YACV;QACF,EAAE,OAAOmB,KAAK;YACZ,IAAIA,eAAejE,IAAIuE,SAAS,EAAE;gBAChC,OAAO,IAAI5B,SAAS,MAAM;oBAAEG,QAAQ;oBAAKC,YAAY;gBAAY;YACnE;YACAtB,IAAIyC,OAAO,CAACC,MAAM,CAACC,KAAK,CAACH;YACzB,OAAO,IAAItB,SAAS,yBAAyB;gBAAEG,QAAQ;YAAI;QAC7D,SAAU;YACRrC,cAAcC;QAChB;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../src/staticHandler.ts"],"sourcesContent":["import type { StaticHandler } from '@payloadcms/plugin-cloud-storage/types'\nimport type { CollectionConfig, PayloadRequest } from 'payload'\nimport type { Readable } from 'stream'\n\nimport * as AWS from '@aws-sdk/client-s3'\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'\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, 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 // @ts-expect-error mismatch versions\n getStorageClient(),\n command,\n typeof signedDownloads === 'object' ? signedDownloads : { expiresIn: 7200 },\n )\n return Response.redirect(signedUrl, 302)\n }\n }\n\n object = await getStorageClient().getObject(\n {\n Bucket: bucket,\n Key: key,\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 // Only include Content-Length when it’s present and strictly numeric.\n // This prevents \"Parse Error: Invalid character in Content-Length\" when providers (e.g., MinIO)\n // return undefined or a non-numeric value.\n const contentLength = String(object.ContentLength);\n if (contentLength && !isNaN(Number(contentLength))) {\n headers.append('Content-Length', contentLength);\n }\n\n headers.append('Content-Type', String(object.ContentType))\n headers.append('Accept-Ranges', String(object.AcceptRanges))\n headers.append('ETag', String(object.ETag))\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) => {\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: 200 })\n } catch (err) {\n if (err instanceof AWS.NoSuchKey) {\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":["AWS","GetObjectCommand","getSignedUrl","getFilePrefix","path","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","getObject","abortSignal","status","statusText","Headers","contentLength","String","ContentLength","isNaN","Number","append","ContentType","AcceptRanges","ETag","etagFromHeaders","get","objectEtag","upload","modifyResponseHeaders","payload","logger","error","msg","stream","on","err","NoSuchKey"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/storage-s3",
3
- "version": "3.53.0-canary.3",
3
+ "version": "3.53.0-canary.5",
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.53.0-canary.3"
43
+ "@payloadcms/plugin-cloud-storage": "3.53.0-canary.5"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@smithy/node-http-handler": "4.0.3",
47
- "payload": "3.53.0-canary.3"
47
+ "payload": "3.53.0-canary.5"
48
48
  },
49
49
  "peerDependencies": {
50
- "payload": "3.53.0-canary.3"
50
+ "payload": "3.53.0-canary.5"
51
51
  },
52
52
  "engines": {
53
53
  "node": "^18.20.2 || >=20.9.0"