@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/src/s3/s3.js ADDED
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.S3Service = void 0;
4
+ const logger_1 = require("@aws-lambda-powertools/logger");
5
+ const client_s3_1 = require("@aws-sdk/client-s3");
6
+ const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
7
+ const aws_xray_sdk_core_1 = require("aws-xray-sdk-core");
8
+ const redact_1 = require("../util/redact");
9
+ const DEFAULT_PRESIGNED_URL_EXPIRES_IN_SECONDS = 3600;
10
+ const DELETE_OBJECTS_BATCH_LIMIT = 1000;
11
+ /**
12
+ * Fields safe to log at INFO for `putObject`. Omits `Body` (object payload).
13
+ * `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
14
+ */
15
+ const PUT_OBJECT_SAFE_FIELDS = ['Bucket', 'Key'];
16
+ /**
17
+ * Fields safe to log at INFO for `putJsonObject`. Omits `Body` (the
18
+ * unserialised JSON payload). `Metadata` is included (operational labels).
19
+ * `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
20
+ */
21
+ const PUT_JSON_OBJECT_SAFE_FIELDS = [
22
+ 'Bucket',
23
+ 'Key',
24
+ 'Metadata',
25
+ ];
26
+ /**
27
+ * Wrapper around the AWS S3 client providing structured Powertools logging
28
+ * and X-Ray tracing by default.
29
+ *
30
+ * Input shapes are intentionally tight (Bucket/Key/Body only). Callers
31
+ * needing SDK-level options not exposed here (server-side encryption,
32
+ * tagging, version IDs) should use `S3Client` directly.
33
+ */
34
+ class S3Service {
35
+ client;
36
+ logger;
37
+ /**
38
+ * @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
39
+ * which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
40
+ * @param opts.client - Optional pre-configured `S3Client`. When supplied,
41
+ * the wrapper does not apply X-Ray instrumentation.
42
+ */
43
+ constructor(opts) {
44
+ this.client = opts?.client ?? (0, aws_xray_sdk_core_1.captureAWSv3Client)(new client_s3_1.S3Client());
45
+ this.logger = opts?.logger ?? new logger_1.Logger();
46
+ }
47
+ /**
48
+ * Put an object into S3.
49
+ *
50
+ * Note: the structured log line only includes `Bucket` and `Key` —
51
+ * `Body` is omitted to avoid spilling large payloads or sensitive
52
+ * content into CloudWatch.
53
+ *
54
+ * @param input - Bucket, Key, and Body of the object to store.
55
+ */
56
+ async putObject(input) {
57
+ this.logger.info('Putting S3 object', {
58
+ input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, PUT_OBJECT_SAFE_FIELDS),
59
+ });
60
+ return this.client.send(new client_s3_1.PutObjectCommand(input));
61
+ }
62
+ /**
63
+ * Serialise a value to JSON and store it as an S3 object.
64
+ *
65
+ * Note: the structured log line only includes `Bucket` and `Key` —
66
+ * the JSON-encoded body is omitted to avoid spilling potentially
67
+ * large or sensitive content into CloudWatch.
68
+ *
69
+ * @template T - Type of the value being stored.
70
+ */
71
+ async putJsonObject(input) {
72
+ this.logger.info('Putting S3 JSON object', {
73
+ input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, PUT_JSON_OBJECT_SAFE_FIELDS),
74
+ });
75
+ return this.client.send(new client_s3_1.PutObjectCommand({
76
+ Bucket: input.Bucket,
77
+ Key: input.Key,
78
+ Body: JSON.stringify(input.Body),
79
+ Metadata: input.Metadata,
80
+ }));
81
+ }
82
+ /**
83
+ * Get an object from S3.
84
+ */
85
+ async getObject(input) {
86
+ this.logger.info('Getting S3 object', { input });
87
+ return this.client.send(new client_s3_1.GetObjectCommand(input));
88
+ }
89
+ /**
90
+ * Get an object from S3 and return its body as a string.
91
+ * @returns The object body as a string, or `undefined` if the response
92
+ * has no body.
93
+ */
94
+ async getObjectBody(input) {
95
+ this.logger.info('Getting S3 object body', { input });
96
+ const response = await this.client.send(new client_s3_1.GetObjectCommand(input));
97
+ return response.Body?.transformToString();
98
+ }
99
+ /**
100
+ * Get an object from S3 and parse it as JSON.
101
+ * @template T - Expected type of the parsed value.
102
+ * @returns The parsed value, or `undefined` if the response has no body.
103
+ * @throws If the body is non-empty and not valid JSON.
104
+ */
105
+ async getJsonObject(input) {
106
+ this.logger.info('Getting S3 JSON object', { input });
107
+ const response = await this.client.send(new client_s3_1.GetObjectCommand(input));
108
+ const body = await response.Body?.transformToString();
109
+ return body ? JSON.parse(body) : undefined;
110
+ }
111
+ /**
112
+ * Fetch the metadata for an S3 object without downloading its body.
113
+ */
114
+ async headObject(input) {
115
+ this.logger.info('Fetching S3 object metadata', { input });
116
+ return this.client.send(new client_s3_1.HeadObjectCommand(input));
117
+ }
118
+ /**
119
+ * Copy an object within S3.
120
+ */
121
+ async copyObject(input) {
122
+ this.logger.info('Copying S3 object', { input });
123
+ return this.client.send(new client_s3_1.CopyObjectCommand(input));
124
+ }
125
+ /**
126
+ * List object keys under a bucket and optional prefix, auto-paginating
127
+ * across all pages.
128
+ */
129
+ async listObjects(bucket, prefix) {
130
+ this.logger.info('Listing S3 objects', { input: { bucket, prefix } });
131
+ const paginator = (0, client_s3_1.paginateListObjectsV2)({ client: this.client }, { Bucket: bucket, Prefix: prefix });
132
+ const keys = [];
133
+ for await (const page of paginator) {
134
+ for (const object of page.Contents ?? []) {
135
+ if (object.Key)
136
+ keys.push(object.Key);
137
+ }
138
+ }
139
+ return keys;
140
+ }
141
+ /**
142
+ * List and JSON-parse every object under a bucket and optional prefix.
143
+ * Auto-paginated. Objects without a body are skipped.
144
+ * @template T - Expected type of each parsed object.
145
+ */
146
+ async getAllObjects(bucket, prefix) {
147
+ this.logger.info('Getting all S3 objects', { input: { bucket, prefix } });
148
+ const paginator = (0, client_s3_1.paginateListObjectsV2)({ client: this.client }, { Bucket: bucket, Prefix: prefix });
149
+ const bodies = [];
150
+ for await (const page of paginator) {
151
+ for (const object of page.Contents ?? []) {
152
+ if (!object.Key)
153
+ continue;
154
+ const response = await this.client.send(new client_s3_1.GetObjectCommand({ Bucket: bucket, Key: object.Key }));
155
+ const body = await response.Body?.transformToString();
156
+ if (body)
157
+ bodies.push(JSON.parse(body));
158
+ }
159
+ }
160
+ return bodies;
161
+ }
162
+ /**
163
+ * Generate a presigned URL that callers can use to GET or PUT an S3 object
164
+ * directly, without going through the wrapper. The signing happens against
165
+ * the wrapper's `S3Client`, so callers do not need their own client.
166
+ *
167
+ * GET URLs are signed with `ResponseContentDisposition: 'attachment'` so
168
+ * browsers download the object rather than rendering it in-place.
169
+ *
170
+ * The input shape is an inline object (rather than the `Required<Pick<...>>`
171
+ * pattern used by other S3 methods) because this method wraps two SDK
172
+ * commands rather than one, and `action` / `expiresIn` are wrapper-level
173
+ * concerns with no SDK-input equivalent.
174
+ *
175
+ * @param input.Bucket - The S3 bucket name.
176
+ * @param input.Key - The S3 object key.
177
+ * @param input.action - `'get'` to download, `'put'` to upload.
178
+ * @param input.expiresIn - URL lifetime in seconds. Defaults to 3600 (1 hour).
179
+ */
180
+ async getPresignedUrl(input) {
181
+ const expiresIn = input.expiresIn ?? DEFAULT_PRESIGNED_URL_EXPIRES_IN_SECONDS;
182
+ this.logger.info('Generating S3 presigned URL', {
183
+ input: { Bucket: input.Bucket, Key: input.Key, action: input.action, expiresIn },
184
+ });
185
+ const command = input.action === 'get'
186
+ ? new client_s3_1.GetObjectCommand({
187
+ Bucket: input.Bucket,
188
+ Key: input.Key,
189
+ ResponseContentDisposition: 'attachment',
190
+ })
191
+ : new client_s3_1.PutObjectCommand({ Bucket: input.Bucket, Key: input.Key });
192
+ return (0, s3_request_presigner_1.getSignedUrl)(this.client, command, { expiresIn });
193
+ }
194
+ /**
195
+ * Delete a single object from S3.
196
+ */
197
+ async deleteObject(input) {
198
+ this.logger.info('Deleting S3 object', { input });
199
+ return this.client.send(new client_s3_1.DeleteObjectCommand(input));
200
+ }
201
+ /**
202
+ * Delete multiple objects from S3, auto-chunking the request into batches
203
+ * of 1000 keys (the S3-enforced DeleteObjects limit). Returns one output
204
+ * per chunk.
205
+ */
206
+ async deleteObjects(bucket, keys) {
207
+ // Inline DEBUG check rather than `filterFieldsForLogLevel` because the
208
+ // safe log shape includes the computed `keyCount`, which isn't a key
209
+ // on any SDK input type.
210
+ const isDebug = this.logger.getLevelName() === 'DEBUG';
211
+ this.logger.info('Deleting S3 objects', {
212
+ input: isDebug ? { bucket, keys } : { bucket, keyCount: keys.length },
213
+ });
214
+ const results = [];
215
+ for (let i = 0; i < keys.length; i += DELETE_OBJECTS_BATCH_LIMIT) {
216
+ const batch = keys.slice(i, i + DELETE_OBJECTS_BATCH_LIMIT);
217
+ results.push(await this.client.send(new client_s3_1.DeleteObjectsCommand({
218
+ Bucket: bucket,
219
+ Delete: { Objects: batch.map(Key => ({ Key })) },
220
+ })));
221
+ }
222
+ return results;
223
+ }
224
+ /**
225
+ * Delete every object in a bucket. Streams the listing page-by-page and
226
+ * delegates each page's deletion to `deleteObjects`, so peak memory stays
227
+ * bounded by one page (~1000 keys) regardless of bucket size.
228
+ * @returns The keys of every deleted object.
229
+ */
230
+ async emptyBucket(bucket) {
231
+ this.logger.info('Emptying S3 bucket', { input: { bucket } });
232
+ const paginator = (0, client_s3_1.paginateListObjectsV2)({ client: this.client }, { Bucket: bucket });
233
+ const deletedKeys = [];
234
+ for await (const page of paginator) {
235
+ const keys = (page.Contents ?? []).flatMap(o => (o.Key ? [o.Key] : []));
236
+ if (keys.length === 0)
237
+ continue;
238
+ await this.deleteObjects(bucket, keys);
239
+ deletedKeys.push(...keys);
240
+ }
241
+ return deletedKeys;
242
+ }
243
+ }
244
+ exports.S3Service = S3Service;
@@ -0,0 +1,78 @@
1
+ import { Logger } from '@aws-lambda-powertools/logger';
2
+ import { CreateSecretCommandInput, CreateSecretCommandOutput, DeleteSecretCommandInput, DeleteSecretCommandOutput, PutSecretValueCommandInput, PutSecretValueCommandOutput, SecretsManagerClient, UpdateSecretCommandInput, UpdateSecretCommandOutput } from '@aws-sdk/client-secrets-manager';
3
+ /**
4
+ * Wrapper around the AWS Secrets Manager client providing structured
5
+ * Powertools logging and X-Ray tracing by default.
6
+ *
7
+ * Write operations (`createSecret`, `updateSecret`, `putSecretValue`,
8
+ * `deleteSecret`) are exposed for convenience but should be used with care:
9
+ * secret lifecycle is usually managed by IaC (CDK / Terraform). Prefer IaC
10
+ * for anything that exists at deploy time; reserve runtime writes for
11
+ * dynamically-issued credentials, rotation flows, or other genuinely
12
+ * mutable values.
13
+ */
14
+ export declare class SecretsManagerService {
15
+ private readonly client;
16
+ private readonly logger;
17
+ /**
18
+ * @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
19
+ * which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
20
+ * @param opts.client - Optional pre-configured `SecretsManagerClient`. When
21
+ * supplied, the wrapper does not apply X-Ray instrumentation — the caller
22
+ * owns that decision.
23
+ */
24
+ constructor(opts?: {
25
+ logger?: Logger;
26
+ client?: SecretsManagerClient;
27
+ });
28
+ /**
29
+ * Fetch a secret's string value from Secrets Manager.
30
+ * @param secretId - The ARN or friendly name of the secret.
31
+ * @returns The secret's `SecretString` value.
32
+ * @throws If the response does not contain a `SecretString` (e.g. the secret
33
+ * stores binary data).
34
+ */
35
+ getSecret(secretId: string): Promise<string>;
36
+ /**
37
+ * Fetch a secret and parse it as JSON.
38
+ * @param secretId - The ARN or friendly name of the secret.
39
+ * @template T - Expected shape of the parsed secret.
40
+ * @returns The parsed secret value.
41
+ * @throws If the secret has no `SecretString` or the value is not valid JSON.
42
+ */
43
+ getJsonSecret<T>(secretId: string): Promise<T>;
44
+ /**
45
+ * Create a new secret. At INFO level the log line includes only identity
46
+ * and non-secret metadata; `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full
47
+ * input (including `SecretString` / `SecretBinary`).
48
+ *
49
+ * Prefer IaC (CDK / Terraform) for secret lifecycle — use this for
50
+ * dynamically-issued credentials only.
51
+ */
52
+ createSecret(input: CreateSecretCommandInput): Promise<CreateSecretCommandOutput>;
53
+ /**
54
+ * Update an existing secret's metadata or value. At INFO level the log
55
+ * line omits `SecretString` / `SecretBinary`; `POWERTOOLS_LOG_LEVEL=DEBUG`
56
+ * unlocks the full input.
57
+ *
58
+ * Prefer IaC (CDK / Terraform) for secret lifecycle — use this for
59
+ * runtime metadata updates only.
60
+ */
61
+ updateSecret(input: UpdateSecretCommandInput): Promise<UpdateSecretCommandOutput>;
62
+ /**
63
+ * Store a new version of a secret's value. At INFO level the log line
64
+ * omits `SecretString` / `SecretBinary`; `POWERTOOLS_LOG_LEVEL=DEBUG`
65
+ * unlocks the full input.
66
+ *
67
+ * Typically used by rotation flows.
68
+ */
69
+ putSecretValue(input: PutSecretValueCommandInput): Promise<PutSecretValueCommandOutput>;
70
+ /**
71
+ * Delete a secret. Pass `ForceDeleteWithoutRecovery: true` to bypass the
72
+ * default 7-30 day recovery window (irreversible).
73
+ *
74
+ * Prefer IaC (CDK / Terraform) for secret lifecycle.
75
+ */
76
+ deleteSecret(input: DeleteSecretCommandInput): Promise<DeleteSecretCommandOutput>;
77
+ private fetchSecretString;
78
+ }
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SecretsManagerService = void 0;
4
+ const logger_1 = require("@aws-lambda-powertools/logger");
5
+ const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
6
+ const aws_xray_sdk_core_1 = require("aws-xray-sdk-core");
7
+ const redact_1 = require("../util/redact");
8
+ /**
9
+ * Fields safe to log at INFO level. Omits `SecretString` and `SecretBinary` —
10
+ * the secret material itself. `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full
11
+ * input.
12
+ */
13
+ const CREATE_SECRET_SAFE_FIELDS = [
14
+ 'Name',
15
+ 'Description',
16
+ 'KmsKeyId',
17
+ 'Tags',
18
+ 'ClientRequestToken',
19
+ 'AddReplicaRegions',
20
+ 'ForceOverwriteReplicaSecret',
21
+ ];
22
+ const UPDATE_SECRET_SAFE_FIELDS = [
23
+ 'SecretId',
24
+ 'Description',
25
+ 'KmsKeyId',
26
+ 'ClientRequestToken',
27
+ ];
28
+ const PUT_SECRET_VALUE_SAFE_FIELDS = [
29
+ 'SecretId',
30
+ 'VersionStages',
31
+ 'ClientRequestToken',
32
+ ];
33
+ /**
34
+ * `DeleteSecretCommandInput` carries no secret material today, but the
35
+ * explicit allowlist keeps the log shape consistent with the other write
36
+ * methods and protects against future field additions.
37
+ */
38
+ const DELETE_SECRET_SAFE_FIELDS = [
39
+ 'SecretId',
40
+ 'RecoveryWindowInDays',
41
+ 'ForceDeleteWithoutRecovery',
42
+ ];
43
+ /**
44
+ * Wrapper around the AWS Secrets Manager client providing structured
45
+ * Powertools logging and X-Ray tracing by default.
46
+ *
47
+ * Write operations (`createSecret`, `updateSecret`, `putSecretValue`,
48
+ * `deleteSecret`) are exposed for convenience but should be used with care:
49
+ * secret lifecycle is usually managed by IaC (CDK / Terraform). Prefer IaC
50
+ * for anything that exists at deploy time; reserve runtime writes for
51
+ * dynamically-issued credentials, rotation flows, or other genuinely
52
+ * mutable values.
53
+ */
54
+ class SecretsManagerService {
55
+ client;
56
+ logger;
57
+ /**
58
+ * @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
59
+ * which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
60
+ * @param opts.client - Optional pre-configured `SecretsManagerClient`. When
61
+ * supplied, the wrapper does not apply X-Ray instrumentation — the caller
62
+ * owns that decision.
63
+ */
64
+ constructor(opts) {
65
+ this.client = opts?.client ?? (0, aws_xray_sdk_core_1.captureAWSv3Client)(new client_secrets_manager_1.SecretsManagerClient());
66
+ this.logger = opts?.logger ?? new logger_1.Logger();
67
+ }
68
+ /**
69
+ * Fetch a secret's string value from Secrets Manager.
70
+ * @param secretId - The ARN or friendly name of the secret.
71
+ * @returns The secret's `SecretString` value.
72
+ * @throws If the response does not contain a `SecretString` (e.g. the secret
73
+ * stores binary data).
74
+ */
75
+ async getSecret(secretId) {
76
+ this.logger.info('Fetching secret', { input: { secretId } });
77
+ return this.fetchSecretString(secretId);
78
+ }
79
+ /**
80
+ * Fetch a secret and parse it as JSON.
81
+ * @param secretId - The ARN or friendly name of the secret.
82
+ * @template T - Expected shape of the parsed secret.
83
+ * @returns The parsed secret value.
84
+ * @throws If the secret has no `SecretString` or the value is not valid JSON.
85
+ */
86
+ async getJsonSecret(secretId) {
87
+ this.logger.info('Fetching JSON secret', { input: { secretId } });
88
+ const secretString = await this.fetchSecretString(secretId);
89
+ return JSON.parse(secretString);
90
+ }
91
+ /**
92
+ * Create a new secret. At INFO level the log line includes only identity
93
+ * and non-secret metadata; `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full
94
+ * input (including `SecretString` / `SecretBinary`).
95
+ *
96
+ * Prefer IaC (CDK / Terraform) for secret lifecycle — use this for
97
+ * dynamically-issued credentials only.
98
+ */
99
+ async createSecret(input) {
100
+ this.logger.info('Creating secret', {
101
+ input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, CREATE_SECRET_SAFE_FIELDS),
102
+ });
103
+ return this.client.send(new client_secrets_manager_1.CreateSecretCommand(input));
104
+ }
105
+ /**
106
+ * Update an existing secret's metadata or value. At INFO level the log
107
+ * line omits `SecretString` / `SecretBinary`; `POWERTOOLS_LOG_LEVEL=DEBUG`
108
+ * unlocks the full input.
109
+ *
110
+ * Prefer IaC (CDK / Terraform) for secret lifecycle — use this for
111
+ * runtime metadata updates only.
112
+ */
113
+ async updateSecret(input) {
114
+ this.logger.info('Updating secret', {
115
+ input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, UPDATE_SECRET_SAFE_FIELDS),
116
+ });
117
+ return this.client.send(new client_secrets_manager_1.UpdateSecretCommand(input));
118
+ }
119
+ /**
120
+ * Store a new version of a secret's value. At INFO level the log line
121
+ * omits `SecretString` / `SecretBinary`; `POWERTOOLS_LOG_LEVEL=DEBUG`
122
+ * unlocks the full input.
123
+ *
124
+ * Typically used by rotation flows.
125
+ */
126
+ async putSecretValue(input) {
127
+ this.logger.info('Putting secret value', {
128
+ input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, PUT_SECRET_VALUE_SAFE_FIELDS),
129
+ });
130
+ return this.client.send(new client_secrets_manager_1.PutSecretValueCommand(input));
131
+ }
132
+ /**
133
+ * Delete a secret. Pass `ForceDeleteWithoutRecovery: true` to bypass the
134
+ * default 7-30 day recovery window (irreversible).
135
+ *
136
+ * Prefer IaC (CDK / Terraform) for secret lifecycle.
137
+ */
138
+ async deleteSecret(input) {
139
+ this.logger.info('Deleting secret', {
140
+ input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, DELETE_SECRET_SAFE_FIELDS),
141
+ });
142
+ return this.client.send(new client_secrets_manager_1.DeleteSecretCommand(input));
143
+ }
144
+ async fetchSecretString(secretId) {
145
+ const response = await this.client.send(new client_secrets_manager_1.GetSecretValueCommand({ SecretId: secretId }));
146
+ if (response.SecretString === undefined) {
147
+ throw new Error(`Secret '${secretId}' does not contain a string value`);
148
+ }
149
+ return response.SecretString;
150
+ }
151
+ }
152
+ exports.SecretsManagerService = SecretsManagerService;
@@ -0,0 +1,38 @@
1
+ import { Logger } from '@aws-lambda-powertools/logger';
2
+ import { DescribeExecutionCommandInput, DescribeExecutionCommandOutput, ExecutionListItem, ListExecutionsCommandInput, SFNClient, StartExecutionCommandInput, StartExecutionCommandOutput, StopExecutionCommandInput, StopExecutionCommandOutput } from '@aws-sdk/client-sfn';
3
+ /**
4
+ * Wrapper around the AWS Step Functions client providing structured
5
+ * Powertools logging and X-Ray tracing by default.
6
+ */
7
+ export declare class StepFunctionsService {
8
+ private readonly client;
9
+ private readonly logger;
10
+ /**
11
+ * @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
12
+ * which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
13
+ * @param opts.client - Optional pre-configured `SFNClient`. When supplied,
14
+ * the wrapper does not apply X-Ray instrumentation.
15
+ */
16
+ constructor(opts?: {
17
+ logger?: Logger;
18
+ client?: SFNClient;
19
+ });
20
+ /**
21
+ * List all executions for a state machine, auto-paginating across all
22
+ * pages. Typically bounded by `statusFilter` and state-machine retention,
23
+ * so the flat-array shape is safe in practice.
24
+ */
25
+ listExecutions(input: ListExecutionsCommandInput): Promise<ExecutionListItem[]>;
26
+ /**
27
+ * Start a new Step Functions execution.
28
+ */
29
+ startExecution(input: StartExecutionCommandInput): Promise<StartExecutionCommandOutput>;
30
+ /**
31
+ * Describe an existing Step Functions execution.
32
+ */
33
+ describeExecution(input: DescribeExecutionCommandInput): Promise<DescribeExecutionCommandOutput>;
34
+ /**
35
+ * Stop an in-progress Step Functions execution.
36
+ */
37
+ stopExecution(input: StopExecutionCommandInput): Promise<StopExecutionCommandOutput>;
38
+ }
package/src/sfn/sfn.js ADDED
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StepFunctionsService = void 0;
4
+ const logger_1 = require("@aws-lambda-powertools/logger");
5
+ const client_sfn_1 = require("@aws-sdk/client-sfn");
6
+ const aws_xray_sdk_core_1 = require("aws-xray-sdk-core");
7
+ const redact_1 = require("../util/redact");
8
+ /**
9
+ * Fields safe to log at INFO for `startExecution`. Omits `input` — the SFN
10
+ * execution payload, which routinely carries PII (customer IDs, addresses,
11
+ * order contents, etc.). `POWERTOOLS_LOG_LEVEL=DEBUG` unlocks the full input.
12
+ */
13
+ const START_EXECUTION_SAFE_FIELDS = [
14
+ 'stateMachineArn',
15
+ 'name',
16
+ 'traceHeader',
17
+ ];
18
+ /**
19
+ * Wrapper around the AWS Step Functions client providing structured
20
+ * Powertools logging and X-Ray tracing by default.
21
+ */
22
+ class StepFunctionsService {
23
+ client;
24
+ logger;
25
+ /**
26
+ * @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
27
+ * which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
28
+ * @param opts.client - Optional pre-configured `SFNClient`. When supplied,
29
+ * the wrapper does not apply X-Ray instrumentation.
30
+ */
31
+ constructor(opts) {
32
+ this.client = opts?.client ?? (0, aws_xray_sdk_core_1.captureAWSv3Client)(new client_sfn_1.SFNClient());
33
+ this.logger = opts?.logger ?? new logger_1.Logger();
34
+ }
35
+ /**
36
+ * List all executions for a state machine, auto-paginating across all
37
+ * pages. Typically bounded by `statusFilter` and state-machine retention,
38
+ * so the flat-array shape is safe in practice.
39
+ */
40
+ async listExecutions(input) {
41
+ this.logger.info('Listing Step Functions executions', { input });
42
+ const paginator = (0, client_sfn_1.paginateListExecutions)({ client: this.client }, input);
43
+ const executions = [];
44
+ for await (const page of paginator) {
45
+ if (page.executions)
46
+ executions.push(...page.executions);
47
+ }
48
+ return executions;
49
+ }
50
+ /**
51
+ * Start a new Step Functions execution.
52
+ */
53
+ async startExecution(input) {
54
+ this.logger.info('Starting Step Functions execution', {
55
+ input: (0, redact_1.filterFieldsForLogLevel)(this.logger, input, START_EXECUTION_SAFE_FIELDS),
56
+ });
57
+ return this.client.send(new client_sfn_1.StartExecutionCommand(input));
58
+ }
59
+ /**
60
+ * Describe an existing Step Functions execution.
61
+ */
62
+ async describeExecution(input) {
63
+ this.logger.info('Describing Step Functions execution', { input });
64
+ return this.client.send(new client_sfn_1.DescribeExecutionCommand(input));
65
+ }
66
+ /**
67
+ * Stop an in-progress Step Functions execution.
68
+ */
69
+ async stopExecution(input) {
70
+ this.logger.info('Stopping Step Functions execution', { input });
71
+ return this.client.send(new client_sfn_1.StopExecutionCommand(input));
72
+ }
73
+ }
74
+ exports.StepFunctionsService = StepFunctionsService;
@@ -0,0 +1,48 @@
1
+ import { Logger } from '@aws-lambda-powertools/logger';
2
+ import { PublishBatchCommandInput, PublishBatchCommandOutput, PublishCommandInput, PublishCommandOutput, SNSClient } from '@aws-sdk/client-sns';
3
+ /**
4
+ * Wrapper around the AWS SNS client providing structured Powertools logging
5
+ * and X-Ray tracing by default.
6
+ */
7
+ export declare class SNSService {
8
+ private readonly client;
9
+ private readonly logger;
10
+ private readonly truncate;
11
+ /**
12
+ * @param opts.logger - Optional Powertools logger. Defaults to `new Logger()`,
13
+ * which picks up `POWERTOOLS_SERVICE_NAME` from the environment.
14
+ * @param opts.client - Optional pre-configured `SNSClient`. When supplied,
15
+ * the wrapper does not apply X-Ray instrumentation.
16
+ * @param opts.truncate - When `true`, oversized `Message` / `Subject` are
17
+ * truncated (byte-safe / codepoint-safe) before sending instead of failing
18
+ * at the SDK. Defaults to `false` — the SDK throws on oversize, which is
19
+ * usually the right failure mode. Each `publish` call can override via
20
+ * its own `truncate` option.
21
+ */
22
+ constructor(opts?: {
23
+ logger?: Logger;
24
+ client?: SNSClient;
25
+ truncate?: boolean;
26
+ });
27
+ /**
28
+ * Publish a single message to an SNS topic.
29
+ *
30
+ * At INFO level the log line includes only routing / dedup metadata; see
31
+ * `PUBLISH_SAFE_FIELDS` for the list. Setting `POWERTOOLS_LOG_LEVEL=DEBUG`
32
+ * unlocks the full input.
33
+ *
34
+ * @param input - PublishCommandInput including TopicArn and Message.
35
+ */
36
+ publish(input: PublishCommandInput, opts?: {
37
+ truncate?: boolean;
38
+ }): Promise<PublishCommandOutput>;
39
+ private applyTruncation;
40
+ /**
41
+ * Publish a batch of messages to an SNS topic. The SNS API caps
42
+ * PublishBatch at 10 entries per request, so this method auto-chunks
43
+ * the caller's `PublishBatchRequestEntries` and sends one request per
44
+ * chunk, returning the array of outputs.
45
+ * @param input - PublishBatchCommandInput including TopicArn and entries.
46
+ */
47
+ publishBatch(input: PublishBatchCommandInput): Promise<PublishBatchCommandOutput[]>;
48
+ }