Skip to content

Commit

Permalink
feat(maintenance): drop support for Node.js 16.x (#2717)
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamorosi authored Jul 2, 2024
1 parent 4ec3dcd commit e4eee73
Show file tree
Hide file tree
Showing 56 changed files with 142 additions and 242 deletions.
1 change: 0 additions & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ body:
options:
- 20.x
- 18.x
- 16.x
validations:
required: true
- type: dropdown
Expand Down
4 changes: 0 additions & 4 deletions .github/actions/cached-node-modules/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ outputs:
runs:
using: "composite"
steps:
- name: Install npm
# We need to keep this npm version until we drop Node.js 16 support because Node.js 16 doesn't support npm 10
run: npm i -g npm@next-9
shell: bash
- name: Cache node modules
id: cache-node-modules
uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
NODE_ENV: dev
strategy:
matrix:
version: [16, 18, 20]
version: [18, 20]
fail-fast: false
steps:
- name: Checkout code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
packages/parameters,
packages/idempotency,
]
version: [16, 18, 20]
version: [18, 20]
arch: [x86_64, arm64]
fail-fast: false
steps:
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa

[Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html){target="_blank"} is a `.zip` file archive that can contain additional code, pre-packaged dependencies, data, or configuration files. We compile and optimize [all dependencies](#install) to achieve an optimal build.

You can use the Lambda Layer both with CommonJS and ESM (ECMAScript modules) for Node.js 18.x and newer runtimes. **If you are using the managed Node.js 16.x runtime and cannot upgrade, you should use the CommonJS version only**.
You can use the Lambda Layer both with CommonJS and ESM (ECMAScript modules) for Node.js 18.x and newer runtimes.

??? note "Click to expand and copy any regional Lambda Layer ARN"
| Region | Layer ARN |
Expand Down
6 changes: 4 additions & 2 deletions docs/overrides/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
{% endblock %}

{% block announce %}
Starting from July 1, 2024 we will end support for Node.js 16. Learn more <a
href="https://github.com/aws-powertools/powertools-lambda-typescript/issues/2223" target="_blank">here</a>.
On September 1st, 2024 v1 of Powertools for AWS Lambda (TypeScript) <a
href="https://github.com/aws-powertools/powertools-lambda-typescript/issues/2224" target="_blank">will reach
End-of-Life</a>. We recommend you to <a href="https://docs.powertools.aws.dev/lambda/typescript/latest/upgrade/"
target="_blank">upgrade to v2</a>.
{% endblock %}
2 changes: 1 addition & 1 deletion docs/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ V2 is focused on official support for ESM (ECMAScript modules). We've made other

Before you start, we suggest making a copy of your current working project or create a new git branch.

1. Upgrade Node.js to v16 or higher, Node.js v20 is recommended.
1. Upgrade Node.js to v18 or higher, Node.js v20 is recommended.
2. Ensure that you have the latest Powertools for AWS Lambda (TypeScript) version via [Lambda Layer](./index.md#lambda-layer) or npm.
3. Review the following sections to confirm whether they apply to your codebase.

Expand Down
2 changes: 1 addition & 1 deletion layers/src/canary-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class CanaryStack extends Stack {
'../tests/e2e/layerPublisher.class.test.functionCode.ts'
),
handler: 'handler',
runtime: Runtime.NODEJS_16_X,
runtime: Runtime.NODEJS_18_X,
functionName: `canary-${suffix}`,
timeout: Duration.seconds(30),
bundling: {
Expand Down
8 changes: 2 additions & 6 deletions layers/src/layer-publisher-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ export class LayerPublisherStack extends Stack {
this.lambdaLayerVersion = new LayerVersion(this, 'LambdaPowertoolsLayer', {
layerVersionName: props?.layerName,
description: `Powertools for AWS Lambda (TypeScript) version ${powertoolsPackageVersion}`,
compatibleRuntimes: [
Runtime.NODEJS_16_X,
Runtime.NODEJS_18_X,
Runtime.NODEJS_20_X,
],
compatibleRuntimes: [Runtime.NODEJS_18_X, Runtime.NODEJS_20_X],
license: 'MIT-0',
// This is needed because the following regions do not support the compatibleArchitectures property #1400
// ...(![ 'eu-south-2', 'eu-central-2', 'ap-southeast-4' ].includes(Stack.of(this).region) ? { compatibleArchitectures: [Architecture.X86_64] } : {}),
Expand Down Expand Up @@ -105,7 +101,7 @@ export class LayerPublisherStack extends Stack {
'node_modules/@aws-sdk/**/README.md ',
];
const buildCommands: string[] = [];
// We need these modules because they are not included in the nodejs16x runtimes
// We install these to get the latest version of the packages
const modulesToInstall: string[] = [
'@aws-sdk/client-dynamodb',
'@aws-sdk/util-dynamodb',
Expand Down
9 changes: 1 addition & 8 deletions layers/tests/e2e/layerPublisher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
TestInvocationLogs,
invokeFunctionOnce,
generateTestUniqueName,
getRuntimeKey,
} from '@aws-lambda-powertools/testing-utils';
import { TestNodejsFunction } from '@aws-lambda-powertools/testing-utils/resources/lambda';
import {
Expand Down Expand Up @@ -48,13 +47,7 @@ describe(`Layers E2E tests`, () => {
},
});

/**
* Node.js 16.x does not support importing ESM modules from Lambda Layers reliably.
*
* The feature is available in Node.js 18.x and later.
* @see https://aws.amazon.com/blogs/compute/node-js-18-x-runtime-now-available-in-aws-lambda/
*/
const cases = getRuntimeKey() === 'nodejs16x' ? ['CJS'] : ['CJS', 'ESM'];
const cases = ['CJS', 'ESM'];
const invocationLogsMap: Map<(typeof cases)[number], TestInvocationLogs> =
new Map();

Expand Down
2 changes: 1 addition & 1 deletion layers/tests/unit/layer-publisher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Class: LayerPublisherStack', () => {
// Assess
template.resourceCountIs('AWS::Lambda::LayerVersion', 1);
template.hasResourceProperties('AWS::Lambda::LayerVersion', {
CompatibleRuntimes: ['nodejs16.x', 'nodejs18.x', 'nodejs20.x'],
CompatibleRuntimes: ['nodejs18.x', 'nodejs20.x'],
LicenseInfo: 'MIT-0',
/* CompatibleArchitectures: [
'x86_64',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"*.md": "markdownlint-cli2 --fix"
},
"engines": {
"node": ">=16"
"node": ">=18"
},
"overrides": {
"lerna": {
Expand Down
1 change: 0 additions & 1 deletion packages/batch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"test": "npm run test:unit",
"test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose",
"jest": "jest --detectOpenHandles --verbose",
"test:e2e:nodejs16x": "echo 'Not Implemented'",
"test:e2e:nodejs18x": "echo 'Not Implemented'",
"test:e2e:nodejs20x": "echo 'Not Implemented'",
"test:e2e": "echo 'Not Implemented'",
Expand Down
2 changes: 1 addition & 1 deletion packages/commons/src/middleware/cleanupMiddlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const cleanupMiddlewares = async (request: MiddyLikeRequest): Promise<void> => {
IDEMPOTENCY_KEY,
];
for (const functionName of cleanupFunctionNames) {
if (Object(request.internal).hasOwnProperty(functionName)) {
if (Object.hasOwn(request.internal, functionName)) {
const functionReference = request.internal[functionName];
if (isFunction(functionReference)) {
await functionReference(request);
Expand Down
1 change: 0 additions & 1 deletion packages/idempotency/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"test": "npm run test:unit",
"test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose",
"jest": "jest --detectOpenHandles --verbose",
"test:e2e:nodejs16x": "RUNTIME=nodejs16x jest --group=e2e",
"test:e2e:nodejs18x": "RUNTIME=nodejs18x jest --group=e2e",
"test:e2e:nodejs20x": "RUNTIME=nodejs20x jest --group=e2e",
"test:e2e": "jest --group=e2e",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Reserved variables
process.env._X_AMZN_TRACE_ID = '1-abcdef12-3456abcdef123456abcdef12';
process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function';
process.env.AWS_EXECUTION_ENV = 'nodejs16.x';
process.env.AWS_EXECUTION_ENV = 'nodejs20.x';
process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128';
if (
process.env.AWS_REGION === undefined &&
Expand Down
7 changes: 0 additions & 7 deletions packages/jmespath/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,6 @@ class ParseError extends JMESPathError {
* Error thrown when an incomplete expression is encountered during parsing.
*/
class IncompleteExpressionError extends ParseError {
/**
* Expression that was being parsed when the error occurred.
*
* Can be set by whatever catches the error.
*/
public expression?: string;

public constructor(options: {
lexPosition: number;
tokenValue: Token['value'];
Expand Down
1 change: 0 additions & 1 deletion packages/logger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"test": "npm run test:unit",
"test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose",
"jest": "jest --detectOpenHandles --verbose",
"test:e2e:nodejs16x": "RUNTIME=nodejs16x jest --group=e2e",
"test:e2e:nodejs18x": "RUNTIME=nodejs18x jest --group=e2e",
"test:e2e:nodejs20x": "RUNTIME=nodejs20x jest --group=e2e",
"test:e2e": "jest --group=e2e",
Expand Down
2 changes: 1 addition & 1 deletion packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ class Logger extends Utility implements LoggerInterface {
logger.addContext(context);

let shouldLogEvent = undefined;
if (options && options.hasOwnProperty('logEvent')) {
if (options && Object.hasOwn(options, 'logEvent')) {
shouldLogEvent = options.logEvent;
}
logger.logEventIfEnabled(event, shouldLogEvent);
Expand Down
23 changes: 3 additions & 20 deletions packages/logger/src/formatter/LogFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,6 @@ import type {
import type { UnformattedAttributes } from '../types/Logger.js';
import { LogItem } from './LogItem.js';

/**
* Typeguard to monkey patch Error to add a cause property.
*
* This is needed because the `cause` property is present in ES2022 or newer.
* Since we want to be able to format errors in Node 16.x, we need to
* add this property ourselves. We can remove this once we drop support
* for Node 16.x.
*
* @see https://nodejs.org/api/errors.html#errors_error_cause
*/
const isErrorWithCause = (
error: Error
): error is Error & { cause: unknown } => {
return 'cause' in error;
};

/**
* This class defines and implements common methods for the formatting of log attributes.
*
Expand Down Expand Up @@ -65,11 +49,10 @@ abstract class LogFormatter implements LogFormatterInterface {
location: this.getCodeLocation(error.stack),
message: error.message,
stack: error.stack,
cause: isErrorWithCause(error)
? error.cause instanceof Error
cause:
error.cause instanceof Error
? this.formatError(error.cause)
: error.cause
: undefined,
: error.cause,
};
}

Expand Down
1 change: 0 additions & 1 deletion packages/metrics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"scripts": {
"test": "npm run test:unit",
"test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose",
"test:e2e:nodejs16x": "RUNTIME=nodejs16x jest --group=e2e",
"test:e2e:nodejs18x": "RUNTIME=nodejs18x jest --group=e2e",
"test:e2e:nodejs20x": "RUNTIME=nodejs20x jest --group=e2e",
"test:e2e": "jest --group=e2e",
Expand Down
1 change: 0 additions & 1 deletion packages/parameters/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"test": "npm run test:unit",
"test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose",
"jest": "jest --detectOpenHandles --verbose",
"test:e2e:nodejs16x": "RUNTIME=nodejs16x jest --group=e2e",
"test:e2e:nodejs18x": "RUNTIME=nodejs18x jest --group=e2e",
"test:e2e:nodejs20x": "RUNTIME=nodejs20x jest --group=e2e",
"test:e2e": "jest --group=e2e",
Expand Down
2 changes: 1 addition & 1 deletion packages/parameters/src/appconfig/getAppConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const getAppConfig = <
| AppConfigGetOutput<ExplicitUserProvidedType, InferredFromOptionsType>
| undefined
> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('appconfig')) {
if (!Object.hasOwn(DEFAULT_PROVIDERS, 'appconfig')) {
DEFAULT_PROVIDERS.appconfig = new AppConfigProvider({
application: options?.application,
environment: options.environment,
Expand Down
2 changes: 1 addition & 1 deletion packages/parameters/src/secrets/getSecret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const getSecret = async <
| SecretsGetOutput<ExplicitUserProvidedType, InferredFromOptionsType>
| undefined
> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('secrets')) {
if (!Object.hasOwn(DEFAULT_PROVIDERS, 'secrets')) {
DEFAULT_PROVIDERS.secrets = new SecretsProvider();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/parameters/src/ssm/SSMProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ class SSMProvider extends BaseProvider {
reservedParameter: string,
throwOnError: boolean
): void {
if (!throwOnError && parameters.hasOwnProperty(reservedParameter)) {
if (!throwOnError && Object.hasOwn(parameters, reservedParameter)) {
throw new GetParameterError(
`You cannot fetch a parameter named ${reservedParameter} in graceful error mode.`
);
Expand Down
2 changes: 1 addition & 1 deletion packages/parameters/src/ssm/getParameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ const getParameter = async <
): Promise<
SSMGetOutput<ExplicitUserProvidedType, InferredFromOptionsType> | undefined
> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('ssm')) {
if (!Object.hasOwn(DEFAULT_PROVIDERS, 'ssm')) {
DEFAULT_PROVIDERS.ssm = new SSMProvider();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/parameters/src/ssm/getParameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const getParameters = async <
| SSMGetMultipleOutput<ExplicitUserProvidedType, InferredFromOptionsType>
| undefined
> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('ssm')) {
if (!Object.hasOwn(DEFAULT_PROVIDERS, 'ssm')) {
DEFAULT_PROVIDERS.ssm = new SSMProvider();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/parameters/src/ssm/getParametersByName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ const getParametersByName = async <ExplicitUserProvidedType = undefined>(
parameters: Record<string, SSMGetParametersByNameOptions>,
options?: SSMGetParametersByNameOptions
): Promise<SSMGetParametersByNameOutput<ExplicitUserProvidedType>> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('ssm')) {
if (!Object.hasOwn(DEFAULT_PROVIDERS, 'ssm')) {
DEFAULT_PROVIDERS.ssm = new SSMProvider();
}

Expand Down
14 changes: 6 additions & 8 deletions packages/parser/src/envelopes/apigw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ export class ApiGatewayEnvelope extends Envelope {
if (!parsedEnvelope.success) {
return {
success: false,
error: new ParseError(
'Failed to parse ApiGatewayEnvelope',
parsedEnvelope.error
),
error: new ParseError('Failed to parse ApiGatewayEnvelope', {
cause: parsedEnvelope.error,
}),
originalEvent: data,
};
}
Expand All @@ -36,10 +35,9 @@ export class ApiGatewayEnvelope extends Envelope {
if (!parsedBody.success) {
return {
success: false,
error: new ParseError(
'Failed to parse ApiGatewayEnvelope body',
parsedBody.error
),
error: new ParseError('Failed to parse ApiGatewayEnvelope body', {
cause: parsedBody.error,
}),
originalEvent: data,
};
}
Expand Down
14 changes: 6 additions & 8 deletions packages/parser/src/envelopes/apigwv2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ export class ApiGatewayV2Envelope extends Envelope {
if (!parsedEnvelope.success) {
return {
success: false,
error: new ParseError(
'Failed to parse API Gateway V2 envelope',
parsedEnvelope.error
),
error: new ParseError('Failed to parse API Gateway V2 envelope', {
cause: parsedEnvelope.error,
}),
originalEvent: data,
};
}
Expand All @@ -36,10 +35,9 @@ export class ApiGatewayV2Envelope extends Envelope {
if (!parsedBody.success) {
return {
success: false,
error: new ParseError(
'Failed to parse API Gateway V2 envelope body',
parsedBody.error
),
error: new ParseError('Failed to parse API Gateway V2 envelope body', {
cause: parsedBody.error,
}),
originalEvent: data,
};
}
Expand Down
14 changes: 6 additions & 8 deletions packages/parser/src/envelopes/cloudwatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ export class CloudWatchEnvelope extends Envelope {
if (!parsedEnvelope.success) {
return {
success: false,
error: new ParseError(
'Failed to parse CloudWatch envelope',
parsedEnvelope.error
),
error: new ParseError('Failed to parse CloudWatch envelope', {
cause: parsedEnvelope.error,
}),
originalEvent: data,
};
}
Expand All @@ -48,10 +47,9 @@ export class CloudWatchEnvelope extends Envelope {
if (!parsedMessage.success) {
return {
success: false,
error: new ParseError(
'Failed to parse CloudWatch log event',
parsedMessage.error
),
error: new ParseError('Failed to parse CloudWatch log event', {
cause: parsedMessage.error,
}),
originalEvent: data,
};
} else {
Expand Down
Loading

0 comments on commit e4eee73

Please sign in to comment.