@leanstacks/lambda-utils 0.1.0-alpha.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/.editorconfig ADDED
@@ -0,0 +1,12 @@
1
+ # This file is used to define coding styles and formatting rules for the project.
2
+ # For more information, see https://editorconfig.org/
3
+ root=true
4
+
5
+ [*]
6
+ charset=utf-8
7
+ end_of_line=lf
8
+ indent_style=space
9
+ indent_size=2
10
+ insert_final_newline=true
11
+ max_line_length=120
12
+ trim_trailing_whitespace=true
@@ -0,0 +1,101 @@
1
+ # Lambda Utilities Project Instructions
2
+
3
+ This project contains a set of utilities and helper functions designed to streamline the development of AWS Lambda functions using TypeScript. The utilities cover common tasks such as input validation, response formatting, error handling, and logging. The project is packaged and published as an npm package for easy integration into other Lambda projects.
4
+
5
+ ---
6
+
7
+ ## Technology Stack
8
+
9
+ Each pattern project uses the following technology stack:
10
+
11
+ - **Language:** TypeScript
12
+ - **Platform:** AWS Lambda
13
+ - **Runtime:** Node.js 24.x
14
+ - **AWS SDK:** v3 (modular packages)
15
+ - **Testing:** Jest
16
+ - **Linting/Formatting:** ESLint + Prettier
17
+ - **Validation:** Zod
18
+ - **Logging:** Pino + Pino-Lambda
19
+ - **Package Manager:** npm
20
+ - **Package Bundler:** rollup
21
+
22
+ ---
23
+
24
+ ## Pattern Project Structure
25
+
26
+ Each pattern project follows a consistent directory and file structure to promote maintainability and scalability. Below is an example structure:
27
+
28
+ ```
29
+ /docs # Project documentation
30
+ README.md # Documentation table of contents
31
+
32
+ /src
33
+ /logging
34
+ logger.ts # Logger utility using Pino
35
+ logger.test.ts # Unit tests for logger
36
+ /clients
37
+ dynamodb-client.ts # AWS SDK client for DynamoDB
38
+ dynamodb-client.test.ts # Unit tests for DynamoDB client
39
+ lambda-client.ts # AWS SDK client for Lambda
40
+ lambda-client.test.ts # Unit tests for Lambda client
41
+ /validation
42
+ config.ts # Configuration validation with Zod
43
+ config.test.ts # Unit tests for config
44
+ validator.ts # Generic validator helpers
45
+ validator.test.ts # Unit tests for validator
46
+ /responses
47
+ apigateway-response.ts # Standard API response helpers
48
+ apigateway-response.test.ts # Unit tests for API response helpers
49
+ .editorconfig # Editor config
50
+ .gitignore # Git ignore rules
51
+ .nvmrc # Node version manager config
52
+ .prettierrc # Prettier config
53
+ eslint.config.mjs # ESLint config
54
+ jest.config.ts # App Jest config
55
+ jest.setup.ts # App Jest setup
56
+ package.json # App NPM package config
57
+ README.md # Project README
58
+ tsconfig.json # Project TypeScript config
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Source Code Guidelines
64
+
65
+ Each pattern project follows best practices for source code organization, naming conventions, and coding standards. Below are the key guidelines:
66
+
67
+ - Use **TypeScript** for all source and infrastructure code.
68
+ - Use arrow functions for defining functions.
69
+ - Use path aliases for cleaner imports (e.g., `@utils`, `@models`).
70
+ - Organize import statements: external packages first, then internal modules.
71
+ - Use async/await for asynchronous operations.
72
+ - Document functions and modules with JSDoc comments.
73
+
74
+ ### Source Code Commands & Scripts
75
+
76
+ - Use `npm run build` to compile TypeScript.
77
+ - Use `npm run test` to run tests.
78
+ - Use `npm run test:coverage` to run tests with coverage report.
79
+ - Use `npm run lint` to run ESLint.
80
+ - Use `npm run lint:fix` to fix ESLint issues.
81
+ - Use `npm run format` to run Prettier to format code.
82
+ - Use `npm run format:check` to check code formatting with Prettier.
83
+
84
+ ---
85
+
86
+ ## Unit Testing Guidelines
87
+
88
+ Each pattern project includes comprehensive unit tests for both application and infrastructure code. Below are the key guidelines for writing unit tests:
89
+
90
+ - Use the **Jest** testing framework.
91
+ - Place test files next to the source file, with `.test.ts` suffix.
92
+ - Use `describe` and `it` blocks for organization.
93
+ - Use `beforeEach` for setup and `afterEach` for cleanup.
94
+ - Use `expect` assertions for results.
95
+ - Mock dependencies to isolate the component under test.
96
+ - Mock external calls (e.g., AWS SDK, databases).
97
+ - Structure your tests using the Arrange-Act-Assert pattern:
98
+ - **Arrange:** Set up the test environment, including any necessary mocks and test data.
99
+ - **Act:** Execute the function or service being tested.
100
+ - **Assert:** Verify that the results are as expected.
101
+ - Add comments to separate these sections for clarity.
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 24.11.1
package/.prettierrc ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "plugins": [],
3
+ "printWidth": 120,
4
+ "semi": true,
5
+ "singleQuote": true,
6
+ "tabWidth": 2,
7
+ "trailingComma": "all"
8
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 LeanStacks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Lambda Utilities
2
+
3
+ Lambda utilities
@@ -0,0 +1 @@
1
+ export { initializeLogger, logger, LoggerConfig } from './logging/logger';
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ import pino from 'pino';
2
+ import { StructuredLogFormatter, pinoLambdaDestination, CloudwatchLogFormatter } from 'pino-lambda';
3
+
4
+ /**
5
+ * Module-level state to store logger configuration
6
+ */
7
+ let _loggerConfig = {
8
+ enabled: true,
9
+ level: 'info',
10
+ format: 'json',
11
+ };
12
+ /**
13
+ * Module-level cache for the logger instance
14
+ */
15
+ let _loggerInstance = null;
16
+ /**
17
+ * Create and return the Pino Lambda logger instance
18
+ * Uses the configuration set by initializeLogger
19
+ * Logger instance is cached after first creation
20
+ */
21
+ const _createLogger = () => {
22
+ const formatter = _loggerConfig.format === 'json' ? new StructuredLogFormatter() : new CloudwatchLogFormatter();
23
+ const lambdaDestination = pinoLambdaDestination({
24
+ formatter,
25
+ });
26
+ return pino({
27
+ enabled: _loggerConfig.enabled,
28
+ level: _loggerConfig.level,
29
+ }, lambdaDestination);
30
+ };
31
+ /**
32
+ * Get the cached logger instance, creating it if necessary
33
+ */
34
+ const _getLogger = () => {
35
+ if (_loggerInstance === null) {
36
+ _loggerInstance = _createLogger();
37
+ }
38
+ return _loggerInstance;
39
+ };
40
+ /**
41
+ * Initialize the logger with configuration
42
+ * Should be called once at Lambda handler entry point
43
+ * Invalidates the cached logger instance so a new one is created with the updated config
44
+ *
45
+ * @param config Logger configuration options
46
+ * @returns void
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * import { initializeLogger } from '@utils/logging/logger';
51
+ *
52
+ * initializeLogger({
53
+ * enabled: true,
54
+ * level: 'debug',
55
+ * format: 'json',
56
+ * });
57
+ * ```
58
+ */
59
+ const initializeLogger = (config) => {
60
+ _loggerConfig = {
61
+ enabled: config.enabled ?? true,
62
+ level: config.level ?? 'info',
63
+ format: config.format ?? 'json',
64
+ };
65
+ // Invalidate the cached logger instance so a new one is created with updated config
66
+ _loggerInstance = null;
67
+ };
68
+ /**
69
+ * Pino logger instance
70
+ * Configuration is supplied via initializeLogger() and persists across imports
71
+ * Logger instance is cached after first creation for reuse
72
+ */
73
+ const logger = _getLogger();
74
+
75
+ export { initializeLogger, logger };
@@ -0,0 +1,38 @@
1
+ import pino from 'pino';
2
+ /**
3
+ * Configuration options for the Pino Lambda logger
4
+ */
5
+ export interface LoggerConfig {
6
+ /** Whether logging is enabled */
7
+ enabled?: boolean;
8
+ /** Minimum log level (e.g., 'debug', 'info', 'warn', 'error') */
9
+ level?: 'debug' | 'info' | 'warn' | 'error';
10
+ /** Output format: 'json' for StructuredLogFormatter, 'text' for CloudwatchLogFormatter */
11
+ format?: 'json' | 'text';
12
+ }
13
+ /**
14
+ * Initialize the logger with configuration
15
+ * Should be called once at Lambda handler entry point
16
+ * Invalidates the cached logger instance so a new one is created with the updated config
17
+ *
18
+ * @param config Logger configuration options
19
+ * @returns void
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import { initializeLogger } from '@utils/logging/logger';
24
+ *
25
+ * initializeLogger({
26
+ * enabled: true,
27
+ * level: 'debug',
28
+ * format: 'json',
29
+ * });
30
+ * ```
31
+ */
32
+ export declare const initializeLogger: (config: LoggerConfig) => void;
33
+ /**
34
+ * Pino logger instance
35
+ * Configuration is supplied via initializeLogger() and persists across imports
36
+ * Logger instance is cached after first creation for reuse
37
+ */
38
+ export declare const logger: pino.Logger<never, boolean>;
package/docs/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Lambda Utilities - Documentation
2
+
3
+ Welcome to the Lambda Utilities documentation. This library provides a comprehensive set of utilities and helper functions to streamline the development of AWS Lambda functions using TypeScript.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Getting Started](./GETTING_STARTED.md)
8
+ - [Logging](./LOGGING.md)
9
+ - [API Gateway Responses](./API_GATEWAY_RESPONSES.md)
10
+ - [Configuration](./CONFIGURATION.md)
11
+ - [Clients](./CLIENTS.md)
12
+
13
+ ## Quick Start
14
+
15
+ Install the package:
16
+
17
+ ```bash
18
+ npm install @leanstacks/lambda-utils
19
+ ```
20
+
21
+ Use a utility in your Lambda function:
22
+
23
+ ```typescript
24
+ import { getLogger } from '@leanstacks/lambda-utils';
25
+ import { success } from '@leanstacks/lambda-utils';
26
+
27
+ const logger = getLogger();
28
+
29
+ export const handler = async (event: any) => {
30
+ logger.info({ message: 'Processing event', event });
31
+
32
+ // Your handler logic here
33
+
34
+ return success({ message: 'Success' });
35
+ };
36
+ ```
37
+
38
+ ## Features
39
+
40
+ - **Logging:** Structured logging with Pino configured for Lambda
41
+ - **API Responses:** Standard response formatting for API Gateway
42
+ - **Configuration:** Environment variable validation with Zod
43
+ - **AWS Clients:** Pre-configured AWS SDK v3 clients
44
+ - **Type Safe:** Full TypeScript support with comprehensive types
45
+
46
+ ## Support
47
+
48
+ For issues or questions, please visit the [GitHub repository](https://github.com/leanstacks/lambda-utils).
@@ -0,0 +1,44 @@
1
+ import js from '@eslint/js';
2
+ import tsPlugin from '@typescript-eslint/eslint-plugin';
3
+ import tsParser from '@typescript-eslint/parser';
4
+
5
+ export default [
6
+ {
7
+ ignores: ['dist', 'node_modules'],
8
+ },
9
+ {
10
+ files: ['src/**/*.ts'],
11
+ languageOptions: {
12
+ parser: tsParser,
13
+ parserOptions: {
14
+ ecmaVersion: 2020,
15
+ sourceType: 'module',
16
+ },
17
+ globals: {
18
+ console: 'readonly',
19
+ process: 'readonly',
20
+ describe: 'readonly',
21
+ it: 'readonly',
22
+ expect: 'readonly',
23
+ beforeEach: 'readonly',
24
+ afterEach: 'readonly',
25
+ jest: 'readonly',
26
+ },
27
+ },
28
+ plugins: {
29
+ '@typescript-eslint': tsPlugin,
30
+ },
31
+ rules: {
32
+ ...js.configs.recommended.rules,
33
+ ...tsPlugin.configs.recommended.rules,
34
+ '@typescript-eslint/no-unused-vars': [
35
+ 'error',
36
+ {
37
+ argsIgnorePattern: '^_',
38
+ varsIgnorePattern: '^_',
39
+ },
40
+ ],
41
+ '@typescript-eslint/no-explicit-any': 'warn',
42
+ },
43
+ },
44
+ ];
package/jest.config.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { Config } from 'jest';
2
+
3
+ const config: Config = {
4
+ preset: 'ts-jest',
5
+ testEnvironment: 'node',
6
+ rootDir: 'src',
7
+ testMatch: ['**/*.test.ts'],
8
+ moduleNameMapper: {
9
+ '^@/(.*)$': '<rootDir>/$1',
10
+ },
11
+ collectCoverageFrom: ['**/*.ts', '!**/*.test.ts'],
12
+ coveragePathIgnorePatterns: ['/node_modules/'],
13
+ };
14
+
15
+ export default config;
package/jest.setup.ts ADDED
@@ -0,0 +1,9 @@
1
+ // Jest setup file for global test configuration
2
+ // Add any global test setup here
3
+
4
+ // Mock pino-lambda for tests
5
+ jest.mock('pino-lambda', () => {
6
+ return {
7
+ target: 'pino-lambda',
8
+ };
9
+ });
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@leanstacks/lambda-utils",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "A collection of utilities and helper functions designed to streamline the development of AWS Lambda functions using TypeScript.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "rollup -c",
9
+ "build:watch": "rollup -c -w",
10
+ "clean": "rimraf dist",
11
+ "test": "jest",
12
+ "test:watch": "jest --watch",
13
+ "test:coverage": "jest --coverage",
14
+ "lint": "eslint src",
15
+ "lint:fix": "eslint src --fix",
16
+ "format": "prettier --write \"src/**/*.ts\"",
17
+ "format:check": "prettier --check \"src/**/*.ts\""
18
+ },
19
+ "keywords": [
20
+ "lambda",
21
+ "aws",
22
+ "utilities",
23
+ "nodejs",
24
+ "typescript"
25
+ ],
26
+ "author": "Matthew Warman <leanstacker@gmail.com> (https://leanstacks.com)",
27
+ "license": "MIT",
28
+ "devDependencies": {
29
+ "@eslint/js": "9.39.2",
30
+ "@types/aws-lambda": "8.10.159",
31
+ "@types/jest": "30.0.0",
32
+ "@types/node": "25.0.3",
33
+ "@typescript-eslint/eslint-plugin": "8.50.0",
34
+ "@typescript-eslint/parser": "8.50.0",
35
+ "eslint": "9.39.2",
36
+ "jest": "30.2.0",
37
+ "prettier": "3.7.4",
38
+ "rimraf": "6.1.2",
39
+ "rollup": "4.53.5",
40
+ "rollup-plugin-typescript2": "0.36.0",
41
+ "ts-jest": "29.4.6",
42
+ "ts-node": "10.9.2",
43
+ "typescript": "5.9.3"
44
+ },
45
+ "dependencies": {
46
+ "pino": "10.1.0",
47
+ "pino-lambda": "4.4.1",
48
+ "zod": "4.2.1"
49
+ }
50
+ }
@@ -0,0 +1,18 @@
1
+ import typescript from 'rollup-plugin-typescript2';
2
+
3
+ export default {
4
+ input: 'src/index.ts',
5
+ output: [
6
+ {
7
+ file: 'dist/index.js',
8
+ format: 'esm',
9
+ },
10
+ ],
11
+ external: ['pino', 'pino-lambda', 'zod', '@aws-sdk/client-dynamodb', '@aws-sdk/client-lambda'],
12
+ plugins: [
13
+ typescript({
14
+ tsconfig: 'tsconfig.json',
15
+ clean: true,
16
+ }),
17
+ ],
18
+ };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { initializeLogger, logger, LoggerConfig } from './logging/logger';
@@ -0,0 +1,95 @@
1
+ import pino from 'pino';
2
+ import { CloudwatchLogFormatter, pinoLambdaDestination, StructuredLogFormatter } from 'pino-lambda';
3
+
4
+ /**
5
+ * Configuration options for the Pino Lambda logger
6
+ */
7
+ export interface LoggerConfig {
8
+ /** Whether logging is enabled */
9
+ enabled?: boolean;
10
+ /** Minimum log level (e.g., 'debug', 'info', 'warn', 'error') */
11
+ level?: 'debug' | 'info' | 'warn' | 'error';
12
+ /** Output format: 'json' for StructuredLogFormatter, 'text' for CloudwatchLogFormatter */
13
+ format?: 'json' | 'text';
14
+ }
15
+
16
+ /**
17
+ * Module-level state to store logger configuration
18
+ */
19
+ let _loggerConfig: LoggerConfig = {
20
+ enabled: true,
21
+ level: 'info',
22
+ format: 'json',
23
+ };
24
+
25
+ /**
26
+ * Module-level cache for the logger instance
27
+ */
28
+ let _loggerInstance: pino.Logger | null = null;
29
+
30
+ /**
31
+ * Create and return the Pino Lambda logger instance
32
+ * Uses the configuration set by initializeLogger
33
+ * Logger instance is cached after first creation
34
+ */
35
+ const _createLogger = (): pino.Logger => {
36
+ const formatter = _loggerConfig.format === 'json' ? new StructuredLogFormatter() : new CloudwatchLogFormatter();
37
+
38
+ const lambdaDestination = pinoLambdaDestination({
39
+ formatter,
40
+ });
41
+
42
+ return pino(
43
+ {
44
+ enabled: _loggerConfig.enabled,
45
+ level: _loggerConfig.level,
46
+ },
47
+ lambdaDestination,
48
+ );
49
+ };
50
+
51
+ /**
52
+ * Get the cached logger instance, creating it if necessary
53
+ */
54
+ const _getLogger = (): pino.Logger => {
55
+ if (_loggerInstance === null) {
56
+ _loggerInstance = _createLogger();
57
+ }
58
+ return _loggerInstance;
59
+ };
60
+
61
+ /**
62
+ * Initialize the logger with configuration
63
+ * Should be called once at Lambda handler entry point
64
+ * Invalidates the cached logger instance so a new one is created with the updated config
65
+ *
66
+ * @param config Logger configuration options
67
+ * @returns void
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * import { initializeLogger } from '@utils/logging/logger';
72
+ *
73
+ * initializeLogger({
74
+ * enabled: true,
75
+ * level: 'debug',
76
+ * format: 'json',
77
+ * });
78
+ * ```
79
+ */
80
+ export const initializeLogger = (config: LoggerConfig): void => {
81
+ _loggerConfig = {
82
+ enabled: config.enabled ?? true,
83
+ level: config.level ?? 'info',
84
+ format: config.format ?? 'json',
85
+ };
86
+ // Invalidate the cached logger instance so a new one is created with updated config
87
+ _loggerInstance = null;
88
+ };
89
+
90
+ /**
91
+ * Pino logger instance
92
+ * Configuration is supplied via initializeLogger() and persists across imports
93
+ * Logger instance is cached after first creation for reuse
94
+ */
95
+ export const logger = _getLogger();
package/tsconfig.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "lib": ["ES2020"],
6
+ "declaration": true,
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "moduleResolution": "node",
15
+ "baseUrl": "./src",
16
+ "paths": {
17
+ "@/*": ["./*"]
18
+ }
19
+ },
20
+ "include": ["src/**/*"],
21
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
22
+ }