@aligent/aws-wrappers 0.0.1
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/CLAUDE.md +172 -0
- package/README.md +286 -0
- package/docs/classes/DynamoDBService.md +353 -0
- package/docs/classes/S3Service.md +389 -0
- package/docs/classes/SNSService.md +95 -0
- package/docs/classes/SQSService.md +162 -0
- package/docs/classes/SSMService.md +157 -0
- package/docs/classes/SecretsManagerService.md +114 -0
- package/docs/classes/StepFunctionsService.md +134 -0
- package/docs/modules.md +15 -0
- package/package.json +32 -0
- package/src/dynamodb/dynamodb.d.ts +127 -0
- package/src/dynamodb/dynamodb.js +308 -0
- package/src/index.d.ts +7 -0
- package/src/index.js +17 -0
- package/src/s3/s3.d.ts +131 -0
- package/src/s3/s3.js +244 -0
- package/src/secrets-manager/secrets-manager.d.ts +78 -0
- package/src/secrets-manager/secrets-manager.js +152 -0
- package/src/sfn/sfn.d.ts +38 -0
- package/src/sfn/sfn.js +74 -0
- package/src/sns/sns.d.ts +48 -0
- package/src/sns/sns.js +110 -0
- package/src/sqs/sqs.d.ts +60 -0
- package/src/sqs/sqs.js +134 -0
- package/src/ssm/ssm.d.ts +84 -0
- package/src/ssm/ssm.js +144 -0
- package/src/util/redact.d.ts +18 -0
- package/src/util/redact.js +29 -0
- package/src/util/truncate.d.ts +15 -0
- package/src/util/truncate.js +36 -0
- package/tsconfig.lib.tsbuildinfo +1 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DynamoDBService = void 0;
|
|
4
|
+
const logger_1 = require("@aws-lambda-powertools/logger");
|
|
5
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
6
|
+
const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
|
|
7
|
+
const aws_xray_sdk_core_1 = require("aws-xray-sdk-core");
|
|
8
|
+
const redact_1 = require("../util/redact");
|
|
9
|
+
const BATCH_WRITE_MAX_ATTEMPTS = 5;
|
|
10
|
+
const BATCH_WRITE_BASE_DELAY_MS = 200;
|
|
11
|
+
/**
|
|
12
|
+
* Fields safe to log at INFO. Omits `Key` (may carry customer IDs / tenant IDs).
|
|
13
|
+
* `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
|
|
14
|
+
*/
|
|
15
|
+
const GET_ITEM_SAFE_FIELDS = [
|
|
16
|
+
'TableName',
|
|
17
|
+
'ConsistentRead',
|
|
18
|
+
'ProjectionExpression',
|
|
19
|
+
'ReturnConsumedCapacity',
|
|
20
|
+
'ExpressionAttributeNames',
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Fields safe to log at INFO. Omits `Item` (the payload itself) and
|
|
24
|
+
* `ExpressionAttributeValues` (values bound to ConditionExpression, often PII).
|
|
25
|
+
* `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
|
|
26
|
+
*/
|
|
27
|
+
const PUT_ITEM_SAFE_FIELDS = [
|
|
28
|
+
'TableName',
|
|
29
|
+
'ConditionExpression',
|
|
30
|
+
'ExpressionAttributeNames',
|
|
31
|
+
'ReturnValues',
|
|
32
|
+
'ReturnConsumedCapacity',
|
|
33
|
+
'ReturnItemCollectionMetrics',
|
|
34
|
+
'ReturnValuesOnConditionCheckFailure',
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Fields safe to log at INFO. Omits `Key` and `ExpressionAttributeValues`.
|
|
38
|
+
* `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
|
|
39
|
+
*/
|
|
40
|
+
const UPDATE_ITEM_SAFE_FIELDS = [
|
|
41
|
+
'TableName',
|
|
42
|
+
'UpdateExpression',
|
|
43
|
+
'ConditionExpression',
|
|
44
|
+
'ExpressionAttributeNames',
|
|
45
|
+
'ReturnValues',
|
|
46
|
+
'ReturnConsumedCapacity',
|
|
47
|
+
'ReturnItemCollectionMetrics',
|
|
48
|
+
'ReturnValuesOnConditionCheckFailure',
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Fields safe to log at INFO. Omits `Key` and `ExpressionAttributeValues`
|
|
52
|
+
* (the latter binds to ConditionExpression and may carry PII).
|
|
53
|
+
* `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
|
|
54
|
+
*/
|
|
55
|
+
const DELETE_ITEM_SAFE_FIELDS = [
|
|
56
|
+
'TableName',
|
|
57
|
+
'ConditionExpression',
|
|
58
|
+
'ExpressionAttributeNames',
|
|
59
|
+
'ReturnValues',
|
|
60
|
+
'ReturnConsumedCapacity',
|
|
61
|
+
'ReturnItemCollectionMetrics',
|
|
62
|
+
'ReturnValuesOnConditionCheckFailure',
|
|
63
|
+
];
|
|
64
|
+
/**
|
|
65
|
+
* Fields safe to log at INFO for `query` and `paginateItems`. Omits
|
|
66
|
+
* `ExpressionAttributeValues` (values often carry PII) and `ExclusiveStartKey`
|
|
67
|
+
* (pagination cursor includes Key shape). `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks
|
|
68
|
+
* the full input.
|
|
69
|
+
*/
|
|
70
|
+
const QUERY_SAFE_FIELDS = [
|
|
71
|
+
'TableName',
|
|
72
|
+
'IndexName',
|
|
73
|
+
'KeyConditionExpression',
|
|
74
|
+
'FilterExpression',
|
|
75
|
+
'ProjectionExpression',
|
|
76
|
+
'ExpressionAttributeNames',
|
|
77
|
+
'ConsistentRead',
|
|
78
|
+
'ScanIndexForward',
|
|
79
|
+
'Select',
|
|
80
|
+
'Limit',
|
|
81
|
+
'ReturnConsumedCapacity',
|
|
82
|
+
];
|
|
83
|
+
/**
|
|
84
|
+
* Fields safe to log at INFO for `scan` and `paginateScan`. Omits
|
|
85
|
+
* `ExpressionAttributeValues` and `ExclusiveStartKey`.
|
|
86
|
+
* `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
|
|
87
|
+
*/
|
|
88
|
+
const SCAN_SAFE_FIELDS = [
|
|
89
|
+
'TableName',
|
|
90
|
+
'IndexName',
|
|
91
|
+
'FilterExpression',
|
|
92
|
+
'ProjectionExpression',
|
|
93
|
+
'ExpressionAttributeNames',
|
|
94
|
+
'ConsistentRead',
|
|
95
|
+
'Select',
|
|
96
|
+
'Limit',
|
|
97
|
+
'Segment',
|
|
98
|
+
'TotalSegments',
|
|
99
|
+
'ReturnConsumedCapacity',
|
|
100
|
+
];
|
|
101
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
102
|
+
const backoffDelay = (attempt) => {
|
|
103
|
+
const exp = BATCH_WRITE_BASE_DELAY_MS * 2 ** attempt;
|
|
104
|
+
return exp + Math.random() * exp;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Wrapper around the AWS DynamoDB Document client providing structured
|
|
108
|
+
* Powertools logging and X-Ray tracing by default.
|
|
109
|
+
*
|
|
110
|
+
* Items are automatically marshalled / unmarshalled via the document client —
|
|
111
|
+
* callers work with plain TypeScript objects in both directions.
|
|
112
|
+
*/
|
|
113
|
+
class DynamoDBService {
|
|
114
|
+
client;
|
|
115
|
+
logger;
|
|
116
|
+
/**
|
|
117
|
+
* @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
|
|
118
|
+
* which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
|
|
119
|
+
* @param opts.client - Optional pre-configured `DynamoDBDocumentClient`.
|
|
120
|
+
* When supplied, the wrapper does not apply X-Ray instrumentation. When
|
|
121
|
+
* omitted, a default `DynamoDBClient` is wrapped with `captureAWSv3Client`
|
|
122
|
+
* *before* being passed to `DynamoDBDocumentClient.from`, so X-Ray
|
|
123
|
+
* tracing captures every DynamoDB call.
|
|
124
|
+
*/
|
|
125
|
+
constructor(opts) {
|
|
126
|
+
this.client =
|
|
127
|
+
opts?.client ??
|
|
128
|
+
lib_dynamodb_1.DynamoDBDocumentClient.from((0, aws_xray_sdk_core_1.captureAWSv3Client)(new client_dynamodb_1.DynamoDBClient({})), {
|
|
129
|
+
marshallOptions: { removeUndefinedValues: true },
|
|
130
|
+
});
|
|
131
|
+
this.logger = opts?.logger ?? new logger_1.Logger();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get an item from DynamoDB.
|
|
135
|
+
* @template K - Shape of the partition / sort key.
|
|
136
|
+
* @template R - Expected unmarshalled item shape.
|
|
137
|
+
* @returns The item, or `undefined` if not found.
|
|
138
|
+
*/
|
|
139
|
+
async getItem(input) {
|
|
140
|
+
this.logger.info('Getting DynamoDB item', {
|
|
141
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, GET_ITEM_SAFE_FIELDS),
|
|
142
|
+
});
|
|
143
|
+
const response = await this.client.send(new lib_dynamodb_1.GetCommand(input));
|
|
144
|
+
return response.Item;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Put an item into DynamoDB. The caller's `Item` is typed as `T`, which
|
|
148
|
+
* the document client marshalls automatically.
|
|
149
|
+
* @template T - Type of the item being stored.
|
|
150
|
+
*/
|
|
151
|
+
async putItem(input) {
|
|
152
|
+
this.logger.info('Putting DynamoDB item', {
|
|
153
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, PUT_ITEM_SAFE_FIELDS),
|
|
154
|
+
});
|
|
155
|
+
return this.client.send(new lib_dynamodb_1.PutCommand(input));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Update an item in DynamoDB. The `Attributes` field on the response is
|
|
159
|
+
* typed as `R` — the caller should choose `R` to match their
|
|
160
|
+
* `ReturnValues` setting:
|
|
161
|
+
* - `NONE` (default): no `Attributes` returned.
|
|
162
|
+
* - `ALL_OLD` / `ALL_NEW`: full item.
|
|
163
|
+
* - `UPDATED_OLD` / `UPDATED_NEW`: only updated attributes (partial).
|
|
164
|
+
* @template K - Shape of the partition / sort key.
|
|
165
|
+
* @template R - Expected shape of the returned `Attributes`.
|
|
166
|
+
*/
|
|
167
|
+
async updateItem(input) {
|
|
168
|
+
this.logger.info('Updating DynamoDB item', {
|
|
169
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, UPDATE_ITEM_SAFE_FIELDS),
|
|
170
|
+
});
|
|
171
|
+
const response = await this.client.send(new lib_dynamodb_1.UpdateCommand(input));
|
|
172
|
+
return response;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Delete an item from DynamoDB. The `Attributes` field on the response is
|
|
176
|
+
* typed as `R` — relevant when `ReturnValues: 'ALL_OLD'` is set.
|
|
177
|
+
* @template K - Shape of the partition / sort key.
|
|
178
|
+
* @template R - Expected shape of the returned `Attributes`.
|
|
179
|
+
*/
|
|
180
|
+
async deleteItem(input) {
|
|
181
|
+
this.logger.info('Deleting DynamoDB item', {
|
|
182
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, DELETE_ITEM_SAFE_FIELDS),
|
|
183
|
+
});
|
|
184
|
+
const response = await this.client.send(new lib_dynamodb_1.DeleteCommand(input));
|
|
185
|
+
return response;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Execute a DynamoDB Query. The full `QueryCommandOutput` is returned with
|
|
189
|
+
* `Items` typed as `T[]` so callers retain pagination metadata
|
|
190
|
+
* (`LastEvaluatedKey`, `Count`, etc.).
|
|
191
|
+
* @template T - Expected shape of each unmarshalled item.
|
|
192
|
+
*/
|
|
193
|
+
async query(input) {
|
|
194
|
+
this.logger.info('Querying DynamoDB', {
|
|
195
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, QUERY_SAFE_FIELDS),
|
|
196
|
+
});
|
|
197
|
+
const response = await this.client.send(new lib_dynamodb_1.QueryCommand(input));
|
|
198
|
+
return response;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Scan a DynamoDB table. The full `ScanCommandOutput` is returned with
|
|
202
|
+
* `Items` typed as `T[]` so callers retain pagination metadata.
|
|
203
|
+
*
|
|
204
|
+
* Scan reads every item in the table, so cost and latency grow linearly
|
|
205
|
+
* with table size; it is rarely the right tool in a runtime service.
|
|
206
|
+
* Prefer, in order:
|
|
207
|
+
*
|
|
208
|
+
* 1. `query` with the table's partition key.
|
|
209
|
+
* 2. `query` against a GSI or LSI whose key matches your access pattern.
|
|
210
|
+
* 3. A sparse GSI populated only for the items you need to enumerate.
|
|
211
|
+
* 4. A denormalised lookup item or table maintained on write.
|
|
212
|
+
*
|
|
213
|
+
* Legitimate scan use cases are mostly one-off admin work (export,
|
|
214
|
+
* migration, audit). For those, prefer the AWS CLI or Console rather than
|
|
215
|
+
* embedding a scan in a Lambda.
|
|
216
|
+
*
|
|
217
|
+
* @template T - Expected shape of each unmarshalled item.
|
|
218
|
+
*/
|
|
219
|
+
async scan(input) {
|
|
220
|
+
this.logger.info('Scanning DynamoDB', {
|
|
221
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, SCAN_SAFE_FIELDS),
|
|
222
|
+
});
|
|
223
|
+
const response = await this.client.send(new lib_dynamodb_1.ScanCommand(input));
|
|
224
|
+
return response;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Batch-get items from one or more DynamoDB tables.
|
|
228
|
+
*
|
|
229
|
+
* Note: this method is intentionally **not** generic. `BatchGet`'s
|
|
230
|
+
* `Responses` field is a multi-table `Record<string, item[]>` whose item
|
|
231
|
+
* shapes can differ per table — no single `T` can soundly describe it.
|
|
232
|
+
* Callers should narrow the result type at the call site.
|
|
233
|
+
*/
|
|
234
|
+
async batchGet(input) {
|
|
235
|
+
// Inline DEBUG check rather than `filterFieldsForLogLevel` because
|
|
236
|
+
// `RequestItems` is a `Record<tableName, KeysAndAttributes>` — the
|
|
237
|
+
// payload (`Keys[]`) lives inside the value, not as a top-level key
|
|
238
|
+
// the helper could pick or drop.
|
|
239
|
+
const isDebug = this.logger.getLevelName() === 'DEBUG';
|
|
240
|
+
this.logger.info('Batch getting DynamoDB items', {
|
|
241
|
+
input: isDebug ? input : { tables: Object.keys(input.RequestItems ?? {}) },
|
|
242
|
+
});
|
|
243
|
+
return this.client.send(new lib_dynamodb_1.BatchGetCommand(input));
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Batch-write items to DynamoDB, retrying `UnprocessedItems` with jittered
|
|
247
|
+
* exponential backoff. Up to 5 attempts (200ms base delay). Throws when
|
|
248
|
+
* items remain unprocessed after the final attempt.
|
|
249
|
+
*/
|
|
250
|
+
async batchWrite(input) {
|
|
251
|
+
// Inline DEBUG check rather than `filterFieldsForLogLevel` because
|
|
252
|
+
// `RequestItems` is a `Record<tableName, WriteRequest[]>` — the
|
|
253
|
+
// payload (`PutRequest.Item` / `DeleteRequest.Key`) lives inside the
|
|
254
|
+
// value, not as a top-level key the helper could pick or drop.
|
|
255
|
+
const isDebug = this.logger.getLevelName() === 'DEBUG';
|
|
256
|
+
this.logger.info('Batch writing DynamoDB items', {
|
|
257
|
+
input: isDebug ? input : { tables: Object.keys(input.RequestItems ?? {}) },
|
|
258
|
+
});
|
|
259
|
+
let current = input;
|
|
260
|
+
for (let attempt = 0; attempt < BATCH_WRITE_MAX_ATTEMPTS; attempt++) {
|
|
261
|
+
const response = await this.client.send(new lib_dynamodb_1.BatchWriteCommand(current));
|
|
262
|
+
const unprocessed = response.UnprocessedItems;
|
|
263
|
+
if (!unprocessed || Object.keys(unprocessed).length === 0)
|
|
264
|
+
return response;
|
|
265
|
+
this.logger.warn('Retrying unprocessed DynamoDB items', {
|
|
266
|
+
attempt: attempt + 1,
|
|
267
|
+
tables: Object.keys(unprocessed),
|
|
268
|
+
});
|
|
269
|
+
if (attempt < BATCH_WRITE_MAX_ATTEMPTS - 1)
|
|
270
|
+
await sleep(backoffDelay(attempt));
|
|
271
|
+
current = { ...input, RequestItems: unprocessed };
|
|
272
|
+
}
|
|
273
|
+
throw new Error(`batchWrite failed after ${BATCH_WRITE_MAX_ATTEMPTS} attempts`);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Paginate over Query results, yielding one unmarshalled item at a time.
|
|
277
|
+
* @template T - Expected shape of each yielded item.
|
|
278
|
+
*/
|
|
279
|
+
async *paginateItems(input) {
|
|
280
|
+
this.logger.info('Paginating DynamoDB query', {
|
|
281
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, QUERY_SAFE_FIELDS),
|
|
282
|
+
});
|
|
283
|
+
const paginator = (0, lib_dynamodb_1.paginateQuery)({ client: this.client }, input);
|
|
284
|
+
for await (const page of paginator) {
|
|
285
|
+
if (!page.Items)
|
|
286
|
+
continue;
|
|
287
|
+
for (const item of page.Items)
|
|
288
|
+
yield item;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Paginate over Scan results, yielding one unmarshalled item at a time.
|
|
293
|
+
* @template T - Expected shape of each yielded item.
|
|
294
|
+
*/
|
|
295
|
+
async *paginateScan(input) {
|
|
296
|
+
this.logger.info('Paginating DynamoDB scan', {
|
|
297
|
+
input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, SCAN_SAFE_FIELDS),
|
|
298
|
+
});
|
|
299
|
+
const paginator = (0, lib_dynamodb_1.paginateScan)({ client: this.client }, input);
|
|
300
|
+
for await (const page of paginator) {
|
|
301
|
+
if (!page.Items)
|
|
302
|
+
continue;
|
|
303
|
+
for (const item of page.Items)
|
|
304
|
+
yield item;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
exports.DynamoDBService = DynamoDBService;
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { DynamoDBService } from './dynamodb/dynamodb';
|
|
2
|
+
export { S3Service } from './s3/s3';
|
|
3
|
+
export { SecretsManagerService } from './secrets-manager/secrets-manager';
|
|
4
|
+
export { StepFunctionsService } from './sfn/sfn';
|
|
5
|
+
export { SNSService } from './sns/sns';
|
|
6
|
+
export { SQSService } from './sqs/sqs';
|
|
7
|
+
export { SSMService } from './ssm/ssm';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SSMService = exports.SQSService = exports.SNSService = exports.StepFunctionsService = exports.SecretsManagerService = exports.S3Service = exports.DynamoDBService = void 0;
|
|
4
|
+
var dynamodb_1 = require("./dynamodb/dynamodb");
|
|
5
|
+
Object.defineProperty(exports, "DynamoDBService", { enumerable: true, get: function () { return dynamodb_1.DynamoDBService; } });
|
|
6
|
+
var s3_1 = require("./s3/s3");
|
|
7
|
+
Object.defineProperty(exports, "S3Service", { enumerable: true, get: function () { return s3_1.S3Service; } });
|
|
8
|
+
var secrets_manager_1 = require("./secrets-manager/secrets-manager");
|
|
9
|
+
Object.defineProperty(exports, "SecretsManagerService", { enumerable: true, get: function () { return secrets_manager_1.SecretsManagerService; } });
|
|
10
|
+
var sfn_1 = require("./sfn/sfn");
|
|
11
|
+
Object.defineProperty(exports, "StepFunctionsService", { enumerable: true, get: function () { return sfn_1.StepFunctionsService; } });
|
|
12
|
+
var sns_1 = require("./sns/sns");
|
|
13
|
+
Object.defineProperty(exports, "SNSService", { enumerable: true, get: function () { return sns_1.SNSService; } });
|
|
14
|
+
var sqs_1 = require("./sqs/sqs");
|
|
15
|
+
Object.defineProperty(exports, "SQSService", { enumerable: true, get: function () { return sqs_1.SQSService; } });
|
|
16
|
+
var ssm_1 = require("./ssm/ssm");
|
|
17
|
+
Object.defineProperty(exports, "SSMService", { enumerable: true, get: function () { return ssm_1.SSMService; } });
|
package/src/s3/s3.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Logger } from '@aws-lambda-powertools/logger';
|
|
2
|
+
import { CopyObjectCommandInput, CopyObjectCommandOutput, DeleteObjectCommandInput, DeleteObjectCommandOutput, DeleteObjectsCommandOutput, GetObjectCommandInput, GetObjectCommandOutput, HeadObjectCommandInput, HeadObjectCommandOutput, PutObjectCommandInput, PutObjectCommandOutput, S3Client } from '@aws-sdk/client-s3';
|
|
3
|
+
/** Tight wrapper input type for `putObject`. */
|
|
4
|
+
type PutObjectInput = Required<Pick<PutObjectCommandInput, 'Bucket' | 'Key' | 'Body'>>;
|
|
5
|
+
/** Tight wrapper input type for `putJsonObject`. */
|
|
6
|
+
type PutJsonObjectInput<T> = {
|
|
7
|
+
Bucket: string;
|
|
8
|
+
Key: string;
|
|
9
|
+
Body: T;
|
|
10
|
+
Metadata?: Record<string, string>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Wrapper around the AWS S3 client providing structured Powertools logging
|
|
14
|
+
* and X-Ray tracing by default.
|
|
15
|
+
*
|
|
16
|
+
* Input shapes are intentionally tight (Bucket/Key/Body only). Callers
|
|
17
|
+
* needing SDK-level options not exposed here (server-side encryption,
|
|
18
|
+
* tagging, version IDs) should use `S3Client` directly.
|
|
19
|
+
*/
|
|
20
|
+
export declare class S3Service {
|
|
21
|
+
private readonly client;
|
|
22
|
+
private readonly logger;
|
|
23
|
+
/**
|
|
24
|
+
* @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
|
|
25
|
+
* which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
|
|
26
|
+
* @param opts.client - Optional pre-configured `S3Client`. When supplied,
|
|
27
|
+
* the wrapper does not apply X-Ray instrumentation.
|
|
28
|
+
*/
|
|
29
|
+
constructor(opts?: {
|
|
30
|
+
logger?: Logger;
|
|
31
|
+
client?: S3Client;
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Put an object into S3.
|
|
35
|
+
*
|
|
36
|
+
* Note: the structured log line only includes `Bucket` and `Key` —
|
|
37
|
+
* `Body` is omitted to avoid spilling large payloads or sensitive
|
|
38
|
+
* content into CloudWatch.
|
|
39
|
+
*
|
|
40
|
+
* @param input - Bucket, Key, and Body of the object to store.
|
|
41
|
+
*/
|
|
42
|
+
putObject(input: PutObjectInput): Promise<PutObjectCommandOutput>;
|
|
43
|
+
/**
|
|
44
|
+
* Serialise a value to JSON and store it as an S3 object.
|
|
45
|
+
*
|
|
46
|
+
* Note: the structured log line only includes `Bucket` and `Key` —
|
|
47
|
+
* the JSON-encoded body is omitted to avoid spilling potentially
|
|
48
|
+
* large or sensitive content into CloudWatch.
|
|
49
|
+
*
|
|
50
|
+
* @template T - Type of the value being stored.
|
|
51
|
+
*/
|
|
52
|
+
putJsonObject<T>(input: PutJsonObjectInput<T>): Promise<PutObjectCommandOutput>;
|
|
53
|
+
/**
|
|
54
|
+
* Get an object from S3.
|
|
55
|
+
*/
|
|
56
|
+
getObject(input: Required<Pick<GetObjectCommandInput, 'Bucket' | 'Key'>>): Promise<GetObjectCommandOutput>;
|
|
57
|
+
/**
|
|
58
|
+
* Get an object from S3 and return its body as a string.
|
|
59
|
+
* @returns The object body as a string, or `undefined` if the response
|
|
60
|
+
* has no body.
|
|
61
|
+
*/
|
|
62
|
+
getObjectBody(input: Required<Pick<GetObjectCommandInput, 'Bucket' | 'Key'>>): Promise<string | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* Get an object from S3 and parse it as JSON.
|
|
65
|
+
* @template T - Expected type of the parsed value.
|
|
66
|
+
* @returns The parsed value, or `undefined` if the response has no body.
|
|
67
|
+
* @throws If the body is non-empty and not valid JSON.
|
|
68
|
+
*/
|
|
69
|
+
getJsonObject<T>(input: Required<Pick<GetObjectCommandInput, 'Bucket' | 'Key'>>): Promise<T | undefined>;
|
|
70
|
+
/**
|
|
71
|
+
* Fetch the metadata for an S3 object without downloading its body.
|
|
72
|
+
*/
|
|
73
|
+
headObject(input: Required<Pick<HeadObjectCommandInput, 'Bucket' | 'Key'>>): Promise<HeadObjectCommandOutput>;
|
|
74
|
+
/**
|
|
75
|
+
* Copy an object within S3.
|
|
76
|
+
*/
|
|
77
|
+
copyObject(input: Required<Pick<CopyObjectCommandInput, 'Bucket' | 'Key' | 'CopySource'>>): Promise<CopyObjectCommandOutput>;
|
|
78
|
+
/**
|
|
79
|
+
* List object keys under a bucket and optional prefix, auto-paginating
|
|
80
|
+
* across all pages.
|
|
81
|
+
*/
|
|
82
|
+
listObjects(bucket: string, prefix?: string): Promise<string[]>;
|
|
83
|
+
/**
|
|
84
|
+
* List and JSON-parse every object under a bucket and optional prefix.
|
|
85
|
+
* Auto-paginated. Objects without a body are skipped.
|
|
86
|
+
* @template T - Expected type of each parsed object.
|
|
87
|
+
*/
|
|
88
|
+
getAllObjects<T>(bucket: string, prefix?: string): Promise<T[]>;
|
|
89
|
+
/**
|
|
90
|
+
* Generate a presigned URL that callers can use to GET or PUT an S3 object
|
|
91
|
+
* directly, without going through the wrapper. The signing happens against
|
|
92
|
+
* the wrapper's `S3Client`, so callers do not need their own client.
|
|
93
|
+
*
|
|
94
|
+
* GET URLs are signed with `ResponseContentDisposition: 'attachment'` so
|
|
95
|
+
* browsers download the object rather than rendering it in-place.
|
|
96
|
+
*
|
|
97
|
+
* The input shape is an inline object (rather than the `Required<Pick<...>>`
|
|
98
|
+
* pattern used by other S3 methods) because this method wraps two SDK
|
|
99
|
+
* commands rather than one, and `action` / `expiresIn` are wrapper-level
|
|
100
|
+
* concerns with no SDK-input equivalent.
|
|
101
|
+
*
|
|
102
|
+
* @param input.Bucket - The S3 bucket name.
|
|
103
|
+
* @param input.Key - The S3 object key.
|
|
104
|
+
* @param input.action - `'get'` to download, `'put'` to upload.
|
|
105
|
+
* @param input.expiresIn - URL lifetime in seconds. Defaults to 3600 (1 hour).
|
|
106
|
+
*/
|
|
107
|
+
getPresignedUrl(input: {
|
|
108
|
+
Bucket: string;
|
|
109
|
+
Key: string;
|
|
110
|
+
action: 'get' | 'put';
|
|
111
|
+
expiresIn?: number;
|
|
112
|
+
}): Promise<string>;
|
|
113
|
+
/**
|
|
114
|
+
* Delete a single object from S3.
|
|
115
|
+
*/
|
|
116
|
+
deleteObject(input: Required<Pick<DeleteObjectCommandInput, 'Bucket' | 'Key'>>): Promise<DeleteObjectCommandOutput>;
|
|
117
|
+
/**
|
|
118
|
+
* Delete multiple objects from S3, auto-chunking the request into batches
|
|
119
|
+
* of 1000 keys (the S3-enforced DeleteObjects limit). Returns one output
|
|
120
|
+
* per chunk.
|
|
121
|
+
*/
|
|
122
|
+
deleteObjects(bucket: string, keys: string[]): Promise<DeleteObjectsCommandOutput[]>;
|
|
123
|
+
/**
|
|
124
|
+
* Delete every object in a bucket. Streams the listing page-by-page and
|
|
125
|
+
* delegates each page's deletion to `deleteObjects`, so peak memory stays
|
|
126
|
+
* bounded by one page (~1000 keys) regardless of bucket size.
|
|
127
|
+
* @returns The keys of every deleted object.
|
|
128
|
+
*/
|
|
129
|
+
emptyBucket(bucket: string): Promise<string[]>;
|
|
130
|
+
}
|
|
131
|
+
export {};
|