From bbffbbafd2bbfc34c1417404de02bdfcf45dc521 Mon Sep 17 00:00:00 2001 From: Min Xia Date: Wed, 4 Sep 2024 21:33:03 -0700 Subject: [PATCH] Build Lambda Layer and sample app --- lambda-layer/README.md | 41 +++++++++++ lambda-layer/build.sh | 26 +++++++ lambda-layer/packages/layer/.eslintignore | 1 + lambda-layer/packages/layer/.eslintrc.js | 7 ++ lambda-layer/packages/layer/package.json | 53 +++++++++++++++ .../packages/layer/scripts/otel-instrument | 27 ++++++++ lambda-layer/packages/layer/src/wrapper.ts | 4 ++ lambda-layer/packages/layer/tsconfig.json | 11 +++ .../sample-apps/aws-sdk/.eslintignore | 1 + lambda-layer/sample-apps/aws-sdk/.eslintrc.js | 7 ++ lambda-layer/sample-apps/aws-sdk/package.json | 56 +++++++++++++++ lambda-layer/sample-apps/aws-sdk/src/index.ts | 21 ++++++ .../sample-apps/aws-sdk/tsconfig.json | 11 +++ .../terraform/api-gateway-proxy/main.tf | 67 ++++++++++++++++++ .../terraform/api-gateway-proxy/outputs.tf | 3 + .../terraform/api-gateway-proxy/variables.tf | 26 +++++++ lambda-layer/terraform/lambda/main.tf | 68 +++++++++++++++++++ lambda-layer/terraform/lambda/outputs.tf | 7 ++ lambda-layer/terraform/lambda/variables.tf | 29 ++++++++ lambda-layer/tsconfig.base.json | 25 +++++++ 20 files changed, 491 insertions(+) create mode 100644 lambda-layer/README.md create mode 100755 lambda-layer/build.sh create mode 100644 lambda-layer/packages/layer/.eslintignore create mode 100644 lambda-layer/packages/layer/.eslintrc.js create mode 100644 lambda-layer/packages/layer/package.json create mode 100644 lambda-layer/packages/layer/scripts/otel-instrument create mode 100644 lambda-layer/packages/layer/src/wrapper.ts create mode 100644 lambda-layer/packages/layer/tsconfig.json create mode 100644 lambda-layer/sample-apps/aws-sdk/.eslintignore create mode 100644 lambda-layer/sample-apps/aws-sdk/.eslintrc.js create mode 100644 lambda-layer/sample-apps/aws-sdk/package.json create mode 100644 lambda-layer/sample-apps/aws-sdk/src/index.ts create mode 100644 lambda-layer/sample-apps/aws-sdk/tsconfig.json create mode 100644 lambda-layer/terraform/api-gateway-proxy/main.tf create mode 100644 lambda-layer/terraform/api-gateway-proxy/outputs.tf create mode 100644 lambda-layer/terraform/api-gateway-proxy/variables.tf create mode 100644 lambda-layer/terraform/lambda/main.tf create mode 100644 lambda-layer/terraform/lambda/outputs.tf create mode 100644 lambda-layer/terraform/lambda/variables.tf create mode 100644 lambda-layer/tsconfig.base.json diff --git a/lambda-layer/README.md b/lambda-layer/README.md new file mode 100644 index 00000000..2d6b09c0 --- /dev/null +++ b/lambda-layer/README.md @@ -0,0 +1,41 @@ +# AWS Distro Lambda Layer for NodeJS + +This package includes the following three components + +1. AWS Lambda Layer implementation for supporting Application Signals in AWS Lambda. +2. Lambda Sample App with AWS SDK to demonstrate Application Signals telemetry data generated by Lambda Layer. +3. Terraform script for deploy the sample app with Lambda layer built from the local package. + +## Scripts to build everything + +Run the following command in the root director to build both NodeJS Lambda Layer and Sample App. + +**Note**: Make sure to install NodeJS 16+ to build the layer. Lower version of NodJS runtime is not supported by AWS Lambda +anymore. + +1. `./lambda-layer/build.sh` + +## Steps to Build AWS Lambda Layer + +1. Run the following command in the root director + * `./scripts/build_and_install_distro.sh` +2. Run to the following steps in `${root}/lambda-layer/packages/layer` director + + ```any + npm install + npm run compile + ``` + +## Steps to Deploy this Lambda function + +Go to `${root}/lambda-layer/sample-apps/aws-sdk` director, + +1. run `npm install`. +2. run `terraform init` and `terraform apply`. + +The lambda function(`aws-opentelemetry-distro-nodejs`) will be initialized and the URL for an API Gateway invoking the Lambda +will be displayed at the end. Send a request to the URL in a browser or using curl to execute the function. Then, +navigate to Lambda function's Monitoring page. +You will see a log stream with an event time and Traces data corresponding to when you issued the request, +open it and you can find +information about the exported spans in the log stream. diff --git a/lambda-layer/build.sh b/lambda-layer/build.sh new file mode 100755 index 00000000..46e38ee1 --- /dev/null +++ b/lambda-layer/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -x + +SOURCEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +echo "Source directory: ${SOURCEDIR}" + +# Navigate to the root project directory +cd "${SOURCEDIR}/.." + +# Install dependencies and compile all projects in the repository +echo "Installing dependencies and compiling projects..." +npm install +npm run compile + +# Build Lambda SDK layer +cd ${SOURCEDIR}/packages/layer || exit +rm -rf build +rm -rf node_modules +npm install || exit + +# Build sample apps +cd ${SOURCEDIR}/sample-apps/aws-sdk || exit +rm -rf build +rm -rf node_modules +npm install || exit diff --git a/lambda-layer/packages/layer/.eslintignore b/lambda-layer/packages/layer/.eslintignore new file mode 100644 index 00000000..378eac25 --- /dev/null +++ b/lambda-layer/packages/layer/.eslintignore @@ -0,0 +1 @@ +build diff --git a/lambda-layer/packages/layer/.eslintrc.js b/lambda-layer/packages/layer/.eslintrc.js new file mode 100644 index 00000000..f726f3be --- /dev/null +++ b/lambda-layer/packages/layer/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + "env": { + "mocha": true, + "node": true + }, + ...require('../../eslint.config.js') +} diff --git a/lambda-layer/packages/layer/package.json b/lambda-layer/packages/layer/package.json new file mode 100644 index 00000000..b2a71d70 --- /dev/null +++ b/lambda-layer/packages/layer/package.json @@ -0,0 +1,53 @@ +{ + "name": "@aws/aws-distro-opentelemetry-node-autoinstrumentatio-sdk-layer", + "version": "0.0.1", + "description": "Lambda Layer including AWS Distro OpenTelemetry SDK for supporting Amazon Application Signals", + "repository": "aws-observability/aws-otel-js-instrumentation", + "author": { + "name": "Amazon Web Services", + "url": "http://aws.amazon.com" + }, + "homepage": "https://github.com/aws-observability/aws-otel-js-instrumentation/tree/main/aws-distro-opentelemetry-node-autoinstrumentation#readme", + "license": "Apache-2.0", + "engines": { + "node": ">=16" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "clean": "rimraf build/*", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "prepare": "npm run compile", + "compile": "tsc -p .", + "postcompile": "copyfiles -F -e 'node_modules/@aws/aws-distro-opentelemetry-node-autoinstrumentation/node_modules/**' 'node_modules/**' build/workspace/nodejs && copyfiles -f 'scripts/*' build/workspace && copyfiles -f 'build/src/*' build/workspace && cd build/workspace && bestzip ../layer.zip *" + }, + "keywords": [ + "awsdistroopentelemetry", + "opentelemetry", + "awslambda", + "nodejs", + "tracing", + "profiling", + "instrumentation" + ], + "dependencies": { + "@aws/aws-distro-opentelemetry-node-autoinstrumentation": "file:../../../aws-distro-opentelemetry-node-autoinstrumentation", + "@opentelemetry/api": "1.9.0", + "@opentelemetry/auto-instrumentations-node": "0.48.0", + "@opentelemetry/auto-configuration-propagators": "0.2.0", + "@opentelemetry/exporter-metrics-otlp-grpc": "0.52.1", + "@opentelemetry/exporter-metrics-otlp-http": "0.52.1", + "@opentelemetry/instrumentation": "0.52.1", + "@opentelemetry/id-generator-aws-xray": "1.2.2", + "@opentelemetry/propagator-aws-xray": "1.25.1", + "@opentelemetry/core": "1.25.1", + "@opentelemetry/sdk-trace-base": "1.25.1", + "@opentelemetry/semantic-conventions": "1.25.1", + "@opentelemetry/resources": "1.25.1", + "@opentelemetry/exporter-trace-otlp-proto": "0.52.1", + "@opentelemetry/exporter-zipkin": "1.25.1", + "@opentelemetry/sdk-metrics": "1.25.1" + } +} diff --git a/lambda-layer/packages/layer/scripts/otel-instrument b/lambda-layer/packages/layer/scripts/otel-instrument new file mode 100644 index 00000000..fbdb4bd6 --- /dev/null +++ b/lambda-layer/packages/layer/scripts/otel-instrument @@ -0,0 +1,27 @@ +#!/bin/bash +export NODE_OPTIONS="${NODE_OPTIONS} --require /opt/wrapper.js" +export LAMBDA_RESOURCE_ATTRIBUTES="cloud.region=$AWS_REGION,cloud.provider=aws,faas.name=$AWS_LAMBDA_FUNCTION_NAME,faas.version=$AWS_LAMBDA_FUNCTION_VERSION,faas.instance=$AWS_LAMBDA_LOG_STREAM_NAME,aws.log.group.names=$AWS_LAMBDA_LOG_GROUP_NAME"; +export OTEL_NODE_ENABLED_INSTRUMENTATIONS="http,aws-lambda,aws-sdk" + +# - Set Application Signals configuration +if [ "${OTEL_AWS_APPLICATION_SIGNALS_ENABLED}" = "true" ]; then + export OTEL_METRICS_EXPORTER="none"; + export OTEL_LOGS_EXPORTER="none"; +fi + +# - Append Lambda Resource Attributes to OTel Resource Attribute List +if [ -z "${OTEL_RESOURCE_ATTRIBUTES}" ]; then + export OTEL_RESOURCE_ATTRIBUTES=$LAMBDA_RESOURCE_ATTRIBUTES; +else + export OTEL_RESOURCE_ATTRIBUTES="$LAMBDA_RESOURCE_ATTRIBUTES,$OTEL_RESOURCE_ATTRIBUTES"; +fi + +# - Set the service name +if [ -z "${OTEL_SERVICE_NAME}" ]; then + export OTEL_SERVICE_NAME=$AWS_LAMBDA_FUNCTION_NAME; +fi +if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then + export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" +fi + +exec "$@" diff --git a/lambda-layer/packages/layer/src/wrapper.ts b/lambda-layer/packages/layer/src/wrapper.ts new file mode 100644 index 00000000..9345b817 --- /dev/null +++ b/lambda-layer/packages/layer/src/wrapper.ts @@ -0,0 +1,4 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +require('@aws/aws-distro-opentelemetry-node-autoinstrumentation/register') \ No newline at end of file diff --git a/lambda-layer/packages/layer/tsconfig.json b/lambda-layer/packages/layer/tsconfig.json new file mode 100644 index 00000000..4078877c --- /dev/null +++ b/lambda-layer/packages/layer/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/lambda-layer/sample-apps/aws-sdk/.eslintignore b/lambda-layer/sample-apps/aws-sdk/.eslintignore new file mode 100644 index 00000000..378eac25 --- /dev/null +++ b/lambda-layer/sample-apps/aws-sdk/.eslintignore @@ -0,0 +1 @@ +build diff --git a/lambda-layer/sample-apps/aws-sdk/.eslintrc.js b/lambda-layer/sample-apps/aws-sdk/.eslintrc.js new file mode 100644 index 00000000..f726f3be --- /dev/null +++ b/lambda-layer/sample-apps/aws-sdk/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + "env": { + "mocha": true, + "node": true + }, + ...require('../../eslint.config.js') +} diff --git a/lambda-layer/sample-apps/aws-sdk/package.json b/lambda-layer/sample-apps/aws-sdk/package.json new file mode 100644 index 00000000..856fa77b --- /dev/null +++ b/lambda-layer/sample-apps/aws-sdk/package.json @@ -0,0 +1,56 @@ +{ + "name": "@opentelemetry-samples/lambda-awssdk", + "description": "Sample application for AWS Lambda using AWS SDK v2.", + "version": "0.0.1", + "repository": "aws-observability/aws-otel-js-instrumentation", + "author": { + "name": "Amazon Web Services", + "url": "http://aws.amazon.com" + }, + "homepage": "https://github.com/aws-observability/aws-otel-js-instrumentation/tree/main/aws-distro-opentelemetry-node-autoinstrumentation#readme", + "license": "Apache-2.0", + "engines": { + "node": ">=16" + }, + "publishConfig": { + "access": "public" + }, + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "scripts": { + "clean": "rimraf build/*", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "precompile": "tsc --version", + "prepare": "npm run compile", + "compile": "tsc -p .", + "postcompile": "copyfiles 'package*.json' build/src/ && npm install --production --ignore-scripts --prefix build/src/ && cd build/src && bestzip ../function.zip *" + }, + "keywords": [ + "opentelemetry", + "awslambda", + "nodejs", + "tracing", + "profiling", + "instrumentation" + ], + "files": [ + "build/src/**/*.js", + "build/src/**/*.d.ts", + "doc", + "LICENSE", + "README.md" + ], + "devDependencies": { + "@types/aws-lambda": "8.10.110", + "@types/node": "18.14.6", + "bestzip": "2.2.0", + "copyfiles": "2.4.1", + "rimraf": "4.1.2", + "ts-node": "10.9.1", + "typescript": "4.9.5" + }, + "dependencies": { + "aws-sdk": "2.1328.0" + } +} diff --git a/lambda-layer/sample-apps/aws-sdk/src/index.ts b/lambda-layer/sample-apps/aws-sdk/src/index.ts new file mode 100644 index 00000000..5b24caa1 --- /dev/null +++ b/lambda-layer/sample-apps/aws-sdk/src/index.ts @@ -0,0 +1,21 @@ +import { + APIGatewayProxyEvent, + APIGatewayProxyResult, + Context, +} from 'aws-lambda'; + +import AWS from 'aws-sdk'; + +const s3 = new AWS.S3(); + +exports.handler = async (event: APIGatewayProxyEvent, context: Context) => { + console.info('Serving lambda request.'); + + const result = await s3.listBuckets().promise(); + + const response: APIGatewayProxyResult = { + statusCode: 200, + body: `Hello lambda - found ${result.Buckets?.length || 0} buckets`, + }; + return response; +}; diff --git a/lambda-layer/sample-apps/aws-sdk/tsconfig.json b/lambda-layer/sample-apps/aws-sdk/tsconfig.json new file mode 100644 index 00000000..4078877c --- /dev/null +++ b/lambda-layer/sample-apps/aws-sdk/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/lambda-layer/terraform/api-gateway-proxy/main.tf b/lambda-layer/terraform/api-gateway-proxy/main.tf new file mode 100644 index 00000000..4bd8afbe --- /dev/null +++ b/lambda-layer/terraform/api-gateway-proxy/main.tf @@ -0,0 +1,67 @@ +resource "aws_api_gateway_rest_api" "lambda_api_proxy" { + name = var.name +} + +resource "aws_api_gateway_resource" "lambda_api_proxy" { + rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id + parent_id = aws_api_gateway_rest_api.lambda_api_proxy.root_resource_id + path_part = "{proxy+}" +} + +resource "aws_api_gateway_method" "lambda_api_proxy" { + rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id + resource_id = aws_api_gateway_resource.lambda_api_proxy.id + http_method = "ANY" + authorization = "NONE" +} + +resource "aws_api_gateway_integration" "lambda_api" { + rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id + resource_id = aws_api_gateway_method.lambda_api_proxy.resource_id + http_method = aws_api_gateway_method.lambda_api_proxy.http_method + + integration_http_method = "POST" + type = "AWS_PROXY" + uri = var.function_invoke_arn +} + +resource "aws_api_gateway_method" "lambda_api_proxy_root_nodejs" { + rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id + resource_id = aws_api_gateway_rest_api.lambda_api_proxy.root_resource_id + http_method = "ANY" + authorization = "NONE" +} + +resource "aws_api_gateway_integration" "lambda_api_root_nodejs" { + rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id + resource_id = aws_api_gateway_method.lambda_api_proxy_root_nodejs.resource_id + http_method = aws_api_gateway_method.lambda_api_proxy_root_nodejs.http_method + + integration_http_method = "POST" + type = "AWS_PROXY" + uri = var.function_invoke_arn +} + +resource "aws_api_gateway_deployment" "lambda_api_proxy" { + depends_on = [ + aws_api_gateway_integration.lambda_api, + aws_api_gateway_integration.lambda_api_root_nodejs, + ] + + rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id +} + +resource "aws_api_gateway_stage" "test" { + stage_name = "default" + rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id + deployment_id = aws_api_gateway_deployment.lambda_api_proxy.id + xray_tracing_enabled = var.enable_xray_tracing +} + +resource "aws_lambda_permission" "lambda_api_allow_gateway_nodejs" { + action = "lambda:InvokeFunction" + function_name = var.function_name + qualifier = var.function_qualifier + principal = "apigateway.amazonaws.com" + source_arn = "${aws_api_gateway_rest_api.lambda_api_proxy.execution_arn}/*/*" +} diff --git a/lambda-layer/terraform/api-gateway-proxy/outputs.tf b/lambda-layer/terraform/api-gateway-proxy/outputs.tf new file mode 100644 index 00000000..646329f4 --- /dev/null +++ b/lambda-layer/terraform/api-gateway-proxy/outputs.tf @@ -0,0 +1,3 @@ +output "api_gateway_url" { + value = aws_api_gateway_stage.test.invoke_url +} diff --git a/lambda-layer/terraform/api-gateway-proxy/variables.tf b/lambda-layer/terraform/api-gateway-proxy/variables.tf new file mode 100644 index 00000000..125cd1f2 --- /dev/null +++ b/lambda-layer/terraform/api-gateway-proxy/variables.tf @@ -0,0 +1,26 @@ +variable "name" { + type = string + description = "Name of API gateway to create" +} + +variable "function_name" { + type = string + description = "Name of function to proxy to" +} + +variable "function_qualifier" { + type = string + default = null + description = "Qualifier of function to proxy to" +} + +variable "function_invoke_arn" { + type = string + description = "Invoke ARN of function to proxy to" +} + +variable "enable_xray_tracing" { + type = bool + description = "Whether to enable xray tracing of the API gateway" + default = true +} diff --git a/lambda-layer/terraform/lambda/main.tf b/lambda-layer/terraform/lambda/main.tf new file mode 100644 index 00000000..fdce15eb --- /dev/null +++ b/lambda-layer/terraform/lambda/main.tf @@ -0,0 +1,68 @@ +locals { + architecture = var.architecture == "x86_64" ? "amd64" : "arm64" +} +resource "aws_lambda_layer_version" "sdk_layer" { + layer_name = var.sdk_layer_name + filename = "${path.module}/../../packages/layer/build/layer.zip" + compatible_runtimes = ["nodejs14.x", "nodejs16.x", "nodejs18.x"] + license_info = "Apache-2.0" + source_code_hash = filebase64sha256("${path.module}/../../packages/layer/build/layer.zip") +} + +module "hello-lambda-function" { + source = "terraform-aws-modules/lambda/aws" + version = ">= 2.24.0" + + architectures = compact([var.architecture]) + function_name = var.function_name + handler = "index.handler" + runtime = var.runtime + + create_package = false + local_existing_package = "${path.module}/../../sample-apps/aws-sdk/build/function.zip" + + memory_size = 512 + timeout = 30 + + layers = compact([aws_lambda_layer_version.sdk_layer.arn]) + + environment_variables = { + AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-instrument" + OTEL_AWS_APPLICATION_SIGNALS_ENABLED = "true" + OTEL_METRICS_EXPORTER = "none" + } + + tracing_mode = var.tracing_mode + + attach_policy_statements = true + policy_statements = { + s3 = { + effect = "Allow" + actions = [ + "s3:ListAllMyBuckets" + ] + resources = [ + "*" + ] + } + } +} + +module "api-gateway" { + source = "../api-gateway-proxy" + + name = var.function_name + function_name = module.hello-lambda-function.lambda_function_name + function_invoke_arn = module.hello-lambda-function.lambda_function_invoke_arn + enable_xray_tracing = var.tracing_mode == "Active" +} + +resource "aws_iam_role_policy_attachment" "hello-lambda-cloudwatch" { + role = module.hello-lambda-function.lambda_function_name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + +resource "aws_iam_role_policy_attachment" "test_xray" { + role = module.hello-lambda-function.lambda_function_name + policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess" +} diff --git a/lambda-layer/terraform/lambda/outputs.tf b/lambda-layer/terraform/lambda/outputs.tf new file mode 100644 index 00000000..5de8044c --- /dev/null +++ b/lambda-layer/terraform/lambda/outputs.tf @@ -0,0 +1,7 @@ +output "api-gateway-url" { + value = module.api-gateway.api_gateway_url +} + +output "function_role_name" { + value = module.hello-lambda-function.lambda_role_name +} diff --git a/lambda-layer/terraform/lambda/variables.tf b/lambda-layer/terraform/lambda/variables.tf new file mode 100644 index 00000000..e900c217 --- /dev/null +++ b/lambda-layer/terraform/lambda/variables.tf @@ -0,0 +1,29 @@ +variable "function_name" { + type = string + description = "Name of sample app function / API gateway" + default = "aws-opentelemetry-distro-nodejs" +} + +variable "sdk_layer_name" { + type = string + description = "Name of published SDK layer" + default = "aws-opentelemetry-distro-nodejs" +} + +variable "tracing_mode" { + type = string + description = "Lambda function tracing mode" + default = "Active" +} + +variable "runtime" { + type = string + description = "NodeJS runtime version used for sample Lambda Function" + default = "nodejs16.x" +} + +variable "architecture" { + type = string + description = "Lambda function architecture, valid values are arm64 or x86_64" + default = "x86_64" +} diff --git a/lambda-layer/tsconfig.base.json b/lambda-layer/tsconfig.base.json new file mode 100644 index 00000000..2e9e6401 --- /dev/null +++ b/lambda-layer/tsconfig.base.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "module": "commonjs", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "pretty": true, + "sourceMap": true, + "strict": true, + "strictNullChecks": true, + "target": "es2017", + "incremental": true, + "newLine": "LF" + }, + "exclude": [ + "node_modules" + ] +}