@payloadcms/storage-s3 3.52.0-internal.8a9caef → 3.53.0-internal.2dadf5b

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,aA4FT,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, {
@@ -64,7 +70,13 @@ export const getHandler = ({ bucket, collection, getStorageClient, signedDownloa
64
70
  });
65
71
  }
66
72
  let headers = new Headers(incomingHeaders);
67
- headers.append('Content-Length', String(object.ContentLength));
73
+ // Only include Content-Length when it’s present and strictly numeric.
74
+ // This prevents "Parse Error: Invalid character in Content-Length" when providers (e.g., MinIO)
75
+ // return undefined or a non-numeric value.
76
+ const contentLength = String(object.ContentLength);
77
+ if (contentLength && !isNaN(Number(contentLength))) {
78
+ headers.append('Content-Length', contentLength);
79
+ }
68
80
  headers.append('Content-Type', String(object.ContentType));
69
81
  headers.append('Accept-Ranges', String(object.AcceptRanges));
70
82
  headers.append('ETag', String(object.ETag));
@@ -81,20 +93,29 @@ export const getHandler = ({ bucket, collection, getStorageClient, signedDownloa
81
93
  status: 304
82
94
  });
83
95
  }
84
- // On error, manually destroy stream to close socket
85
- if (object.Body && isNodeReadableStream(object.Body)) {
86
- const stream = object.Body;
87
- stream.on('error', (err)=>{
88
- req.payload.logger.error({
89
- err,
90
- key,
91
- msg: 'Error streaming S3 object, destroying stream'
92
- });
93
- 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
94
103
  });
95
104
  }
96
- const bodyBuffer = await streamToBuffer(object.Body);
97
- 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, {
98
119
  headers,
99
120
  status: 200
100
121
  });
@@ -110,7 +131,12 @@ export const getHandler = ({ bucket, collection, getStorageClient, signedDownloa
110
131
  status: 500
111
132
  });
112
133
  } finally{
113
- destroyStream(object);
134
+ if (!streamed) {
135
+ abortRequestAndDestroyStream({
136
+ abortController,
137
+ object
138
+ });
139
+ }
114
140
  }
115
141
  };
116
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 headers.append('Content-Length', String(object.ContentLength))\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","append","String","ContentLength","ContentType","AcceptRanges","ETag","etagFromHeaders","get","objectEtag","upload","modifyResponseHeaders","stream","on","err","payload","logger","error","msg","bodyBuffer","NoSuchKey"],"mappings":"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"}
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.52.0-internal.8a9caef",
3
+ "version": "3.53.0-internal.2dadf5b",
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.52.0-internal.8a9caef"
43
+ "@payloadcms/plugin-cloud-storage": "3.53.0-internal.2dadf5b"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@smithy/node-http-handler": "4.0.3",
47
- "payload": "3.52.0-internal.8a9caef"
47
+ "payload": "3.53.0-internal.2dadf5b"
48
48
  },
49
49
  "peerDependencies": {
50
- "payload": "3.52.0-internal.8a9caef"
50
+ "payload": "3.53.0-internal.2dadf5b"
51
51
  },
52
52
  "engines": {
53
53
  "node": "^18.20.2 || >=20.9.0"