graphile-presigned-url-plugin 1.15.1 → 1.16.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/esm/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export { mintPhysicalBucketName, provisionAndRecordPhysicalBucket, resolveS3, re
38
38
  export { createPresignedUrlPlugin, PresignedUrlPlugin } from './plugin';
39
39
  export { PresignedUrlPreset } from './preset';
40
40
  export { type WithPgClient, withRequestPgClient } from './request-pg-client';
41
+ export { describeS3Failure, s3FailureError } from './s3-failure';
41
42
  export { copyS3Object, deleteS3Object, generatePresignedGetUrl, generatePresignedPutUrl, headObject, readObjectPrefix } from './s3-signer';
42
43
  export { clearBucketCache, clearStorageModuleCache, getBucketConfig, isS3BucketProvisioned, loadAllStorageModules, markS3BucketProvisioned, resolveStorageConfigFromCodec, resolveStorageModuleByFileId } from './storage-module-cache';
43
44
  export type { BucketConfig, BucketNameResolver, EnsureBucketProvisioned, PresignedUrlPluginOptions, RequestUploadUrlInput, RequestUploadUrlPayload, S3Config, S3ConfigOrGetter, StorageModuleConfig, } from './types';
package/esm/index.js CHANGED
@@ -36,5 +36,6 @@ export { mintPhysicalBucketName, provisionAndRecordPhysicalBucket, resolveS3, re
36
36
  export { createPresignedUrlPlugin, PresignedUrlPlugin } from './plugin';
37
37
  export { PresignedUrlPreset } from './preset';
38
38
  export { withRequestPgClient } from './request-pg-client';
39
+ export { describeS3Failure, s3FailureError } from './s3-failure';
39
40
  export { copyS3Object, deleteS3Object, generatePresignedGetUrl, generatePresignedPutUrl, headObject, readObjectPrefix } from './s3-signer';
40
41
  export { clearBucketCache, clearStorageModuleCache, getBucketConfig, isS3BucketProvisioned, loadAllStorageModules, markS3BucketProvisioned, resolveStorageConfigFromCodec, resolveStorageModuleByFileId } from './storage-module-cache';
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { Logger } from '@pgpmjs/logger';
12
12
  import { withRequestPgClient } from './request-pg-client';
13
+ import { s3FailureError } from './s3-failure';
13
14
  import { isS3BucketProvisioned, markS3BucketProvisioned } from './storage-module-cache';
14
15
  const log = new Logger('graphile-presigned-url:physical-bucket');
15
16
  /**
@@ -91,7 +92,15 @@ export async function provisionAndRecordPhysicalBucket(options, withPgClient, st
91
92
  const s3BucketName = mintPhysicalBucketName(options, databaseId, bucket.key);
92
93
  if (options.ensureBucketProvisioned && !isS3BucketProvisioned(s3BucketName)) {
93
94
  log.info(`Lazy-provisioning S3 bucket "${s3BucketName}" for database ${databaseId}`);
94
- await options.ensureBucketProvisioned(s3BucketName, bucket.type, databaseId, allowedOrigins);
95
+ try {
96
+ await options.ensureBucketProvisioned(s3BucketName, bucket.type, databaseId, allowedOrigins);
97
+ }
98
+ catch (err) {
99
+ // The first upload to a bucket is where an unreachable object store is
100
+ // discovered, and the transport's own message is routinely empty: name the
101
+ // endpoint it could not reach so the response says what is misconfigured.
102
+ throw s3FailureError('BUCKET_PROVISION_FAILED', { endpoint: resolveS3(options).endpoint, bucket: s3BucketName, databaseId }, err);
103
+ }
95
104
  markS3BucketProvisioned(s3BucketName);
96
105
  log.info(`Lazy-provisioned S3 bucket "${s3BucketName}" successfully`);
97
106
  }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Turning an S3 transport failure into a reason a caller can act on.
3
+ *
4
+ * The AWS SDK routinely fails with an **empty** `message`: an unreachable
5
+ * endpoint arrives as an `AggregateError` whose own message is `''` and whose
6
+ * per-address `errors` hold the `ECONNREFUSED`, and a hung socket arrives as a
7
+ * bare wrapper around its `cause`. Anything that reports `err.message` verbatim
8
+ * therefore hands the client a blank reason — which is how a server signing
9
+ * against the wrong endpoint (a missing `CDN_ENDPOINT`, so the library default
10
+ * `http://localhost:9000`, i.e. the pod's own loopback) presents as an upload
11
+ * that fails with nothing to diagnose.
12
+ *
13
+ * So a failure is described by walking to where the words actually are, and
14
+ * re-thrown naming the coordinates it was talking to, with the original kept as
15
+ * `cause` for the server log.
16
+ */
17
+ /**
18
+ * Describe a thrown S3 error in one line, including the nested errors an
19
+ * `AggregateError` (or a `cause` chain) hides its actual reason in.
20
+ */
21
+ export declare function describeS3Failure(err: unknown, depth?: number): string;
22
+ /**
23
+ * Wrap a failed S3 call as an error whose message carries the operation, the
24
+ * coordinates it used, and the underlying reason — with the original as `cause`.
25
+ *
26
+ * `context` is rendered as `key=value` pairs in the order given; entries with no
27
+ * value are dropped, so a connection without an explicit endpoint (real AWS)
28
+ * does not print an empty one.
29
+ */
30
+ export declare function s3FailureError(operation: string, context: Record<string, string | number | undefined | null>, err: unknown): Error;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Turning an S3 transport failure into a reason a caller can act on.
3
+ *
4
+ * The AWS SDK routinely fails with an **empty** `message`: an unreachable
5
+ * endpoint arrives as an `AggregateError` whose own message is `''` and whose
6
+ * per-address `errors` hold the `ECONNREFUSED`, and a hung socket arrives as a
7
+ * bare wrapper around its `cause`. Anything that reports `err.message` verbatim
8
+ * therefore hands the client a blank reason — which is how a server signing
9
+ * against the wrong endpoint (a missing `CDN_ENDPOINT`, so the library default
10
+ * `http://localhost:9000`, i.e. the pod's own loopback) presents as an upload
11
+ * that fails with nothing to diagnose.
12
+ *
13
+ * So a failure is described by walking to where the words actually are, and
14
+ * re-thrown naming the coordinates it was talking to, with the original kept as
15
+ * `cause` for the server log.
16
+ */
17
+ /** How far to walk `errors` / `cause` before the chain stops being informative. */
18
+ const MAX_DEPTH = 4;
19
+ /**
20
+ * Describe a thrown S3 error in one line, including the nested errors an
21
+ * `AggregateError` (or a `cause` chain) hides its actual reason in.
22
+ */
23
+ export function describeS3Failure(err, depth = 0) {
24
+ if (err === null || err === undefined)
25
+ return 'unknown error';
26
+ if (typeof err !== 'object')
27
+ return String(err);
28
+ const e = err;
29
+ const name = typeof e.name === 'string' && e.name !== 'Error' ? e.name : '';
30
+ const message = typeof e.message === 'string' ? e.message : '';
31
+ const head = message.length > 0 ? [name, message].filter(Boolean).join(': ') : name;
32
+ const status = e.$metadata?.httpStatusCode ? `HTTP ${e.$metadata.httpStatusCode}` : '';
33
+ let detail = '';
34
+ if (depth < MAX_DEPTH) {
35
+ const nested = Array.isArray(e.errors) ? e.errors : e.cause !== undefined ? [e.cause] : [];
36
+ const described = nested
37
+ .map((inner) => describeS3Failure(inner, depth + 1))
38
+ .filter((text) => text.length > 0 && text !== 'unknown error');
39
+ if (described.length > 0)
40
+ detail = `(${described.join('; ')})`;
41
+ }
42
+ const described = [head, status, detail].filter((part) => part.length > 0).join(' ');
43
+ return described.length > 0 ? described : 'unknown error';
44
+ }
45
+ /**
46
+ * Wrap a failed S3 call as an error whose message carries the operation, the
47
+ * coordinates it used, and the underlying reason — with the original as `cause`.
48
+ *
49
+ * `context` is rendered as `key=value` pairs in the order given; entries with no
50
+ * value are dropped, so a connection without an explicit endpoint (real AWS)
51
+ * does not print an empty one.
52
+ */
53
+ export function s3FailureError(operation, context, err) {
54
+ const coordinates = Object.entries(context)
55
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
56
+ .map(([key, value]) => `${key}=${value}`)
57
+ .join(' ');
58
+ const prefix = coordinates.length > 0 ? `${operation}: ${coordinates}` : operation;
59
+ return new Error(`${prefix}: ${describeS3Failure(err)}`, { cause: err });
60
+ }
package/esm/s3-signer.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CopyObjectCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, PutObjectCommand, } from '@aws-sdk/client-s3';
2
2
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
3
3
  import { Logger } from '@pgpmjs/logger';
4
+ import { s3FailureError } from './s3-failure';
4
5
  const log = new Logger('graphile-presigned-url:s3');
5
6
  /**
6
7
  * Generate a presigned PUT URL for uploading a file to S3.
@@ -23,7 +24,13 @@ export async function generatePresignedPutUrl(s3Config, key, contentType, conten
23
24
  ContentType: contentType,
24
25
  ContentLength: contentLength,
25
26
  });
26
- const url = await getSignedUrl(s3Config.client, command, { expiresIn });
27
+ let url;
28
+ try {
29
+ url = await getSignedUrl(s3Config.client, command, { expiresIn });
30
+ }
31
+ catch (err) {
32
+ throw s3FailureError('PRESIGN_PUT_FAILED', { endpoint: s3Config.endpoint, bucket: s3Config.bucket, key, contentType }, err);
33
+ }
27
34
  log.debug(`Generated presigned PUT URL for key=${key}, contentType=${contentType}, expires=${expiresIn}s`);
28
35
  return url;
29
36
  }
@@ -49,7 +56,13 @@ export async function generatePresignedGetUrl(s3Config, key, expiresIn = 3600, f
49
56
  params.ResponseContentDisposition = `attachment; filename="${sanitized}"`;
50
57
  }
51
58
  const command = new GetObjectCommand(params);
52
- const url = await getSignedUrl(s3Config.client, command, { expiresIn });
59
+ let url;
60
+ try {
61
+ url = await getSignedUrl(s3Config.client, command, { expiresIn });
62
+ }
63
+ catch (err) {
64
+ throw s3FailureError('PRESIGN_GET_FAILED', { endpoint: s3Config.endpoint, bucket: s3Config.bucket, key }, err);
65
+ }
53
66
  log.debug(`Generated presigned GET URL for key=${key}, expires=${expiresIn}s`);
54
67
  return url;
55
68
  }
package/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export { mintPhysicalBucketName, provisionAndRecordPhysicalBucket, resolveS3, re
38
38
  export { createPresignedUrlPlugin, PresignedUrlPlugin } from './plugin';
39
39
  export { PresignedUrlPreset } from './preset';
40
40
  export { type WithPgClient, withRequestPgClient } from './request-pg-client';
41
+ export { describeS3Failure, s3FailureError } from './s3-failure';
41
42
  export { copyS3Object, deleteS3Object, generatePresignedGetUrl, generatePresignedPutUrl, headObject, readObjectPrefix } from './s3-signer';
42
43
  export { clearBucketCache, clearStorageModuleCache, getBucketConfig, isS3BucketProvisioned, loadAllStorageModules, markS3BucketProvisioned, resolveStorageConfigFromCodec, resolveStorageModuleByFileId } from './storage-module-cache';
43
44
  export type { BucketConfig, BucketNameResolver, EnsureBucketProvisioned, PresignedUrlPluginOptions, RequestUploadUrlInput, RequestUploadUrlPayload, S3Config, S3ConfigOrGetter, StorageModuleConfig, } from './types';
package/index.js CHANGED
@@ -28,7 +28,7 @@
28
28
  * ```
29
29
  */
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.resolveStorageModuleByFileId = exports.resolveStorageConfigFromCodec = exports.markS3BucketProvisioned = exports.loadAllStorageModules = exports.isS3BucketProvisioned = exports.getBucketConfig = exports.clearStorageModuleCache = exports.clearBucketCache = exports.readObjectPrefix = exports.headObject = exports.generatePresignedPutUrl = exports.generatePresignedGetUrl = exports.deleteS3Object = exports.copyS3Object = exports.withRequestPgClient = exports.PresignedUrlPreset = exports.PresignedUrlPlugin = exports.createPresignedUrlPlugin = exports.resolveS3ForDatabase = exports.resolveS3 = exports.provisionAndRecordPhysicalBucket = exports.mintPhysicalBucketName = exports.resolveManagedUploadTarget = exports.finalizeStagedUpload = exports.buildFileProjection = exports.assertUploadAllowedByBucket = exports.getFileRefFieldBinding = exports.FileRefFieldNotRegisteredError = exports.clearFileRefFieldCache = exports.createDownloadUrlPlugin = exports.resolveDefaultBucket = exports.validateCustomKey = exports.confirmUploadedBytes = exports.CONFIRM_PREFIX_BYTES = void 0;
31
+ exports.resolveStorageModuleByFileId = exports.resolveStorageConfigFromCodec = exports.markS3BucketProvisioned = exports.loadAllStorageModules = exports.isS3BucketProvisioned = exports.getBucketConfig = exports.clearStorageModuleCache = exports.clearBucketCache = exports.readObjectPrefix = exports.headObject = exports.generatePresignedPutUrl = exports.generatePresignedGetUrl = exports.deleteS3Object = exports.copyS3Object = exports.s3FailureError = exports.describeS3Failure = exports.withRequestPgClient = exports.PresignedUrlPreset = exports.PresignedUrlPlugin = exports.createPresignedUrlPlugin = exports.resolveS3ForDatabase = exports.resolveS3 = exports.provisionAndRecordPhysicalBucket = exports.mintPhysicalBucketName = exports.resolveManagedUploadTarget = exports.finalizeStagedUpload = exports.buildFileProjection = exports.assertUploadAllowedByBucket = exports.getFileRefFieldBinding = exports.FileRefFieldNotRegisteredError = exports.clearFileRefFieldCache = exports.createDownloadUrlPlugin = exports.resolveDefaultBucket = exports.validateCustomKey = exports.confirmUploadedBytes = exports.CONFIRM_PREFIX_BYTES = void 0;
32
32
  var confirm_upload_1 = require("./confirm-upload");
33
33
  Object.defineProperty(exports, "CONFIRM_PREFIX_BYTES", { enumerable: true, get: function () { return confirm_upload_1.CONFIRM_PREFIX_BYTES; } });
34
34
  Object.defineProperty(exports, "confirmUploadedBytes", { enumerable: true, get: function () { return confirm_upload_1.confirmUploadedBytes; } });
@@ -59,6 +59,9 @@ var preset_1 = require("./preset");
59
59
  Object.defineProperty(exports, "PresignedUrlPreset", { enumerable: true, get: function () { return preset_1.PresignedUrlPreset; } });
60
60
  var request_pg_client_1 = require("./request-pg-client");
61
61
  Object.defineProperty(exports, "withRequestPgClient", { enumerable: true, get: function () { return request_pg_client_1.withRequestPgClient; } });
62
+ var s3_failure_1 = require("./s3-failure");
63
+ Object.defineProperty(exports, "describeS3Failure", { enumerable: true, get: function () { return s3_failure_1.describeS3Failure; } });
64
+ Object.defineProperty(exports, "s3FailureError", { enumerable: true, get: function () { return s3_failure_1.s3FailureError; } });
62
65
  var s3_signer_1 = require("./s3-signer");
63
66
  Object.defineProperty(exports, "copyS3Object", { enumerable: true, get: function () { return s3_signer_1.copyS3Object; } });
64
67
  Object.defineProperty(exports, "deleteS3Object", { enumerable: true, get: function () { return s3_signer_1.deleteS3Object; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphile-presigned-url-plugin",
3
- "version": "1.15.1",
3
+ "version": "1.16.0",
4
4
  "description": "Presigned URL upload plugin for PostGraphile v5 — requestUploadUrl mutation and downloadUrl computed field",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "homepage": "https://github.com/constructive-io/constructive",
@@ -62,5 +62,5 @@
62
62
  "@types/node": "^22.19.11",
63
63
  "makage": "^0.3.0"
64
64
  },
65
- "gitHead": "e35db12526094b515596ced2dd27a1ec8edd99d5"
65
+ "gitHead": "df6b6613c844b505813e5d02d3a4afd918b74eab"
66
66
  }
@@ -16,6 +16,7 @@ exports.resolveS3ForDatabase = resolveS3ForDatabase;
16
16
  exports.provisionAndRecordPhysicalBucket = provisionAndRecordPhysicalBucket;
17
17
  const logger_1 = require("@pgpmjs/logger");
18
18
  const request_pg_client_1 = require("./request-pg-client");
19
+ const s3_failure_1 = require("./s3-failure");
19
20
  const storage_module_cache_1 = require("./storage-module-cache");
20
21
  const log = new logger_1.Logger('graphile-presigned-url:physical-bucket');
21
22
  /**
@@ -97,7 +98,15 @@ async function provisionAndRecordPhysicalBucket(options, withPgClient, storageCo
97
98
  const s3BucketName = mintPhysicalBucketName(options, databaseId, bucket.key);
98
99
  if (options.ensureBucketProvisioned && !(0, storage_module_cache_1.isS3BucketProvisioned)(s3BucketName)) {
99
100
  log.info(`Lazy-provisioning S3 bucket "${s3BucketName}" for database ${databaseId}`);
100
- await options.ensureBucketProvisioned(s3BucketName, bucket.type, databaseId, allowedOrigins);
101
+ try {
102
+ await options.ensureBucketProvisioned(s3BucketName, bucket.type, databaseId, allowedOrigins);
103
+ }
104
+ catch (err) {
105
+ // The first upload to a bucket is where an unreachable object store is
106
+ // discovered, and the transport's own message is routinely empty: name the
107
+ // endpoint it could not reach so the response says what is misconfigured.
108
+ throw (0, s3_failure_1.s3FailureError)('BUCKET_PROVISION_FAILED', { endpoint: resolveS3(options).endpoint, bucket: s3BucketName, databaseId }, err);
109
+ }
101
110
  (0, storage_module_cache_1.markS3BucketProvisioned)(s3BucketName);
102
111
  log.info(`Lazy-provisioned S3 bucket "${s3BucketName}" successfully`);
103
112
  }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Turning an S3 transport failure into a reason a caller can act on.
3
+ *
4
+ * The AWS SDK routinely fails with an **empty** `message`: an unreachable
5
+ * endpoint arrives as an `AggregateError` whose own message is `''` and whose
6
+ * per-address `errors` hold the `ECONNREFUSED`, and a hung socket arrives as a
7
+ * bare wrapper around its `cause`. Anything that reports `err.message` verbatim
8
+ * therefore hands the client a blank reason — which is how a server signing
9
+ * against the wrong endpoint (a missing `CDN_ENDPOINT`, so the library default
10
+ * `http://localhost:9000`, i.e. the pod's own loopback) presents as an upload
11
+ * that fails with nothing to diagnose.
12
+ *
13
+ * So a failure is described by walking to where the words actually are, and
14
+ * re-thrown naming the coordinates it was talking to, with the original kept as
15
+ * `cause` for the server log.
16
+ */
17
+ /**
18
+ * Describe a thrown S3 error in one line, including the nested errors an
19
+ * `AggregateError` (or a `cause` chain) hides its actual reason in.
20
+ */
21
+ export declare function describeS3Failure(err: unknown, depth?: number): string;
22
+ /**
23
+ * Wrap a failed S3 call as an error whose message carries the operation, the
24
+ * coordinates it used, and the underlying reason — with the original as `cause`.
25
+ *
26
+ * `context` is rendered as `key=value` pairs in the order given; entries with no
27
+ * value are dropped, so a connection without an explicit endpoint (real AWS)
28
+ * does not print an empty one.
29
+ */
30
+ export declare function s3FailureError(operation: string, context: Record<string, string | number | undefined | null>, err: unknown): Error;
package/s3-failure.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * Turning an S3 transport failure into a reason a caller can act on.
4
+ *
5
+ * The AWS SDK routinely fails with an **empty** `message`: an unreachable
6
+ * endpoint arrives as an `AggregateError` whose own message is `''` and whose
7
+ * per-address `errors` hold the `ECONNREFUSED`, and a hung socket arrives as a
8
+ * bare wrapper around its `cause`. Anything that reports `err.message` verbatim
9
+ * therefore hands the client a blank reason — which is how a server signing
10
+ * against the wrong endpoint (a missing `CDN_ENDPOINT`, so the library default
11
+ * `http://localhost:9000`, i.e. the pod's own loopback) presents as an upload
12
+ * that fails with nothing to diagnose.
13
+ *
14
+ * So a failure is described by walking to where the words actually are, and
15
+ * re-thrown naming the coordinates it was talking to, with the original kept as
16
+ * `cause` for the server log.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.describeS3Failure = describeS3Failure;
20
+ exports.s3FailureError = s3FailureError;
21
+ /** How far to walk `errors` / `cause` before the chain stops being informative. */
22
+ const MAX_DEPTH = 4;
23
+ /**
24
+ * Describe a thrown S3 error in one line, including the nested errors an
25
+ * `AggregateError` (or a `cause` chain) hides its actual reason in.
26
+ */
27
+ function describeS3Failure(err, depth = 0) {
28
+ if (err === null || err === undefined)
29
+ return 'unknown error';
30
+ if (typeof err !== 'object')
31
+ return String(err);
32
+ const e = err;
33
+ const name = typeof e.name === 'string' && e.name !== 'Error' ? e.name : '';
34
+ const message = typeof e.message === 'string' ? e.message : '';
35
+ const head = message.length > 0 ? [name, message].filter(Boolean).join(': ') : name;
36
+ const status = e.$metadata?.httpStatusCode ? `HTTP ${e.$metadata.httpStatusCode}` : '';
37
+ let detail = '';
38
+ if (depth < MAX_DEPTH) {
39
+ const nested = Array.isArray(e.errors) ? e.errors : e.cause !== undefined ? [e.cause] : [];
40
+ const described = nested
41
+ .map((inner) => describeS3Failure(inner, depth + 1))
42
+ .filter((text) => text.length > 0 && text !== 'unknown error');
43
+ if (described.length > 0)
44
+ detail = `(${described.join('; ')})`;
45
+ }
46
+ const described = [head, status, detail].filter((part) => part.length > 0).join(' ');
47
+ return described.length > 0 ? described : 'unknown error';
48
+ }
49
+ /**
50
+ * Wrap a failed S3 call as an error whose message carries the operation, the
51
+ * coordinates it used, and the underlying reason — with the original as `cause`.
52
+ *
53
+ * `context` is rendered as `key=value` pairs in the order given; entries with no
54
+ * value are dropped, so a connection without an explicit endpoint (real AWS)
55
+ * does not print an empty one.
56
+ */
57
+ function s3FailureError(operation, context, err) {
58
+ const coordinates = Object.entries(context)
59
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
60
+ .map(([key, value]) => `${key}=${value}`)
61
+ .join(' ');
62
+ const prefix = coordinates.length > 0 ? `${operation}: ${coordinates}` : operation;
63
+ return new Error(`${prefix}: ${describeS3Failure(err)}`, { cause: err });
64
+ }
package/s3-signer.js CHANGED
@@ -9,6 +9,7 @@ exports.headObject = headObject;
9
9
  const client_s3_1 = require("@aws-sdk/client-s3");
10
10
  const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
11
11
  const logger_1 = require("@pgpmjs/logger");
12
+ const s3_failure_1 = require("./s3-failure");
12
13
  const log = new logger_1.Logger('graphile-presigned-url:s3');
13
14
  /**
14
15
  * Generate a presigned PUT URL for uploading a file to S3.
@@ -31,7 +32,13 @@ async function generatePresignedPutUrl(s3Config, key, contentType, contentLength
31
32
  ContentType: contentType,
32
33
  ContentLength: contentLength,
33
34
  });
34
- const url = await (0, s3_request_presigner_1.getSignedUrl)(s3Config.client, command, { expiresIn });
35
+ let url;
36
+ try {
37
+ url = await (0, s3_request_presigner_1.getSignedUrl)(s3Config.client, command, { expiresIn });
38
+ }
39
+ catch (err) {
40
+ throw (0, s3_failure_1.s3FailureError)('PRESIGN_PUT_FAILED', { endpoint: s3Config.endpoint, bucket: s3Config.bucket, key, contentType }, err);
41
+ }
35
42
  log.debug(`Generated presigned PUT URL for key=${key}, contentType=${contentType}, expires=${expiresIn}s`);
36
43
  return url;
37
44
  }
@@ -57,7 +64,13 @@ async function generatePresignedGetUrl(s3Config, key, expiresIn = 3600, filename
57
64
  params.ResponseContentDisposition = `attachment; filename="${sanitized}"`;
58
65
  }
59
66
  const command = new client_s3_1.GetObjectCommand(params);
60
- const url = await (0, s3_request_presigner_1.getSignedUrl)(s3Config.client, command, { expiresIn });
67
+ let url;
68
+ try {
69
+ url = await (0, s3_request_presigner_1.getSignedUrl)(s3Config.client, command, { expiresIn });
70
+ }
71
+ catch (err) {
72
+ throw (0, s3_failure_1.s3FailureError)('PRESIGN_GET_FAILED', { endpoint: s3Config.endpoint, bucket: s3Config.bucket, key }, err);
73
+ }
61
74
  log.debug(`Generated presigned GET URL for key=${key}, expires=${expiresIn}s`);
62
75
  return url;
63
76
  }