@leanstacks/lambda-utils 0.3.0-alpha.4 → 0.3.0

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/README.md CHANGED
@@ -46,6 +46,33 @@ export const handler = async (event: any, context: any) => {
46
46
  };
47
47
  ```
48
48
 
49
+ ### Configuration Example
50
+
51
+ ```typescript
52
+ import { z } from 'zod';
53
+ import { createConfigManager } from '@leanstacks/lambda-utils';
54
+
55
+ // Define your configuration schema
56
+ const configSchema = z.object({
57
+ TABLE_NAME: z.string().min(1),
58
+ AWS_REGION: z.string().default('us-east-1'),
59
+ LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
60
+ });
61
+
62
+ type Config = z.infer<typeof configSchema>;
63
+
64
+ const configManager = createConfigManager(configSchema);
65
+ const config = configManager.get();
66
+
67
+ export const handler = async (event: any) => {
68
+ console.log(`Using table: ${config.TABLE_NAME}`);
69
+
70
+ // Your Lambda handler logic here
71
+
72
+ return { statusCode: 200, body: 'Success' };
73
+ };
74
+ ```
75
+
49
76
  ### API Response Example
50
77
 
51
78
  ```typescript
@@ -77,12 +104,35 @@ Comprehensive guides and examples are available in the `docs` directory:
77
104
 
78
105
  | Guide | Description |
79
106
  | ------------------------------------------------------------ | ---------------------------------------------------------------------- |
107
+ | **[Configuration Guide](./docs/CONFIGURATION.md)** | Validate environment variables with Zod schemas and type safety |
80
108
  | **[Logging Guide](./docs/LOGGING.md)** | Configure and use structured logging with automatic AWS Lambda context |
81
109
  | **[API Gateway Responses](./docs/API_GATEWAY_RESPONSES.md)** | Format responses for API Gateway with standard HTTP patterns |
82
- | **[AWS Clients](./docs/README.md)** | Use pre-configured AWS SDK v3 clients in your handlers |
110
+ | **[DynamoDB Client](./docs/DYNAMODB_CLIENT.md)** | Use pre-configured AWS SDK v3 clients in your handlers |
83
111
 
84
112
  ## Usage
85
113
 
114
+ ### Configuration
115
+
116
+ Validate and manage environment variables with type safety:
117
+
118
+ ```typescript
119
+ import { z } from 'zod';
120
+ import { createConfigManager } from '@leanstacks/lambda-utils';
121
+
122
+ const configManager = createConfigManager(
123
+ z.object({
124
+ TABLE_NAME: z.string().min(1),
125
+ AWS_REGION: z.string().default('us-east-1'),
126
+ }),
127
+ );
128
+
129
+ const config = configManager.get();
130
+ // TypeScript infers type from schema
131
+ // Validation errors thrown immediately
132
+ ```
133
+
134
+ **→ See [Configuration Guide](./docs/CONFIGURATION.md) for detailed validation patterns and best practices**
135
+
86
136
  ### Logging
87
137
 
88
138
  The Logger utility provides structured logging configured specifically for AWS Lambda:
package/dist/index.esm.js CHANGED
@@ -1,2 +1,2 @@
1
- import n from"pino";import{lambdaRequestTracker as e,StructuredLogFormatter as t,CloudwatchLogFormatter as o,pinoLambdaDestination as r}from"pino-lambda";import{DynamoDBClient as i}from"@aws-sdk/client-dynamodb";import{DynamoDBDocumentClient as s}from"@aws-sdk/lib-dynamodb";import{z as l}from"zod";const a=e();class c{constructor(e){this._loggerConfig={enabled:!0,level:"info",format:"json"},this._instance=null,this._createLogger=()=>{const e="json"===this._loggerConfig.format?new t:new o,i=r({formatter:e});return n({enabled:this._loggerConfig.enabled,level:this._loggerConfig.level},i)},e&&(this._loggerConfig={enabled:e.enabled??!0,level:e.level??"info",format:e.format??"json"})}get instance(){return null===this._instance&&(this._instance=this._createLogger()),this._instance}}const m={contentType:n=>({"Content-Type":n}),json:{"Content-Type":"application/json"},cors:(n="*")=>({"Access-Control-Allow-Origin":n})},f=(n,e,t={})=>({statusCode:n,headers:{...t},body:JSON.stringify(e)}),g=(n,e={})=>f(200,n,e),d=(n,e={})=>f(201,n,e),u=(n={})=>f(204,{},n),h=(n="Bad Request",e={})=>f(400,{message:n},e),p=(n="Not Found",e={})=>f(404,{message:n},e),C=(n="Internal Server Error",e={})=>f(500,{message:n},e);let w=null,y=null;const _=(n,e,t)=>{w=new i(n||{});const o={marshallOptions:e||{},unmarshallOptions:t||{}};return y=s.from(w,o),{client:w,documentClient:y}},b=()=>{if(!w)throw new Error("DynamoDB client not initialized. Call initializeDynamoDBClients() first.");return w},D=()=>{if(!y)throw new Error("DynamoDB Document client not initialized. Call initializeDynamoDBClients() first.");return y},v=()=>{w=null,y=null},j=n=>{let e=null;const t=()=>{try{return n.parse(process.env)}catch(n){if(n instanceof l.ZodError){const e=n.issues.map(n=>`${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Configuration validation failed:\n${e}`)}throw n}};return{get:()=>(e||(e=t()),e),refresh:()=>(e=t(),e)}};export{c as Logger,h as badRequest,j as createConfigManager,f as createResponse,d as created,b as getDynamoDBClient,D as getDynamoDBDocumentClient,m as httpHeaders,_ as initializeDynamoDBClients,C as internalServerError,u as noContent,p as notFound,g as ok,v as resetDynamoDBClients,a as withRequestTracking};
1
+ import n from"pino";import{lambdaRequestTracker as e,StructuredLogFormatter as t,CloudwatchLogFormatter as o,pinoLambdaDestination as r}from"pino-lambda";import{DynamoDBClient as i}from"@aws-sdk/client-dynamodb";import{DynamoDBDocumentClient as s}from"@aws-sdk/lib-dynamodb";import{z as l}from"zod";const a=e();class c{constructor(e){this._loggerConfig={enabled:!0,level:"info",format:"json"},this._instance=null,this._createLogger=()=>{const e="json"===this._loggerConfig.format?new t:new o,i=r({formatter:e});return n({enabled:this._loggerConfig.enabled,level:this._loggerConfig.level},i)},e&&(this._loggerConfig={enabled:e.enabled??!0,level:e.level??"info",format:e.format??"json"})}get instance(){return null===this._instance&&(this._instance=this._createLogger()),this._instance}}const m={contentType:n=>({"Content-Type":n}),json:{"Content-Type":"application/json"},cors:(n="*")=>({"Access-Control-Allow-Origin":n})},f=(n,e,t={})=>({statusCode:n,headers:{...t},body:JSON.stringify(e)}),g=(n,e={})=>f(200,n,e),d=(n,e={})=>f(201,n,e),u=(n={})=>f(204,{},n),h=(n="Bad Request",e={})=>f(400,{message:n},e),p=(n="Not Found",e={})=>f(404,{message:n},e),C=(n="Internal Server Error",e={})=>f(500,{message:n},e);let w=null,y=null;const _=(n,e,t)=>{w=new i(n||{});const o={marshallOptions:e||{},unmarshallOptions:t||{}};return y=s.from(w,o),{client:w,documentClient:y}},b=()=>{if(!w)throw new Error("DynamoDB client not initialized. Call initializeDynamoDBClients() first.");return w},D=()=>{if(!y)throw new Error("DynamoDB Document client not initialized. Call initializeDynamoDBClients() first.");return y},v=()=>{w=null,y=null},j=n=>{let e=null;const t=()=>{try{return n.parse(process.env)}catch(n){if(n instanceof l.ZodError){const e=n.issues.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ");throw new Error(`Configuration validation failed: ${e}`)}throw n}};return{get:()=>(e||(e=t()),e),refresh:()=>(e=t(),e)}};export{c as Logger,h as badRequest,j as createConfigManager,f as createResponse,d as created,b as getDynamoDBClient,D as getDynamoDBDocumentClient,m as httpHeaders,_ as initializeDynamoDBClients,C as internalServerError,u as noContent,p as notFound,g as ok,v as resetDynamoDBClients,a as withRequestTracking};
2
2
  //# sourceMappingURL=index.esm.js.map
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("pino"),t=require("pino-lambda"),n=require("@aws-sdk/client-dynamodb"),r=require("@aws-sdk/lib-dynamodb"),o=require("zod");const i=t.lambdaRequestTracker();const s=(e,t,n={})=>({statusCode:e,headers:{...n},body:JSON.stringify(t)});let a=null,l=null;exports.Logger=class{constructor(n){this._loggerConfig={enabled:!0,level:"info",format:"json"},this._instance=null,this._createLogger=()=>{const n="json"===this._loggerConfig.format?new t.StructuredLogFormatter:new t.CloudwatchLogFormatter,r=t.pinoLambdaDestination({formatter:n});return e({enabled:this._loggerConfig.enabled,level:this._loggerConfig.level},r)},n&&(this._loggerConfig={enabled:n.enabled??!0,level:n.level??"info",format:n.format??"json"})}get instance(){return null===this._instance&&(this._instance=this._createLogger()),this._instance}},exports.badRequest=(e="Bad Request",t={})=>s(400,{message:e},t),exports.createConfigManager=e=>{let t=null;const n=()=>{try{return e.parse(process.env)}catch(e){if(e instanceof o.z.ZodError){const t=e.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join("\n");throw new Error(`Configuration validation failed:\n${t}`)}throw e}};return{get:()=>(t||(t=n()),t),refresh:()=>(t=n(),t)}},exports.createResponse=s,exports.created=(e,t={})=>s(201,e,t),exports.getDynamoDBClient=()=>{if(!a)throw new Error("DynamoDB client not initialized. Call initializeDynamoDBClients() first.");return a},exports.getDynamoDBDocumentClient=()=>{if(!l)throw new Error("DynamoDB Document client not initialized. Call initializeDynamoDBClients() first.");return l},exports.httpHeaders={contentType:e=>({"Content-Type":e}),json:{"Content-Type":"application/json"},cors:(e="*")=>({"Access-Control-Allow-Origin":e})},exports.initializeDynamoDBClients=(e,t,o)=>{a=new n.DynamoDBClient(e||{});const i={marshallOptions:t||{},unmarshallOptions:o||{}};return l=r.DynamoDBDocumentClient.from(a,i),{client:a,documentClient:l}},exports.internalServerError=(e="Internal Server Error",t={})=>s(500,{message:e},t),exports.noContent=(e={})=>s(204,{},e),exports.notFound=(e="Not Found",t={})=>s(404,{message:e},t),exports.ok=(e,t={})=>s(200,e,t),exports.resetDynamoDBClients=()=>{a=null,l=null},exports.withRequestTracking=i;
1
+ "use strict";var e=require("pino"),t=require("pino-lambda"),n=require("@aws-sdk/client-dynamodb"),r=require("@aws-sdk/lib-dynamodb"),o=require("zod");const i=t.lambdaRequestTracker();const s=(e,t,n={})=>({statusCode:e,headers:{...n},body:JSON.stringify(t)});let a=null,l=null;exports.Logger=class{constructor(n){this._loggerConfig={enabled:!0,level:"info",format:"json"},this._instance=null,this._createLogger=()=>{const n="json"===this._loggerConfig.format?new t.StructuredLogFormatter:new t.CloudwatchLogFormatter,r=t.pinoLambdaDestination({formatter:n});return e({enabled:this._loggerConfig.enabled,level:this._loggerConfig.level},r)},n&&(this._loggerConfig={enabled:n.enabled??!0,level:n.level??"info",format:n.format??"json"})}get instance(){return null===this._instance&&(this._instance=this._createLogger()),this._instance}},exports.badRequest=(e="Bad Request",t={})=>s(400,{message:e},t),exports.createConfigManager=e=>{let t=null;const n=()=>{try{return e.parse(process.env)}catch(e){if(e instanceof o.z.ZodError){const t=e.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ");throw new Error(`Configuration validation failed: ${t}`)}throw e}};return{get:()=>(t||(t=n()),t),refresh:()=>(t=n(),t)}},exports.createResponse=s,exports.created=(e,t={})=>s(201,e,t),exports.getDynamoDBClient=()=>{if(!a)throw new Error("DynamoDB client not initialized. Call initializeDynamoDBClients() first.");return a},exports.getDynamoDBDocumentClient=()=>{if(!l)throw new Error("DynamoDB Document client not initialized. Call initializeDynamoDBClients() first.");return l},exports.httpHeaders={contentType:e=>({"Content-Type":e}),json:{"Content-Type":"application/json"},cors:(e="*")=>({"Access-Control-Allow-Origin":e})},exports.initializeDynamoDBClients=(e,t,o)=>{a=new n.DynamoDBClient(e||{});const i={marshallOptions:t||{},unmarshallOptions:o||{}};return l=r.DynamoDBDocumentClient.from(a,i),{client:a,documentClient:l}},exports.internalServerError=(e="Internal Server Error",t={})=>s(500,{message:e},t),exports.noContent=(e={})=>s(204,{},e),exports.notFound=(e="Not Found",t={})=>s(404,{message:e},t),exports.ok=(e,t={})=>s(200,e,t),exports.resetDynamoDBClients=()=>{a=null,l=null},exports.withRequestTracking=i;
2
2
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,348 @@
1
+ # Configuration Guide
2
+
3
+ This guide explains how to use the `createConfigManager` utility to validate and manage environment variables in your Lambda functions with full TypeScript type safety.
4
+
5
+ ## Overview
6
+
7
+ The configuration utility provides:
8
+
9
+ - **Schema-based validation** using Zod for environment variables
10
+ - **Type-safe access** to your configuration with full TypeScript support
11
+ - **Caching** of validated configuration for performance
12
+ - **Flexible defaults** for optional environment variables
13
+ - **Clear error messages** when validation fails
14
+
15
+ ## Quick Start
16
+
17
+ ### Define Your Schema
18
+
19
+ Create a Zod schema that describes your environment variables:
20
+
21
+ ```typescript
22
+ import { z } from 'zod';
23
+
24
+ const configSchema = z.object({
25
+ // Required variables
26
+ TABLE_NAME: z.string().min(1, 'TABLE_NAME is required'),
27
+
28
+ // Optional with defaults
29
+ AWS_REGION: z.string().default('us-east-1'),
30
+ DEBUG_MODE: z
31
+ .enum(['true', 'false'])
32
+ .default('false')
33
+ .transform((val) => val === 'true'),
34
+ });
35
+
36
+ // Infer the TypeScript type from your schema
37
+ type Config = z.infer<typeof configSchema>;
38
+ ```
39
+
40
+ ### Create and Use ConfigManager
41
+
42
+ ```typescript
43
+ import { createConfigManager } from '@leanstacks/lambda-utils';
44
+
45
+ // Create the manager
46
+ const configManager = createConfigManager(configSchema);
47
+
48
+ // Get validated config (cached after first call)
49
+ const config = configManager.get();
50
+
51
+ // Use your configuration
52
+ console.log(config.TABLE_NAME); // Type-safe access
53
+ console.log(config.AWS_REGION); // Automatically defaults to 'us-east-1'
54
+ console.log(config.DEBUG_MODE); // Typed as boolean
55
+ ```
56
+
57
+ ## Complete Example
58
+
59
+ Here's a realistic Lambda function configuration:
60
+
61
+ ```typescript
62
+ import { z } from 'zod';
63
+ import { createConfigManager } from '@leanstacks/lambda-utils';
64
+
65
+ /**
66
+ * Schema for validating environment variables
67
+ */
68
+ const envSchema = z.object({
69
+ // Required variables
70
+ TASKS_TABLE: z.string().min(1, 'TASKS_TABLE environment variable is required'),
71
+
72
+ // Optional variables with defaults
73
+ AWS_REGION: z.string().default('us-east-1'),
74
+
75
+ // Logging configuration
76
+ LOGGING_ENABLED: z
77
+ .enum(['true', 'false'] as const)
78
+ .default('true')
79
+ .transform((val) => val === 'true'),
80
+ LOGGING_LEVEL: z.enum(['debug', 'info', 'warn', 'error'] as const).default('debug'),
81
+ LOGGING_FORMAT: z.enum(['text', 'json'] as const).default('json'),
82
+
83
+ // CORS configuration
84
+ CORS_ALLOW_ORIGIN: z.string().default('*'),
85
+ });
86
+
87
+ /**
88
+ * Type representing our validated config
89
+ */
90
+ export type Config = z.infer<typeof envSchema>;
91
+
92
+ /**
93
+ * Configuration manager instance
94
+ */
95
+ const configManager = createConfigManager(envSchema);
96
+
97
+ /**
98
+ * Validated configuration object. Singleton.
99
+ */
100
+ export const config = configManager.get();
101
+
102
+ /**
103
+ * Refresh configuration (useful in tests)
104
+ */
105
+ export const refreshConfig = () => configManager.refresh();
106
+ ```
107
+
108
+ Then use it in your handler:
109
+
110
+ ```typescript
111
+ import { config } from './config';
112
+ import { Logger } from '@leanstacks/lambda-utils';
113
+
114
+ const logger = new Logger({
115
+ level: config.LOGGING_LEVEL,
116
+ format: config.LOGGING_FORMAT,
117
+ }).instance;
118
+
119
+ export const handler = async (event: any) => {
120
+ logger.info({
121
+ message: 'Processing request',
122
+ table: config.TASKS_TABLE,
123
+ region: config.AWS_REGION,
124
+ });
125
+
126
+ // Your handler logic here
127
+ };
128
+ ```
129
+
130
+ ## API Reference
131
+
132
+ ### `createConfigManager<T>(schema: T): ConfigManager<z.infer<T>>`
133
+
134
+ Creates a configuration manager instance.
135
+
136
+ **Parameters:**
137
+
138
+ - `schema` - A Zod schema defining your environment variables
139
+
140
+ **Returns:** A `ConfigManager` instance with two methods
141
+
142
+ ### `ConfigManager.get(): T`
143
+
144
+ Gets the validated configuration (cached after the first call).
145
+
146
+ **Throws:** `Error` if validation fails
147
+
148
+ **Returns:** The validated configuration object
149
+
150
+ ```typescript
151
+ const config = configManager.get();
152
+ // First call: validates and caches
153
+ // Subsequent calls: returns cached value
154
+ ```
155
+
156
+ ### `ConfigManager.refresh(): T`
157
+
158
+ Refreshes the configuration by re-validating environment variables against the schema.
159
+
160
+ **Throws:** `Error` if validation fails
161
+
162
+ **Returns:** The newly validated configuration object
163
+
164
+ Use this in tests when you need to change environment variables:
165
+
166
+ ```typescript
167
+ beforeEach(() => {
168
+ process.env.TABLE_NAME = 'test-table';
169
+ configManager.refresh(); // Re-validate with new values
170
+ });
171
+ ```
172
+
173
+ ## Best Practices
174
+
175
+ ### 1. Separate Configuration Module
176
+
177
+ Create a dedicated configuration module for your Lambda function:
178
+
179
+ ```typescript
180
+ // src/config.ts
181
+ import { z } from 'zod';
182
+ import { createConfigManager } from '@leanstacks/lambda-utils';
183
+
184
+ const schema = z.object({
185
+ TABLE_NAME: z.string().min(1),
186
+ AWS_REGION: z.string().default('us-east-1'),
187
+ });
188
+
189
+ export type Config = z.infer<typeof schema>;
190
+
191
+ const configManager = createConfigManager(schema);
192
+
193
+ export const config = configManager.get();
194
+ export const refresh = () => configManager.refresh();
195
+ ```
196
+
197
+ ### 2. Validate Early
198
+
199
+ Call `config.get()` during handler initialization to validate configuration before processing requests:
200
+
201
+ ```typescript
202
+ export const handler = async (event: any, context: any) => {
203
+ // Validation happens here, fails fast if config is invalid
204
+ const config = configManager.get();
205
+
206
+ // Handler logic with validated config
207
+ };
208
+ ```
209
+
210
+ ### 3. Use Enums for Known Values
211
+
212
+ Use `z.enum()` for configuration options with limited valid values:
213
+
214
+ ```typescript
215
+ const schema = z.object({
216
+ LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
217
+ ENVIRONMENT: z.enum(['dev', 'staging', 'prod']),
218
+ });
219
+
220
+ // TypeScript autocomplete for config.LOG_LEVEL
221
+ ```
222
+
223
+ ### 4. Transform String to Boolean
224
+
225
+ Since environment variables are always strings, use `transform()` to convert them:
226
+
227
+ ```typescript
228
+ const schema = z.object({
229
+ ENABLE_FEATURE: z
230
+ .enum(['true', 'false'])
231
+ .default('false')
232
+ .transform((val) => val === 'true'),
233
+ });
234
+
235
+ // config.ENABLE_FEATURE is now a boolean
236
+ if (config.ENABLE_FEATURE) {
237
+ // Feature is enabled
238
+ }
239
+ ```
240
+
241
+ ### 5. Provide Helpful Error Messages
242
+
243
+ Use Zod's second parameter to provide context-specific error messages:
244
+
245
+ ```typescript
246
+ const schema = z.object({
247
+ DATABASE_URL: z.string().url('DATABASE_URL must be a valid URL'),
248
+ API_KEY: z.string().min(32, 'API_KEY must be at least 32 characters'),
249
+ });
250
+ ```
251
+
252
+ ### 6. Test Configuration Validation
253
+
254
+ Test that your schema properly validates configuration:
255
+
256
+ ```typescript
257
+ import { config, refresh } from './config';
258
+
259
+ describe('Configuration', () => {
260
+ it('should load default values', () => {
261
+ delete process.env.AWS_REGION;
262
+ refresh();
263
+ expect(config.AWS_REGION).toBe('us-east-1');
264
+ });
265
+
266
+ it('should validate required variables', () => {
267
+ delete process.env.TABLE_NAME;
268
+ expect(() => refresh()).toThrow();
269
+ });
270
+
271
+ it('should parse boolean values', () => {
272
+ process.env.DEBUG_MODE = 'true';
273
+ refresh();
274
+ expect(config.DEBUG_MODE).toBe(true);
275
+ });
276
+ });
277
+ ```
278
+
279
+ ## Common Patterns
280
+
281
+ ### Database Configuration
282
+
283
+ ```typescript
284
+ const schema = z.object({
285
+ DATABASE_URL: z.string().url(),
286
+ DATABASE_POOL_SIZE: z
287
+ .string()
288
+ .default('10')
289
+ .transform((val) => parseInt(val, 10)),
290
+ DATABASE_TIMEOUT: z
291
+ .string()
292
+ .default('5000')
293
+ .transform((val) => parseInt(val, 10)),
294
+ });
295
+ ```
296
+
297
+ ### Feature Flags
298
+
299
+ ```typescript
300
+ const schema = z.object({
301
+ FEATURE_NEW_UI: z
302
+ .enum(['true', 'false'])
303
+ .default('false')
304
+ .transform((val) => val === 'true'),
305
+ FEATURE_BETA_API: z
306
+ .enum(['true', 'false'])
307
+ .default('false')
308
+ .transform((val) => val === 'true'),
309
+ });
310
+ ```
311
+
312
+ ### Multi-Environment Setup
313
+
314
+ ```typescript
315
+ const schema = z.object({
316
+ ENVIRONMENT: z.enum(['development', 'staging', 'production']),
317
+ LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
318
+ DEBUG_MODE: z
319
+ .enum(['true', 'false'])
320
+ .refine(
321
+ (val) => (val === 'true' ? process.env.ENVIRONMENT === 'development' : true),
322
+ 'DEBUG_MODE can only be true in development',
323
+ )
324
+ .transform((val) => val === 'true'),
325
+ });
326
+ ```
327
+
328
+ ## Error Handling
329
+
330
+ Configuration validation errors include detailed information about what failed:
331
+
332
+ ```typescript
333
+ try {
334
+ const config = configManager.get();
335
+ } catch (error) {
336
+ if (error instanceof Error) {
337
+ console.error(error.message);
338
+ // Output: "Configuration validation failed: TABLE_NAME: String must contain at least 1 character"
339
+ }
340
+ }
341
+ ```
342
+
343
+ Lambda will automatically fail fast if configuration is invalid, which is the desired behavior for Lambda functions.
344
+
345
+ ## Related Documentation
346
+
347
+ - **[Zod Documentation](https://zod.dev/)** – Learn more about schema validation with Zod
348
+ - **[Back to the project documentation](README.md)**
package/docs/README.md CHANGED
@@ -8,11 +8,10 @@ Lambda Utilities is a collection of pre-configured tools and helpers designed to
8
8
 
9
9
  ## Documentation
10
10
 
11
+ - **[Configuration Guide](./CONFIGURATION.md)** – Validate environment variables with Zod schemas and type-safe configuration management
11
12
  - **[Logging Guide](./LOGGING.md)** – Implement structured logging in your Lambda functions with Pino and automatic AWS context enrichment
12
13
  - **[API Gateway Responses](./API_GATEWAY_RESPONSES.md)** – Format Lambda responses for API Gateway with standard HTTP status codes and headers
13
14
  - **[DynamoDB Client](./DYNAMODB_CLIENT.md)** – Reusable singleton DynamoDB client instances with custom configuration
14
- - **[Configuration](./CONFIGURATION.md)** – Validate environment variables and configuration with Zod type safety
15
- - **[Getting Started](./GETTING_STARTED.md)** – Quick setup and installation instructions
16
15
 
17
16
  ## Features
18
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanstacks/lambda-utils",
3
- "version": "0.3.0-alpha.4",
3
+ "version": "0.3.0",
4
4
  "description": "A collection of utilities and helper functions designed to streamline the development of AWS Lambda functions using TypeScript.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -55,7 +55,7 @@
55
55
  "jest": "30.2.0",
56
56
  "prettier": "3.7.4",
57
57
  "rimraf": "6.1.2",
58
- "rollup": "4.53.5",
58
+ "rollup": "4.54.0",
59
59
  "rollup-plugin-peer-deps-external": "2.2.4",
60
60
  "rollup-plugin-typescript2": "0.36.0",
61
61
  "ts-jest": "29.4.6",
@@ -63,8 +63,8 @@
63
63
  "typescript": "5.9.3"
64
64
  },
65
65
  "dependencies": {
66
- "@aws-sdk/client-dynamodb": "3.955.0",
67
- "@aws-sdk/lib-dynamodb": "3.955.0",
66
+ "@aws-sdk/client-dynamodb": "3.956.0",
67
+ "@aws-sdk/lib-dynamodb": "3.956.0",
68
68
  "pino": "10.1.0",
69
69
  "pino-lambda": "4.4.1",
70
70
  "zod": "4.2.1"