Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"source-map-support": "^0.5.21",
"tsx": "^4.20.6",
"typescript": "^5.9.3",
"vitest": "^3.0.5"
"vitest": "^4.0.1"
},
"dependencies": {
"@aws-lambda-powertools/batch": "^2.28.1",
Expand Down
952 changes: 396 additions & 556 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"@biomejs/biome": "^2.2.7",
"@types/aws-lambda": "^8.10.156",
"@types/node": "^24.9.1",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/coverage-v8": "^4.0.1",
"husky": "^9.1.7",
"lint-staged": "^16.2.5",
"markdownlint-cli2": "^0.18.1",
Expand All @@ -62,7 +62,7 @@
"typedoc": "^0.28.14",
"typedoc-plugin-missing-exports": "^4.1.2",
"typescript": "^5.9.3",
"vitest": "^3.0.9"
"vitest": "^4.0.1"
},
"lint-staged": {
"*.{js,ts,json}": "biome check --write --no-errors-on-unmatched",
Expand Down
6 changes: 4 additions & 2 deletions packages/batch/src/BatchProcessorSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,13 @@ import type { BaseRecord, FailureResponse, SuccessResponse } from './types.js';
* @param eventType The type of event to process (SQS, Kinesis, DynamoDB)
* @deprecated Use {@link BasePartialBatchProcessor} instead, this class is deprecated and will be removed in the next major version.
*/
/* v8 ignore start */ class BatchProcessorSync extends BasePartialBatchProcessor {
class BatchProcessorSync extends BasePartialBatchProcessor {
/**
* @throws {BatchProcessingError} This method is not implemented for asynchronous processing.
*
* @param _record The record to be processed
*/
/* v8 ignore next -- @preserve */
public processRecord(
_record: BaseRecord
): Promise<SuccessResponse | FailureResponse> {
Expand All @@ -108,6 +109,7 @@ import type { BaseRecord, FailureResponse, SuccessResponse } from './types.js';
*
* @param record The record to be processed
*/
/* v8 ignore next -- @preserve */
public processRecordSync(
record: BaseRecord
): SuccessResponse | FailureResponse {
Expand All @@ -120,6 +122,6 @@ import type { BaseRecord, FailureResponse, SuccessResponse } from './types.js';
return this.failureHandler(record, error as Error);
}
}
} /* v8 ignore stop */
}

export { BatchProcessorSync };
7 changes: 3 additions & 4 deletions packages/batch/src/processPartialResponseSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,8 @@ import type {
* @param processor Batch processor instance to handle the batch processing
* @param options Batch processing options, which can vary with chosen batch processor implementation
*/
/* v8 ignore start */ const processPartialResponseSync = <
T extends BasePartialBatchProcessor,
>(
/* v8 ignore next -- @preserve */
const processPartialResponseSync = <T extends BasePartialBatchProcessor>(
event: { Records: BaseRecord[] },
recordHandler: CallableFunction,
processor: T,
Expand All @@ -116,6 +115,6 @@ import type {
processor.processSync();

return processor.response();
}; /* v8 ignore stop */
};

export { processPartialResponseSync };
37 changes: 37 additions & 0 deletions packages/batch/tests/unit/BatchProcessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,43 @@ describe('Class: AsyncBatchProcessor', () => {
FullBatchFailureError
);
});

it('ignores the failed record in the collector response when the sequence number is not defined', async () => {
// Prepare
const firstRecord = {
eventID: '1',
eventVersion: '1.0',
dynamodb: {
Keys: { Id: { N: '101' } },
OldImage: { Message: { S: 'fail' } },
NewImage: { Message: { S: 'fail' } },
StreamViewType: 'NEW_AND_OLD_IMAGES',
SizeBytes: 26,
},
awsRegion: 'us-west-2',
eventName: 'INSERT',
eventSourceARN: 'eventsource_arn',
eventSource: 'aws:dynamodb',
};
const secondRecord = dynamodbRecordFactory('success');
const records = [firstRecord, secondRecord];
const processor = new BatchProcessor(EventType.DynamoDBStreams);

// Act
processor.register(records, asyncDynamodbRecordHandler, options);
const processedMessages = await processor.process();

// Assess
expect(processedMessages[1]).toStrictEqual([
'success',
secondRecord.dynamodb?.NewImage?.Message,
secondRecord,
]);
expect(processor.failureMessages.length).toBe(1);
expect(processor.response()).toStrictEqual({
batchItemFailures: [],
});
});
});
});

Expand Down
2 changes: 2 additions & 0 deletions packages/commons/src/LRUCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ class LRUCache<K, V> {
if (this.mostRecentlyUsed === item) return;

// If the item is not the newest, we need to mark it as the newest
/* v8 ignore else -- @preserve */
if (item[NEWER]) {
if (item === this.leastRecentlyUsed) {
this.leastRecentlyUsed = item[NEWER];
Expand All @@ -226,6 +227,7 @@ class LRUCache<K, V> {
}
item[NEWER] = undefined;
item[OLDER] = this.mostRecentlyUsed;
/* v8 ignore else -- @preserve */
if (this.mostRecentlyUsed) {
this.mostRecentlyUsed[NEWER] = item;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/commons/tests/unit/awsSdkUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('Helpers: awsSdk', () => {
// Prepare
const client = {
middlewareStack: {
identify: () => '',
identify: () => [''],
addRelativeTo: vi.fn(),
},
send: vi.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class RouteHandlerRegistry {
}
}
if (mostSpecificHandler === undefined) {
/* v8 ignore else -- @preserve */
if (!this.#warningSet.has(path)) {
this.#logger.warn(
`No route handler found for path '${path}' registered for ${this.#eventType}.`
Expand Down
2 changes: 1 addition & 1 deletion packages/event-handler/src/appsync-events/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const isAppSyncEventsEvent = (event: unknown): event is AppSyncEventsEvent => {
'name' in event.info.channelNamespace &&
isString(event.info.channelNamespace.name) &&
'operation' in event.info &&
/* v8 ignore next */
/* v8 ignore next -- @preserve */
(event.info.operation === 'PUBLISH' || event.info.operation === 'SUBSCRIBE')
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ describe('Class: Router - Basic Routing', () => {
expect(actual.hasContext).toBe(true);
});

it('throws an internal server error for non-API Gateway events', () => {
it('throws an internal server error for non-API Gateway events', async () => {
// Prepare
const app = new Router();
const nonApiGatewayEvent = { Records: [] }; // SQS-like event

// Act & Assess
expect(app.resolve(nonApiGatewayEvent, context)).rejects.toThrowError(
await expect(app.resolve(nonApiGatewayEvent, context)).rejects.toThrowError(
InternalServerError
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const makeHandlerIdempotent = (
});

const idempotencyHandler = new IdempotencyHandler({
functionToMakeIdempotent: /* v8 ignore next */ () => ({}),
functionToMakeIdempotent: /* v8 ignore next -- @preserve */ () => ({}),
functionArguments: [],
idempotencyConfig,
persistenceStore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,17 @@ vi.mock('node:crypto', () => ({
}));

describe('Class: BasePersistenceLayer', () => {
const ENVIRONMENT_VARIABLES = process.env;

beforeAll(() => {
vi.useFakeTimers().setSystemTime(new Date());
});

beforeEach(() => {
vi.clearAllMocks();
vi.resetModules();
process.env = { ...ENVIRONMENT_VARIABLES };
vi.stubEnv('AWS_LAMBDA_FUNCTION_NAME', 'my-lambda-function');
});

afterAll(() => {
process.env = ENVIRONMENT_VARIABLES;
vi.useRealTimers();
});

Expand Down
3 changes: 1 addition & 2 deletions packages/kafka/src/consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,11 @@ const getDeserializer = async (type?: string) => {
*/
const parseSchema = (value: unknown, schema: StandardSchemaV1) => {
const result = schema['~standard'].validate(value);
/* v8 ignore start */
/* v8 ignore if -- @preserve */
if (result instanceof Promise)
throw new KafkaConsumerParserError(
'Schema parsing supports only synchronous validation'
);
/* v8 ignore stop */
if (result.issues) {
throw new KafkaConsumerParserError('Schema validation failed', {
cause: result.issues,
Expand Down
12 changes: 7 additions & 5 deletions packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ class Logger extends Utility implements LoggerInterface {
});
}
throw error;
/* v8 ignore next */
/* v8 ignore next -- @preserve */
} finally {
if (options?.clearState || options?.resetKeys) loggerRef.resetKeys();
loggerRef.clearBuffer();
Expand All @@ -527,28 +527,30 @@ class Logger extends Utility implements LoggerInterface {
/**
* @deprecated This method is deprecated and will be removed in the future major versions. Use {@link resetKeys()} instead.
*/
/* v8 ignore start */ public static injectLambdaContextAfterOrOnError(
/* v8 ignore next -- @preserve */
public static injectLambdaContextAfterOrOnError(
logger: Logger,
_persistentAttributes: LogAttributes,
options?: InjectLambdaContextOptions
): void {
if (options && (options.clearState || options?.resetKeys)) {
logger.resetKeys();
}
} /* v8 ignore stop */
}

/**
* @deprecated - This method is deprecated and will be removed in the next major version.
*/
/* v8 ignore start */ public static injectLambdaContextBefore(
/* v8 ignore next -- @preserve */
public static injectLambdaContextBefore(
logger: Logger,
event: unknown,
context: Context,
options?: InjectLambdaContextOptions
): void {
logger.addContext(context);
logger.logEventIfEnabled(event, options?.logEvent);
} /* v8 ignore stop */
}

/**
* Log the AWS Lambda event payload for the current invocation if the environment variable `POWERTOOLS_LOGGER_LOG_EVENT` is set to `true`.
Expand Down
10 changes: 6 additions & 4 deletions packages/metrics/src/Metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -817,9 +817,10 @@ class Metrics extends Utility implements MetricsInterface {
* - `POWERTOOLS_FUNCTION_NAME` environment variable
* - {@link Metrics.captureColdStartMetric | `captureColdStartMetric('myFunctionName')`} method
*/
/* v8 ignore start */ public setFunctionName(name: string): void {
/* v8 ignore next -- @preserve */
public setFunctionName(name: string): void {
this.functionName = name;
} /* v8 ignore end */
}

/**
* Set the flag to throw an error if no metrics are emitted.
Expand Down Expand Up @@ -874,9 +875,10 @@ class Metrics extends Utility implements MetricsInterface {
/**
* @deprecated Use {@link Metrics.setThrowOnEmptyMetrics | `setThrowOnEmptyMetrics()`} instead.
*/
/* v8 ignore start */ public throwOnEmptyMetrics(): void {
/* v8 ignore next -- @preserve */
public throwOnEmptyMetrics(): void {
this.shouldThrowOnEmptyMetrics = true;
} /* v8 ignore stop */
}

/**
* Gets the current number of dimensions count.
Expand Down
8 changes: 3 additions & 5 deletions packages/parameters/src/appconfig/AppConfigProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,10 @@ class AppConfigProvider extends BaseProvider {
/**
* Retrieving multiple configurations is not supported by AWS AppConfig.
*/
/* v8 ignore start */ public async getMultiple(
path: string,
_options?: unknown
): Promise<void> {
/* v8 ignore next -- @preserve */
public async getMultiple(path: string, _options?: unknown): Promise<void> {
await super.getMultiple(path);
} /* v8 ignore stop */
}

/**
* Retrieve a configuration from AWS AppConfig.
Expand Down
8 changes: 3 additions & 5 deletions packages/parameters/src/secrets/SecretsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,10 @@ class SecretsProvider extends BaseProvider {
/**
* Retrieving multiple secrets is not supported with AWS Secrets Manager.
*/
/* v8 ignore start */ public async getMultiple(
path: string,
_options?: unknown
): Promise<void> {
/* v8 ignore next -- @preserve */
public async getMultiple(path: string, _options?: unknown): Promise<void> {
await super.getMultiple(path);
} /* v8 ignore stop */
}

/**
* Retrieve a secret from AWS Secrets Manager.
Expand Down
4 changes: 2 additions & 2 deletions packages/parameters/tests/unit/setParameter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ describe('Function: setParameter', () => {
expect(DEFAULT_PROVIDERS.ssm).toBe(provider);
});

it('rethrows the error thrown by the underlying sdk client', () => {
it('rethrows the error thrown by the underlying sdk client', async () => {
// Prepare
const options: SSMSetOptions = { value: 'my-value' };
client.on(PutParameterCommand).rejects(new Error('Could not send command'));

// Assess
expect(async () => {
await expect(async () => {
await setParameter(parameterName, options);
}).rejects.toThrowError(
`Unable to set parameter with name ${parameterName}`
Expand Down
3 changes: 1 addition & 2 deletions packages/parser/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,10 @@ function parse<T extends StandardSchemaV1, E extends Envelope>(
}

const result = schema['~standard'].validate(data);
/* v8 ignore start */
/* v8 ignore if -- @preserve */
if (result instanceof Promise) {
throw new ParseError('Schema parsing supports only synchronous validation');
}
/* v8 ignore stop */

if (result.issues) {
const error = new ParseError('Failed to parse schema', {
Expand Down
3 changes: 1 addition & 2 deletions packages/parser/src/schemas/alb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,10 @@ const AlbSchema = z.object({
*
* This schema will be removed in a future major release.
*/
/* v8 ignore start */
/* v8 ignore next -- @preserve */
const AlbMultiValueHeadersSchema = AlbSchema.extend({
multiValueHeaders: z.record(z.string(), z.array(z.string())),
multiValueQueryStringParameters: z.record(z.string(), z.array(z.string())),
});
/* v8 ignore stop */

export { AlbSchema, AlbMultiValueHeadersSchema };
Loading