sqs-consumer 10.2.1 → 10.3.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.
@@ -0,0 +1,32 @@
1
+ name: Annotate CI run with test results
2
+ on:
3
+ workflow_run:
4
+ workflows:
5
+ - "Run Tests"
6
+ types:
7
+ - completed
8
+ permissions:
9
+ actions: read
10
+ contents: read
11
+ checks: write
12
+ pull-requests: write
13
+
14
+ jobs:
15
+ annotate:
16
+ name: Annotate CI run with test results
17
+ runs-on: ubuntu-latest
18
+ if: ${{ github.event.workflow_run.conclusion != 'cancelled' }}
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ node-version: [18.x, 20.x, 22.x]
23
+ timeout-minutes: 5
24
+ steps:
25
+ - name: Annotate CI run with test results
26
+ uses: dorny/test-reporter@v1
27
+ with:
28
+ artifact: test-reports-${{ matrix.node-version }}
29
+ name: Test Results (${{matrix.node-version}}
30
+ path: "test-results.json"
31
+ reporter: mocha-json
32
+ token: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,42 @@
1
+ name: Comment PR Coverage
2
+ on:
3
+ pull_request:
4
+ branches:
5
+ - 'main'
6
+ permissions:
7
+ contents: read
8
+ pull-requests: write
9
+
10
+ jobs:
11
+ coverage_report:
12
+ name: Generate coverage report
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ node-version: [20.x]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Use Node.js ${{ matrix.node-version }}
21
+ uses: actions/setup-node@v4
22
+ with:
23
+ node-version: ${{ matrix.node-version }}
24
+ cache: 'npm'
25
+
26
+ - name: Install Node Modules
27
+ run: npm ci
28
+
29
+ - name: Run Coverage Check
30
+ run: npm run lcov
31
+
32
+ - name: Setup LCOV
33
+ uses: hrishikesh-kadam/setup-lcov@v1
34
+
35
+ - name: Report code coverage
36
+ uses: zgosalvez/github-actions-report-lcov@v3
37
+ with:
38
+ coverage-files: coverage/lcov.info
39
+ minimum-coverage: 90
40
+ artifact-name: code-coverage-report
41
+ github-token: ${{ secrets.GITHUB_TOKEN }}
42
+ update-comment: true
@@ -8,6 +8,8 @@ on:
8
8
  - main
9
9
  permissions:
10
10
  contents: read
11
+ checks: write
12
+ pull-requests: write
11
13
 
12
14
  jobs:
13
15
  build:
@@ -34,7 +36,7 @@ jobs:
34
36
  - name: Run Tests and Linting
35
37
  run: npm run test
36
38
 
37
- - uses: actions/upload-artifact@v3
39
+ - uses: actions/upload-artifact@v4
38
40
  with:
39
41
  name: test-reports-${{ matrix.node-version }}
40
42
  path: test/reports/
package/CHANGELOG.md CHANGED
@@ -1,13 +1,12 @@
1
- ## [10.2.1](https://github.com/bbc/sqs-consumer/compare/v10.2.0...v10.2.1) (2024-04-30)
1
+ ## [10.3.0](https://github.com/bbc/sqs-consumer/compare/v10.2.1...v10.3.0) (2024-05-08)
2
2
 
3
3
 
4
- ### Bug Fixes
4
+ ### Features
5
5
 
6
- * build exclusive type files ([65008eb](https://github.com/bbc/sqs-consumer/commit/65008ebaab8aecbe806b8e7ab9be809de58518a9))
7
- * default extension for cjs ([bd9855b](https://github.com/bbc/sqs-consumer/commit/bd9855babedee1ea6506d8fc2901228e1cd31468))
8
- * types extension for cjs ([8bc6239](https://github.com/bbc/sqs-consumer/commit/8bc62396badf30bcf508309110a782aa6f4b9d8c))
6
+ * add the ability to extend errors from aws ([#496](https://github.com/bbc/sqs-consumer/issues/496)) ([f4b071b](https://github.com/bbc/sqs-consumer/commit/f4b071b05e6cee304fcf866fa813e791338359d2))
9
7
 
10
8
 
11
9
  ### Chores
12
10
 
13
- * updating repro links ([48f452e](https://github.com/bbc/sqs-consumer/commit/48f452ee935a563b3d0c1043b552947da84886ea))
11
+ * enhance ci reports ([#497](https://github.com/bbc/sqs-consumer/issues/497)) ([eded17a](https://github.com/bbc/sqs-consumer/commit/eded17adc06fe8414b7ea0732dd5cac2cd00f7e2))
12
+ * updating test-reporter ([645901d](https://github.com/bbc/sqs-consumer/commit/645901de5c60aa44dc45bc2ac5e5981581004b39))
@@ -29,6 +29,7 @@ export declare class Consumer extends TypedEventEmitter {
29
29
  private isPolling;
30
30
  private stopRequestedAtTimestamp;
31
31
  abortController: AbortController;
32
+ private extendedAWSErrors;
32
33
  constructor(options: ConsumerOptions);
33
34
  /**
34
35
  * Creates a new SQS consumer.
@@ -36,6 +36,7 @@ class Consumer extends emitter_js_1.TypedEventEmitter {
36
36
  this.pollingCompleteWaitTimeMs = options.pollingCompleteWaitTimeMs ?? 0;
37
37
  this.shouldDeleteMessages = options.shouldDeleteMessages ?? true;
38
38
  this.alwaysAcknowledge = options.alwaysAcknowledge ?? false;
39
+ this.extendedAWSErrors = options.extendedAWSErrors ?? false;
39
40
  this.sqs =
40
41
  options.sqs ||
41
42
  new client_sqs_1.SQSClient({
@@ -214,7 +215,7 @@ class Consumer extends emitter_js_1.TypedEventEmitter {
214
215
  return result;
215
216
  }
216
217
  catch (err) {
217
- throw (0, errors_js_1.toSQSError)(err, `SQS receive message failed: ${err.message}`);
218
+ throw (0, errors_js_1.toSQSError)(err, `SQS receive message failed: ${err.message}`, this.extendedAWSErrors);
218
219
  }
219
220
  }
220
221
  /**
@@ -326,7 +327,7 @@ class Consumer extends emitter_js_1.TypedEventEmitter {
326
327
  return await this.sqs.send(new client_sqs_1.ChangeMessageVisibilityCommand(input), this.sqsSendOptions);
327
328
  }
328
329
  catch (err) {
329
- this.emit("error", (0, errors_js_1.toSQSError)(err, `Error changing visibility timeout: ${err.message}`), message);
330
+ this.emit("error", (0, errors_js_1.toSQSError)(err, `Error changing visibility timeout: ${err.message}`, this.extendedAWSErrors), message);
330
331
  }
331
332
  }
332
333
  /**
@@ -347,7 +348,7 @@ class Consumer extends emitter_js_1.TypedEventEmitter {
347
348
  return await this.sqs.send(new client_sqs_1.ChangeMessageVisibilityBatchCommand(params), this.sqsSendOptions);
348
349
  }
349
350
  catch (err) {
350
- this.emit("error", (0, errors_js_1.toSQSError)(err, `Error changing visibility timeout: ${err.message}`), messages);
351
+ this.emit("error", (0, errors_js_1.toSQSError)(err, `Error changing visibility timeout: ${err.message}`, this.extendedAWSErrors), messages);
351
352
  }
352
353
  }
353
354
  /**
@@ -426,7 +427,7 @@ class Consumer extends emitter_js_1.TypedEventEmitter {
426
427
  await this.sqs.send(new client_sqs_1.DeleteMessageCommand(deleteParams), this.sqsSendOptions);
427
428
  }
428
429
  catch (err) {
429
- throw (0, errors_js_1.toSQSError)(err, `SQS delete message failed: ${err.message}`);
430
+ throw (0, errors_js_1.toSQSError)(err, `SQS delete message failed: ${err.message}`, this.extendedAWSErrors);
430
431
  }
431
432
  }
432
433
  /**
@@ -454,7 +455,7 @@ class Consumer extends emitter_js_1.TypedEventEmitter {
454
455
  await this.sqs.send(new client_sqs_1.DeleteMessageBatchCommand(deleteParams), this.sqsSendOptions);
455
456
  }
456
457
  catch (err) {
457
- throw (0, errors_js_1.toSQSError)(err, `SQS delete message failed: ${err.message}`);
458
+ throw (0, errors_js_1.toSQSError)(err, `SQS delete message failed: ${err.message}`, this.extendedAWSErrors);
458
459
  }
459
460
  }
460
461
  }
@@ -5,7 +5,9 @@ declare class SQSError extends Error {
5
5
  service: string;
6
6
  time: Date;
7
7
  retryable: boolean;
8
- fault: "client" | "server";
8
+ fault: AWSError["$fault"];
9
+ response?: AWSError["$response"];
10
+ metadata?: AWSError["$metadata"];
9
11
  constructor(message: string);
10
12
  }
11
13
  declare class TimeoutError extends Error {
@@ -28,7 +30,7 @@ declare function isConnectionError(err: Error): boolean;
28
30
  * @param err The error object that was received.
29
31
  * @param message The message to send with the error.
30
32
  */
31
- declare function toSQSError(err: AWSError, message: string): SQSError;
33
+ declare function toSQSError(err: AWSError, message: string, extendedAWSErrors: boolean): SQSError;
32
34
  /**
33
35
  * Formats an Error to the StandardError type.
34
36
  * @param err The error object that was received.
@@ -53,7 +53,7 @@ exports.isConnectionError = isConnectionError;
53
53
  * @param err The error object that was received.
54
54
  * @param message The message to send with the error.
55
55
  */
56
- function toSQSError(err, message) {
56
+ function toSQSError(err, message, extendedAWSErrors) {
57
57
  const sqsError = new SQSError(message);
58
58
  sqsError.code = err.name;
59
59
  sqsError.statusCode = err.$metadata?.httpStatusCode;
@@ -61,6 +61,10 @@ function toSQSError(err, message) {
61
61
  sqsError.service = err.$service;
62
62
  sqsError.fault = err.$fault;
63
63
  sqsError.time = new Date();
64
+ if (extendedAWSErrors) {
65
+ sqsError.response = err.$response;
66
+ sqsError.metadata = err.$metadata;
67
+ }
64
68
  return sqsError;
65
69
  }
66
70
  exports.toSQSError = toSQSError;
@@ -139,6 +139,11 @@ export interface ConsumerOptions {
139
139
  * example to add middlewares.
140
140
  */
141
141
  postReceiveMessageCallback?(): Promise<void>;
142
+ /**
143
+ * Set this to `true` if you want to receive additional information about the error
144
+ * that occurred from AWS, such as the response and metadata.
145
+ */
146
+ extendedAWSErrors?: boolean;
142
147
  }
143
148
  /**
144
149
  * A subset of the ConsumerOptions that can be updated at runtime.
@@ -222,7 +227,7 @@ export type AWSError = {
222
227
  /**
223
228
  * Name, eg. ConditionalCheckFailedException
224
229
  */
225
- name: string;
230
+ readonly name: string;
226
231
  /**
227
232
  * Human-readable error response message
228
233
  */
@@ -234,7 +239,25 @@ export type AWSError = {
234
239
  /**
235
240
  * Whether the client or server are at fault.
236
241
  */
237
- readonly $fault?: "client" | "server";
242
+ readonly $fault: "client" | "server";
243
+ /**
244
+ * Represents an HTTP message as received in reply to a request
245
+ */
246
+ readonly $response?: {
247
+ /**
248
+ * The status code of the HTTP response.
249
+ */
250
+ statusCode?: number;
251
+ /**
252
+ * The headers of the HTTP message.
253
+ */
254
+ headers: Record<string, string>;
255
+ /**
256
+ * The body of the HTTP message.
257
+ * Can be: ArrayBuffer | ArrayBufferView | string | Uint8Array | Readable | ReadableStream
258
+ */
259
+ body?: any;
260
+ };
238
261
  /**
239
262
  * The service that encountered the exception.
240
263
  */
@@ -248,32 +271,32 @@ export type AWSError = {
248
271
  */
249
272
  readonly throttling?: boolean;
250
273
  };
251
- $metadata?: {
274
+ readonly $metadata: {
252
275
  /**
253
276
  * The status code of the last HTTP response received for this operation.
254
277
  */
255
- httpStatusCode?: number;
278
+ readonly httpStatusCode?: number;
256
279
  /**
257
280
  * A unique identifier for the last request sent for this operation. Often
258
281
  * requested by AWS service teams to aid in debugging.
259
282
  */
260
- requestId?: string;
283
+ readonly requestId?: string;
261
284
  /**
262
285
  * A secondary identifier for the last request sent. Used for debugging.
263
286
  */
264
- extendedRequestId?: string;
287
+ readonly extendedRequestId?: string;
265
288
  /**
266
289
  * A tertiary identifier for the last request sent. Used for debugging.
267
290
  */
268
- cfId?: string;
291
+ readonly cfId?: string;
269
292
  /**
270
293
  * The number of times this operation was attempted.
271
294
  */
272
- attempts?: number;
295
+ readonly attempts?: number;
273
296
  /**
274
297
  * The total amount of time (in milliseconds) that was spent waiting between
275
298
  * retry attempts.
276
299
  */
277
- totalRetryDelay?: number;
300
+ readonly totalRetryDelay?: number;
278
301
  };
279
302
  };
@@ -29,6 +29,7 @@ export declare class Consumer extends TypedEventEmitter {
29
29
  private isPolling;
30
30
  private stopRequestedAtTimestamp;
31
31
  abortController: AbortController;
32
+ private extendedAWSErrors;
32
33
  constructor(options: ConsumerOptions);
33
34
  /**
34
35
  * Creates a new SQS consumer.
@@ -33,6 +33,7 @@ export class Consumer extends TypedEventEmitter {
33
33
  this.pollingCompleteWaitTimeMs = options.pollingCompleteWaitTimeMs ?? 0;
34
34
  this.shouldDeleteMessages = options.shouldDeleteMessages ?? true;
35
35
  this.alwaysAcknowledge = options.alwaysAcknowledge ?? false;
36
+ this.extendedAWSErrors = options.extendedAWSErrors ?? false;
36
37
  this.sqs =
37
38
  options.sqs ||
38
39
  new SQSClient({
@@ -211,7 +212,7 @@ export class Consumer extends TypedEventEmitter {
211
212
  return result;
212
213
  }
213
214
  catch (err) {
214
- throw toSQSError(err, `SQS receive message failed: ${err.message}`);
215
+ throw toSQSError(err, `SQS receive message failed: ${err.message}`, this.extendedAWSErrors);
215
216
  }
216
217
  }
217
218
  /**
@@ -323,7 +324,7 @@ export class Consumer extends TypedEventEmitter {
323
324
  return await this.sqs.send(new ChangeMessageVisibilityCommand(input), this.sqsSendOptions);
324
325
  }
325
326
  catch (err) {
326
- this.emit("error", toSQSError(err, `Error changing visibility timeout: ${err.message}`), message);
327
+ this.emit("error", toSQSError(err, `Error changing visibility timeout: ${err.message}`, this.extendedAWSErrors), message);
327
328
  }
328
329
  }
329
330
  /**
@@ -344,7 +345,7 @@ export class Consumer extends TypedEventEmitter {
344
345
  return await this.sqs.send(new ChangeMessageVisibilityBatchCommand(params), this.sqsSendOptions);
345
346
  }
346
347
  catch (err) {
347
- this.emit("error", toSQSError(err, `Error changing visibility timeout: ${err.message}`), messages);
348
+ this.emit("error", toSQSError(err, `Error changing visibility timeout: ${err.message}`, this.extendedAWSErrors), messages);
348
349
  }
349
350
  }
350
351
  /**
@@ -423,7 +424,7 @@ export class Consumer extends TypedEventEmitter {
423
424
  await this.sqs.send(new DeleteMessageCommand(deleteParams), this.sqsSendOptions);
424
425
  }
425
426
  catch (err) {
426
- throw toSQSError(err, `SQS delete message failed: ${err.message}`);
427
+ throw toSQSError(err, `SQS delete message failed: ${err.message}`, this.extendedAWSErrors);
427
428
  }
428
429
  }
429
430
  /**
@@ -451,7 +452,7 @@ export class Consumer extends TypedEventEmitter {
451
452
  await this.sqs.send(new DeleteMessageBatchCommand(deleteParams), this.sqsSendOptions);
452
453
  }
453
454
  catch (err) {
454
- throw toSQSError(err, `SQS delete message failed: ${err.message}`);
455
+ throw toSQSError(err, `SQS delete message failed: ${err.message}`, this.extendedAWSErrors);
455
456
  }
456
457
  }
457
458
  }
@@ -5,7 +5,9 @@ declare class SQSError extends Error {
5
5
  service: string;
6
6
  time: Date;
7
7
  retryable: boolean;
8
- fault: "client" | "server";
8
+ fault: AWSError["$fault"];
9
+ response?: AWSError["$response"];
10
+ metadata?: AWSError["$metadata"];
9
11
  constructor(message: string);
10
12
  }
11
13
  declare class TimeoutError extends Error {
@@ -28,7 +30,7 @@ declare function isConnectionError(err: Error): boolean;
28
30
  * @param err The error object that was received.
29
31
  * @param message The message to send with the error.
30
32
  */
31
- declare function toSQSError(err: AWSError, message: string): SQSError;
33
+ declare function toSQSError(err: AWSError, message: string, extendedAWSErrors: boolean): SQSError;
32
34
  /**
33
35
  * Formats an Error to the StandardError type.
34
36
  * @param err The error object that was received.
@@ -47,7 +47,7 @@ function isConnectionError(err) {
47
47
  * @param err The error object that was received.
48
48
  * @param message The message to send with the error.
49
49
  */
50
- function toSQSError(err, message) {
50
+ function toSQSError(err, message, extendedAWSErrors) {
51
51
  const sqsError = new SQSError(message);
52
52
  sqsError.code = err.name;
53
53
  sqsError.statusCode = err.$metadata?.httpStatusCode;
@@ -55,6 +55,10 @@ function toSQSError(err, message) {
55
55
  sqsError.service = err.$service;
56
56
  sqsError.fault = err.$fault;
57
57
  sqsError.time = new Date();
58
+ if (extendedAWSErrors) {
59
+ sqsError.response = err.$response;
60
+ sqsError.metadata = err.$metadata;
61
+ }
58
62
  return sqsError;
59
63
  }
60
64
  /**
@@ -139,6 +139,11 @@ export interface ConsumerOptions {
139
139
  * example to add middlewares.
140
140
  */
141
141
  postReceiveMessageCallback?(): Promise<void>;
142
+ /**
143
+ * Set this to `true` if you want to receive additional information about the error
144
+ * that occurred from AWS, such as the response and metadata.
145
+ */
146
+ extendedAWSErrors?: boolean;
142
147
  }
143
148
  /**
144
149
  * A subset of the ConsumerOptions that can be updated at runtime.
@@ -222,7 +227,7 @@ export type AWSError = {
222
227
  /**
223
228
  * Name, eg. ConditionalCheckFailedException
224
229
  */
225
- name: string;
230
+ readonly name: string;
226
231
  /**
227
232
  * Human-readable error response message
228
233
  */
@@ -234,7 +239,25 @@ export type AWSError = {
234
239
  /**
235
240
  * Whether the client or server are at fault.
236
241
  */
237
- readonly $fault?: "client" | "server";
242
+ readonly $fault: "client" | "server";
243
+ /**
244
+ * Represents an HTTP message as received in reply to a request
245
+ */
246
+ readonly $response?: {
247
+ /**
248
+ * The status code of the HTTP response.
249
+ */
250
+ statusCode?: number;
251
+ /**
252
+ * The headers of the HTTP message.
253
+ */
254
+ headers: Record<string, string>;
255
+ /**
256
+ * The body of the HTTP message.
257
+ * Can be: ArrayBuffer | ArrayBufferView | string | Uint8Array | Readable | ReadableStream
258
+ */
259
+ body?: any;
260
+ };
238
261
  /**
239
262
  * The service that encountered the exception.
240
263
  */
@@ -248,32 +271,32 @@ export type AWSError = {
248
271
  */
249
272
  readonly throttling?: boolean;
250
273
  };
251
- $metadata?: {
274
+ readonly $metadata: {
252
275
  /**
253
276
  * The status code of the last HTTP response received for this operation.
254
277
  */
255
- httpStatusCode?: number;
278
+ readonly httpStatusCode?: number;
256
279
  /**
257
280
  * A unique identifier for the last request sent for this operation. Often
258
281
  * requested by AWS service teams to aid in debugging.
259
282
  */
260
- requestId?: string;
283
+ readonly requestId?: string;
261
284
  /**
262
285
  * A secondary identifier for the last request sent. Used for debugging.
263
286
  */
264
- extendedRequestId?: string;
287
+ readonly extendedRequestId?: string;
265
288
  /**
266
289
  * A tertiary identifier for the last request sent. Used for debugging.
267
290
  */
268
- cfId?: string;
291
+ readonly cfId?: string;
269
292
  /**
270
293
  * The number of times this operation was attempted.
271
294
  */
272
- attempts?: number;
295
+ readonly attempts?: number;
273
296
  /**
274
297
  * The total amount of time (in milliseconds) that was spent waiting between
275
298
  * retry attempts.
276
299
  */
277
- totalRetryDelay?: number;
300
+ readonly totalRetryDelay?: number;
278
301
  };
279
302
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqs-consumer",
3
- "version": "10.2.1",
3
+ "version": "10.3.0",
4
4
  "description": "Build SQS-based Node applications without the boilerplate",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.js",
@@ -27,7 +27,7 @@
27
27
  "build": "npm run clean && npm run compile && npm run add-package-jsons",
28
28
  "watch": "tsc --watch",
29
29
  "prepublishOnly": "npm run build",
30
- "test:unit": "mocha --recursive --full-trace --exit",
30
+ "test:unit": "mocha --recursive --full-trace --exit --reporter json > test/reports/test-results.json",
31
31
  "pretest:integration:init": "npm run build",
32
32
  "test:integration:init": "sh ./test/scripts/initIntTests.sh",
33
33
  "test:integration": "npm run test:integration:init && cucumber-js --config ./test/config/cucumber.mjs",
package/src/consumer.ts CHANGED
@@ -58,6 +58,7 @@ export class Consumer extends TypedEventEmitter {
58
58
  private isPolling = false;
59
59
  private stopRequestedAtTimestamp: number;
60
60
  public abortController: AbortController;
61
+ private extendedAWSErrors: boolean;
61
62
 
62
63
  constructor(options: ConsumerOptions) {
63
64
  super();
@@ -82,6 +83,7 @@ export class Consumer extends TypedEventEmitter {
82
83
  this.pollingCompleteWaitTimeMs = options.pollingCompleteWaitTimeMs ?? 0;
83
84
  this.shouldDeleteMessages = options.shouldDeleteMessages ?? true;
84
85
  this.alwaysAcknowledge = options.alwaysAcknowledge ?? false;
86
+ this.extendedAWSErrors = options.extendedAWSErrors ?? false;
85
87
  this.sqs =
86
88
  options.sqs ||
87
89
  new SQSClient({
@@ -297,7 +299,11 @@ export class Consumer extends TypedEventEmitter {
297
299
 
298
300
  return result;
299
301
  } catch (err) {
300
- throw toSQSError(err, `SQS receive message failed: ${err.message}`);
302
+ throw toSQSError(
303
+ err,
304
+ `SQS receive message failed: ${err.message}`,
305
+ this.extendedAWSErrors,
306
+ );
301
307
  }
302
308
  }
303
309
 
@@ -439,7 +445,11 @@ export class Consumer extends TypedEventEmitter {
439
445
  } catch (err) {
440
446
  this.emit(
441
447
  "error",
442
- toSQSError(err, `Error changing visibility timeout: ${err.message}`),
448
+ toSQSError(
449
+ err,
450
+ `Error changing visibility timeout: ${err.message}`,
451
+ this.extendedAWSErrors,
452
+ ),
443
453
  message,
444
454
  );
445
455
  }
@@ -470,7 +480,11 @@ export class Consumer extends TypedEventEmitter {
470
480
  } catch (err) {
471
481
  this.emit(
472
482
  "error",
473
- toSQSError(err, `Error changing visibility timeout: ${err.message}`),
483
+ toSQSError(
484
+ err,
485
+ `Error changing visibility timeout: ${err.message}`,
486
+ this.extendedAWSErrors,
487
+ ),
474
488
  messages,
475
489
  );
476
490
  }
@@ -567,7 +581,11 @@ export class Consumer extends TypedEventEmitter {
567
581
  this.sqsSendOptions,
568
582
  );
569
583
  } catch (err) {
570
- throw toSQSError(err, `SQS delete message failed: ${err.message}`);
584
+ throw toSQSError(
585
+ err,
586
+ `SQS delete message failed: ${err.message}`,
587
+ this.extendedAWSErrors,
588
+ );
571
589
  }
572
590
  }
573
591
 
@@ -601,7 +619,11 @@ export class Consumer extends TypedEventEmitter {
601
619
  this.sqsSendOptions,
602
620
  );
603
621
  } catch (err) {
604
- throw toSQSError(err, `SQS delete message failed: ${err.message}`);
622
+ throw toSQSError(
623
+ err,
624
+ `SQS delete message failed: ${err.message}`,
625
+ this.extendedAWSErrors,
626
+ );
605
627
  }
606
628
  }
607
629
  }
package/src/errors.ts CHANGED
@@ -6,7 +6,9 @@ class SQSError extends Error {
6
6
  service: string;
7
7
  time: Date;
8
8
  retryable: boolean;
9
- fault: "client" | "server";
9
+ fault: AWSError["$fault"];
10
+ response?: AWSError["$response"];
11
+ metadata?: AWSError["$metadata"];
10
12
 
11
13
  constructor(message: string) {
12
14
  super(message);
@@ -67,7 +69,11 @@ function isConnectionError(err: Error): boolean {
67
69
  * @param err The error object that was received.
68
70
  * @param message The message to send with the error.
69
71
  */
70
- function toSQSError(err: AWSError, message: string): SQSError {
72
+ function toSQSError(
73
+ err: AWSError,
74
+ message: string,
75
+ extendedAWSErrors: boolean,
76
+ ): SQSError {
71
77
  const sqsError = new SQSError(message);
72
78
  sqsError.code = err.name;
73
79
  sqsError.statusCode = err.$metadata?.httpStatusCode;
@@ -76,6 +82,11 @@ function toSQSError(err: AWSError, message: string): SQSError {
76
82
  sqsError.fault = err.$fault;
77
83
  sqsError.time = new Date();
78
84
 
85
+ if (extendedAWSErrors) {
86
+ sqsError.response = err.$response;
87
+ sqsError.metadata = err.$metadata;
88
+ }
89
+
79
90
  return sqsError;
80
91
  }
81
92
 
package/src/types.ts CHANGED
@@ -140,6 +140,11 @@ export interface ConsumerOptions {
140
140
  * example to add middlewares.
141
141
  */
142
142
  postReceiveMessageCallback?(): Promise<void>;
143
+ /**
144
+ * Set this to `true` if you want to receive additional information about the error
145
+ * that occurred from AWS, such as the response and metadata.
146
+ */
147
+ extendedAWSErrors?: boolean;
143
148
  }
144
149
 
145
150
  /**
@@ -231,7 +236,7 @@ export type AWSError = {
231
236
  /**
232
237
  * Name, eg. ConditionalCheckFailedException
233
238
  */
234
- name: string;
239
+ readonly name: string;
235
240
 
236
241
  /**
237
242
  * Human-readable error response message
@@ -246,7 +251,26 @@ export type AWSError = {
246
251
  /**
247
252
  * Whether the client or server are at fault.
248
253
  */
249
- readonly $fault?: "client" | "server";
254
+ readonly $fault: "client" | "server";
255
+
256
+ /**
257
+ * Represents an HTTP message as received in reply to a request
258
+ */
259
+ readonly $response?: {
260
+ /**
261
+ * The status code of the HTTP response.
262
+ */
263
+ statusCode?: number;
264
+ /**
265
+ * The headers of the HTTP message.
266
+ */
267
+ headers: Record<string, string>;
268
+ /**
269
+ * The body of the HTTP message.
270
+ * Can be: ArrayBuffer | ArrayBufferView | string | Uint8Array | Readable | ReadableStream
271
+ */
272
+ body?: any;
273
+ };
250
274
 
251
275
  /**
252
276
  * The service that encountered the exception.
@@ -263,37 +287,37 @@ export type AWSError = {
263
287
  readonly throttling?: boolean;
264
288
  };
265
289
 
266
- $metadata?: {
290
+ readonly $metadata: {
267
291
  /**
268
292
  * The status code of the last HTTP response received for this operation.
269
293
  */
270
- httpStatusCode?: number;
294
+ readonly httpStatusCode?: number;
271
295
 
272
296
  /**
273
297
  * A unique identifier for the last request sent for this operation. Often
274
298
  * requested by AWS service teams to aid in debugging.
275
299
  */
276
- requestId?: string;
300
+ readonly requestId?: string;
277
301
 
278
302
  /**
279
303
  * A secondary identifier for the last request sent. Used for debugging.
280
304
  */
281
- extendedRequestId?: string;
305
+ readonly extendedRequestId?: string;
282
306
 
283
307
  /**
284
308
  * A tertiary identifier for the last request sent. Used for debugging.
285
309
  */
286
- cfId?: string;
310
+ readonly cfId?: string;
287
311
 
288
312
  /**
289
313
  * The number of times this operation was attempted.
290
314
  */
291
- attempts?: number;
315
+ readonly attempts?: number;
292
316
 
293
317
  /**
294
318
  * The total amount of time (in milliseconds) that was spent waiting between
295
319
  * retry attempts.
296
320
  */
297
- totalRetryDelay?: number;
321
+ readonly totalRetryDelay?: number;
298
322
  };
299
323
  };