lambder 1.0.65 → 1.0.67

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
@@ -1,58 +1,135 @@
1
1
  # Lambder
2
2
 
3
- Lambder provides a simplified way to handle AWS Lambda functions with HTTP triggers, offering a clear structure for managing API endpoints, static file serving, hooks, and error handling.
3
+ Lambder is a dynamic serverless framework designed to facilitate the management and implementation of routes and APIs within AWS Lambda functions, specifically tailored for TypeScript projects. It provides a streamlined approach to handling HTTP requests, managing sessions, and defining API routes, making serverless application development more intuitive and structured.
4
4
 
5
5
  ## Features
6
6
 
7
- - Easy setup of API paths with conditions and actions.
8
- - Support for hooks at different stages of the request lifecycle.
9
- - Integrated cookie and query string parsing.
10
- - Customizable error handling and fallback mechanisms.
11
- - CORS support and easy configuration for public paths.
12
- - Response helpers for JSON, HTML, XML, files, and more.
7
+ - **Simple API & Route Declaration**: Define your APIs and routes using concise and expressive syntax.
8
+ - **Session Management**: Built-in session management to secure and personalize user experiences.
9
+ - **Flexible Hooks System**: Employ hooks to execute code at different stages of the request lifecycle, enabling fine-grained control over the application flow.
10
+ - **Error Handling**: Comprehensive error handling capabilities, including global error handlers and route-specific fallbacks.
11
+ - **Seamless Integration**: Designed to work effortlessly with AWS Lambda and API Gateway, providing a straightforward path to deploy serverless applications.
13
12
 
14
13
  ## Installation
15
14
 
15
+ To include Lambder in your TypeScript project, you can install it using npm or yarn. First, ensure that you have TypeScript set up in your project.
16
+
16
17
  ```bash
17
18
  npm install lambder
19
+ # or
20
+ yarn add lambder
18
21
  ```
19
22
 
20
- ## Quick Start
23
+ ## Backend Usage
24
+
25
+ ### Basic Setup
21
26
 
22
27
  ```typescript
23
28
  import Lambder from 'lambder';
24
- import { APIGatewayProxyEvent, Context } from 'aws-lambda';
29
+ import * as path from 'path';
25
30
 
26
- const app = new Lambder({
27
- apiPath: '/api',
28
- publicPath: '/public',
31
+ const lambder = new Lambder({
32
+ apiPath: "/secure",
29
33
  isCorsEnabled: true,
34
+ publicPath: path.resolve(`./public`),
35
+ });
36
+
37
+ // Define a simple api
38
+ lambder.addApi("fetchData", async (ctx, res) => {
39
+ const data = await fetchDataSomehow();
40
+ return res.api({ payload: data });
41
+ });
42
+
43
+ // Define a simple route
44
+ lambder.addRoute("/hello-world", (ctx, res) => {
45
+ return res.json({ message: "Hello World" });
46
+ });
47
+
48
+ // Match all other paths and serve static files from publicPath, if not found, serve index.html
49
+ lambder.addRoute("*", (ctx, res)=>{
50
+ return res.file(ctx.path, {}, "index.html");
51
+ });
52
+
53
+
54
+ // Set a fallback handler for unmatched routes
55
+ lambder.setRouteFallbackHandler((ctx, res) => {
56
+ return res.status404("Not Found");
30
57
  });
31
58
 
32
- // Define a simple API endpoint
33
- app.addApi('/hello', async (ctx) => {
34
- return ctx.resolver.json({ message: 'Hello, World!' });
59
+ // Global error handler
60
+ lambder.setGlobalErrorHandler((err, ctx, res) => {
61
+ console.error("Error:", err);
62
+ return res.status500("Internal Server Error");
63
+ });
64
+
65
+ export const handler = (event, context) => {
66
+ return lambder.render(event, context);
67
+ };
68
+ ```
69
+
70
+ ### Adding Hooks
71
+
72
+ ```typescript
73
+ // Before render hook example
74
+ lambder.addHook("beforeRender", async (ctx, res) => {
75
+ // Perform actions before rendering
76
+ if(ctx.method === "POST") {
77
+ // Validate CSRF token, for example
78
+ }
79
+ return ctx; // Return modified context or throw an Error
35
80
  });
81
+ ```
82
+
83
+ ## Frontend Usage with LambderCaller
84
+
85
+ LambderCaller is a frontend companion library for Lambder, designed to simplify making API requests to your Lambder backend services.
36
86
 
37
- // Handle 404 Not Found
38
- app.setGlobalErrorHandler((err: Error) => {
39
- return { statusCode: 404, body: 'Not Found' };
87
+ ### Installing LambderCaller
88
+
89
+ LambderCaller is included in the same `lambder` package. Ensure you have `lambder` available in your frontend project.
90
+
91
+ ### Basic Setup
92
+
93
+ Begin by initializing LambderCaller with your API configuration. This setup assumes your project structure accommodates a place for initiating and configuring API handlers, possibly within a dedicated JavaScript module or directly in your main application file.
94
+
95
+ ```javascript
96
+ import LambderCaller from "lambder/dist/LambderCaller";
97
+
98
+ const lambderCaller = new LambderCaller({
99
+ isCorsEnabled: false,
100
+ apiPath: "/secure", // Your Lambder API endpoint, must be the same as in your backend
101
+ fetchStartedHandler: ({ activeFetchList }) => {
102
+ // When any api call starts
103
+ },
104
+ fetchEndedHandler: ({ activeFetchList }) => {
105
+ // When any api call ends
106
+ },
107
+ errorMessageHandler: (message) => {
108
+ console.error("LambderCaller:", message); // Handle error messages
109
+ },
40
110
  });
41
111
 
42
- // Lambda handler
43
- exports.handler = async (event: APIGatewayProxyEvent, context: Context) => {
44
- return app.render(event, context);
112
+
113
+ const loadPageData = async () => {
114
+ try {
115
+ const response = await lambderCaller.api("getCompanyPage", {
116
+ subdomain: "example", // Pass necessary parameters for your API call
117
+ });
118
+ } catch (error) {
119
+ console.error("Failed to fetch page data:", error);
120
+ }
45
121
  };
122
+
46
123
  ```
47
124
 
48
- ## Documentation
125
+ ## Advanced Configuration
49
126
 
50
- For more details on how to use Lambder, including the full API reference, visit [Lambder Documentation](#).
127
+ Lambder is designed to be flexible and extensible, allowing for customized behaviors through hooks and custom error handling mechanisms.
51
128
 
52
129
  ## Contributing
53
130
 
54
- Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
131
+ Contributions are welcome! Especially for documentation. If you have an idea for an improvement or have found a bug, please open an issue or submit a pull request.
55
132
 
56
133
  ## License
57
134
 
58
- MIT License
135
+ This project is licensed under the [MIT License](LICENSE).
package/dist/Lambder.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from
2
2
  import LambderResolver from "./LambderResolver.js";
3
3
  import LambderResponseBuilder, { LambderResolverResponse } from "./LambderResponseBuilder.js";
4
4
  type Path = `/${string}`;
5
- type Session = {
5
+ type LambderSession = {
6
6
  userId: string;
7
7
  userIdHash: string;
8
8
  sessionHash: string;
@@ -11,7 +11,7 @@ type Session = {
11
11
  expiresTimeStamp: number;
12
12
  data: Record<string, any>;
13
13
  };
14
- type RenderContext = {
14
+ type LambderRenderContext = {
15
15
  host: string;
16
16
  path: string;
17
17
  pathParams: Record<string, any> | null;
@@ -21,19 +21,19 @@ type RenderContext = {
21
21
  cookie: Record<string, any>;
22
22
  apiName: string;
23
23
  headers: APIGatewayProxyEventHeaders;
24
- session: Session | null;
24
+ session: LambderSession | null;
25
25
  lambdaContext: Context;
26
26
  };
27
- type ConditionFunction = (ctx: RenderContext) => boolean;
28
- type ActionFunction = (ctx: RenderContext, resolver: LambderResolver) => LambderResolverResponse | Promise<LambderResolverResponse>;
27
+ type ConditionFunction = (ctx: LambderRenderContext) => boolean;
28
+ type ActionFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse | Promise<LambderResolverResponse>;
29
29
  type HookCreatedFunction = (lambderInstance: Lambder) => Promise<void>;
30
- type HookBeforeRenderFunction = (ctx: RenderContext, resolver: LambderResolver) => RenderContext | Error | Promise<RenderContext | Error>;
31
- type HookAfterRenderFunction = (ctx: RenderContext, resolver: LambderResolver, response: LambderResolverResponse) => LambderResolverResponse | Error | Promise<LambderResolverResponse | Error>;
32
- type HookFallbackFunction = (ctx: RenderContext, resolver: LambderResolver) => void | Promise<void>;
33
- type GlobalErrorHandlerFunction = (err: Error, ctx: RenderContext | null, response: LambderResponseBuilder) => LambderResolverResponse | Promise<LambderResolverResponse>;
34
- type RouteFallbackHandlerFunction = (ctx: RenderContext, resolver: LambderResolver) => LambderResolverResponse;
35
- type ApiFallbackHandlerFunction = (ctx: RenderContext, resolver: LambderResolver) => LambderResolverResponse;
36
- export declare const createContext: (event: APIGatewayProxyEvent, lambdaContext: Context, apiPath?: string | null) => RenderContext;
30
+ type HookBeforeRenderFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderRenderContext | Error | Promise<LambderRenderContext | Error>;
31
+ type HookAfterRenderFunction = (ctx: LambderRenderContext, resolver: LambderResolver, response: LambderResolverResponse) => LambderResolverResponse | Error | Promise<LambderResolverResponse | Error>;
32
+ type HookFallbackFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => void | Promise<void>;
33
+ type GlobalErrorHandlerFunction = (err: Error, ctx: LambderRenderContext | null, response: LambderResponseBuilder) => LambderResolverResponse | Promise<LambderResolverResponse>;
34
+ type RouteFallbackHandlerFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse;
35
+ type ApiFallbackHandlerFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse;
36
+ export declare const createContext: (event: APIGatewayProxyEvent, lambdaContext: Context, apiPath?: string | null) => LambderRenderContext;
37
37
  export default class Lambder {
38
38
  private apiPath;
39
39
  private apiVersion;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambder",
3
- "version": "1.0.65",
3
+ "version": "1.0.67",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/Lambder.ts CHANGED
@@ -8,7 +8,7 @@ import LambderResponseBuilder, { LambderResolverResponse } from "./LambderRespon
8
8
 
9
9
  type Path = `/${string}`;
10
10
 
11
- type Session = {
11
+ type LambderSession = {
12
12
  userId: string,
13
13
  userIdHash: string;
14
14
  sessionHash: string;
@@ -18,7 +18,7 @@ type Session = {
18
18
  data: Record<string, any>;
19
19
  };
20
20
 
21
- type RenderContext = {
21
+ type LambderRenderContext = {
22
22
  host: string;
23
23
  path: string;
24
24
  pathParams: Record<string, any> | null;
@@ -28,30 +28,30 @@ type RenderContext = {
28
28
  cookie: Record<string, any>;
29
29
  apiName: string;
30
30
  headers: APIGatewayProxyEventHeaders;
31
- session: Session|null;
31
+ session: LambderSession|null;
32
32
  lambdaContext: Context;
33
33
  };
34
34
 
35
- type ConditionFunction = (ctx: RenderContext) => boolean;
36
- type ActionFunction = (ctx: RenderContext, resolver: LambderResolver) => LambderResolverResponse|Promise<LambderResolverResponse>;
35
+ type ConditionFunction = (ctx: LambderRenderContext) => boolean;
36
+ type ActionFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse|Promise<LambderResolverResponse>;
37
37
  type ActionObject = { conditionFn: ConditionFunction, actionFn: ActionFunction };
38
38
 
39
+ type HookEventType = "created"|"beforeRender"|"afterRender"|"fallback";
39
40
  type HookCreatedFunction = (lambderInstance: Lambder) => Promise<void>;
40
- type HookBeforeRenderFunction = (ctx: RenderContext, resolver: LambderResolver) => RenderContext|Error|Promise<RenderContext|Error>;
41
- type HookAfterRenderFunction = (ctx: RenderContext, resolver: LambderResolver, response: LambderResolverResponse) => LambderResolverResponse|Error|Promise<LambderResolverResponse|Error>;
42
- type HookFallbackFunction = (ctx: RenderContext, resolver: LambderResolver) => void|Promise<void>;
41
+ type HookBeforeRenderFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderRenderContext|Error|Promise<LambderRenderContext|Error>;
42
+ type HookAfterRenderFunction = (ctx: LambderRenderContext, resolver: LambderResolver, response: LambderResolverResponse) => LambderResolverResponse|Error|Promise<LambderResolverResponse|Error>;
43
+ type HookFallbackFunction = (ctx: LambderRenderContext, resolver: LambderResolver) => void|Promise<void>;
43
44
 
44
- type GlobalErrorHandlerFunction = (err: Error, ctx: RenderContext|null, response: LambderResponseBuilder) => LambderResolverResponse|Promise<LambderResolverResponse>;
45
- type RouteFallbackHandlerFunction = (ctx:RenderContext, resolver: LambderResolver) => LambderResolverResponse;
46
- type ApiFallbackHandlerFunction = (ctx:RenderContext, resolver: LambderResolver) => LambderResolverResponse;
45
+ type GlobalErrorHandlerFunction = (err: Error, ctx: LambderRenderContext|null, response: LambderResponseBuilder) => LambderResolverResponse|Promise<LambderResolverResponse>;
46
+ type RouteFallbackHandlerFunction = (ctx:LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse;
47
+ type ApiFallbackHandlerFunction = (ctx:LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse;
47
48
 
48
- type HookEventType = "created"|"beforeRender"|"afterRender"|"fallback";
49
49
 
50
50
  export const createContext = (
51
51
  event: APIGatewayProxyEvent,
52
52
  lambdaContext: Context,
53
53
  apiPath: string|null = null
54
- ):RenderContext => {
54
+ ):LambderRenderContext => {
55
55
  const host = event.headers.Host || event.headers.host || "";
56
56
  const path = event.path;
57
57
  const pathParams = null;
@@ -123,7 +123,7 @@ export default class Lambder {
123
123
  return (match(pattern, { decode: decodeURIComponent }))(path) !== false;
124
124
  }
125
125
 
126
- private async validateSession (ctx: RenderContext): Promise<boolean>{
126
+ private async validateSession (ctx: LambderRenderContext): Promise<boolean>{
127
127
  const { session, apiName, post, cookie } = ctx;
128
128
  if(!session) return false;
129
129
  if(!session.userId || !session.userIdHash || !session.sessionHash || !session.csrfToken) return false;
@@ -139,7 +139,7 @@ export default class Lambder {
139
139
  return false;
140
140
  };
141
141
 
142
- private async handleNoMatchedAction(ctx: RenderContext, resolver: LambderResolver){
142
+ private async handleNoMatchedAction(ctx: LambderRenderContext, resolver: LambderResolver){
143
143
  for(const hook of this.hookList["fallback"]){ await hook.hookFn(ctx, resolver); }
144
144
 
145
145
  const isAPI = ctx.path === this.apiPath;
@@ -159,7 +159,7 @@ export default class Lambder {
159
159
  }
160
160
  addRoute(condition: Path|ConditionFunction|RegExp, actionFn: ActionFunction):void{
161
161
  this.actionList.push({
162
- conditionFn: (ctx:RenderContext) => (
162
+ conditionFn: (ctx:LambderRenderContext) => (
163
163
  ctx.method === "GET" &&
164
164
  (
165
165
  (typeof condition === "string" && this.testPatternMatch(condition, ctx.path)) ||
@@ -167,7 +167,7 @@ export default class Lambder {
167
167
  (condition?.constructor == RegExp && condition.test(ctx.path))
168
168
  )
169
169
  ),
170
- actionFn: async (ctx:RenderContext, resolver: LambderResolver) => {
170
+ actionFn: async (ctx:LambderRenderContext, resolver: LambderResolver) => {
171
171
  if(typeof condition === "string"){
172
172
  ctx.pathParams = this.getPatternMatch(condition, ctx.path);
173
173
  }else if(condition?.constructor == RegExp){
@@ -181,7 +181,7 @@ export default class Lambder {
181
181
 
182
182
  addSessionRoute(condition: Path|ConditionFunction|RegExp, actionFn: ActionFunction):void{
183
183
  this.actionList.push({
184
- conditionFn: (ctx:RenderContext) => (
184
+ conditionFn: (ctx:LambderRenderContext) => (
185
185
  ctx.method === "GET" &&
186
186
  (
187
187
  (typeof condition === "string" && this.testPatternMatch(condition, ctx.path)) ||
@@ -189,7 +189,7 @@ export default class Lambder {
189
189
  (condition?.constructor == RegExp && condition.test(ctx.path))
190
190
  )
191
191
  ),
192
- actionFn: async (ctx:RenderContext, resolver: LambderResolver) => {
192
+ actionFn: async (ctx:LambderRenderContext, resolver: LambderResolver) => {
193
193
  const isSessionValid = this.validateSession(ctx);
194
194
  if(!isSessionValid) throw new Error("Session not found");
195
195
  if(typeof condition === "string"){
@@ -204,23 +204,23 @@ export default class Lambder {
204
204
 
205
205
  addApi(apiName: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
206
206
  this.actionList.push({
207
- conditionFn: (ctx:RenderContext) => (
207
+ conditionFn: (ctx:LambderRenderContext) => (
208
208
  (typeof apiName === "string" && ctx.apiName === apiName) ||
209
209
  (typeof apiName === "function" && apiName(ctx)) ||
210
210
  (apiName?.constructor == RegExp && apiName.test(ctx.apiName))
211
211
  ),
212
- actionFn: async (ctx:RenderContext, resolver: LambderResolver) => await actionFn(ctx, resolver),
212
+ actionFn: async (ctx:LambderRenderContext, resolver: LambderResolver) => await actionFn(ctx, resolver),
213
213
  });
214
214
  };
215
215
 
216
216
  addSessionApi(apiName: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
217
217
  this.actionList.push({
218
- conditionFn: (ctx:RenderContext) => (
218
+ conditionFn: (ctx:LambderRenderContext) => (
219
219
  (typeof apiName === "string" && ctx.apiName === apiName) ||
220
220
  (typeof apiName === "function" && apiName(ctx)) ||
221
221
  (apiName?.constructor == RegExp && apiName.test(ctx.apiName))
222
222
  ),
223
- actionFn: async (ctx:RenderContext, resolver: LambderResolver) => {
223
+ actionFn: async (ctx:LambderRenderContext, resolver: LambderResolver) => {
224
224
  const isSessionValid = this.validateSession(ctx);
225
225
  if(!isSessionValid) throw new Error("Session not found");
226
226
  return await actionFn(ctx, resolver);
@@ -266,7 +266,7 @@ export default class Lambder {
266
266
  event: APIGatewayProxyEvent,
267
267
  lambdaContext: Context
268
268
  ): Promise<LambderResolverResponse>{
269
- let eventRenderContext:RenderContext|null = null;
269
+ let eventRenderContext:LambderRenderContext|null = null;
270
270
 
271
271
  try {
272
272
  let ctx = createContext(event, lambdaContext);