lambder 1.0.41 → 1.0.44

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/dist/Lambder.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from "aws-lambda";
2
2
  import Resolver from "./Resolver.js";
3
3
  import ResponseBuilder, { ResolverResponse } from "./ResponseBuilder.js";
4
- type DDBSession = {
4
+ type Session = {
5
5
  userId: string;
6
6
  userIdHash: string;
7
7
  sessionHash: string;
@@ -11,10 +11,13 @@ type DDBSession = {
11
11
  data: {
12
12
  [key: string]: any;
13
13
  };
14
- } | null;
14
+ };
15
15
  type RenderContext = {
16
16
  host: string;
17
- url: string;
17
+ path: string;
18
+ pathParams: {
19
+ [key: string]: any;
20
+ } | null;
18
21
  method: string;
19
22
  get: {
20
23
  [key: string]: any;
@@ -26,16 +29,16 @@ type RenderContext = {
26
29
  [key: string]: any;
27
30
  };
28
31
  headers: APIGatewayProxyEventHeaders;
29
- session: DDBSession;
32
+ session: Session | null;
30
33
  lambdaContext: Context;
31
34
  };
32
- type ConditionFunction = (ctx: RenderContext) => boolean | Promise<boolean>;
35
+ type ConditionFunction = (ctx: RenderContext) => boolean;
33
36
  type ActionFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse | Promise<ResolverResponse>;
34
37
  type HookCreatedFunction = (lambderInstance: Lambder) => Promise<void>;
35
38
  type HookBeforeRenderFunction = (ctx: RenderContext, resolver: Resolver) => RenderContext | Promise<RenderContext>;
36
- type HookAfterRenderFunction = (ctx: RenderContext, resolver: Resolver, renderResult: ResolverResponse) => ResolverResponse | Promise<ResolverResponse>;
39
+ type HookAfterRenderFunction = (ctx: RenderContext, resolver: Resolver, response: ResolverResponse) => ResolverResponse | Promise<ResolverResponse>;
37
40
  type HookFallbackFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse | Promise<ResolverResponse>;
38
- type HookCompletedFunction = (renderResult: ResolverResponse) => ResolverResponse | Promise<ResolverResponse>;
41
+ type HookCompletedFunction = (response: ResolverResponse) => ResolverResponse | Promise<ResolverResponse>;
39
42
  type GlobalErrorHandlerFunction = (err: Error, ctx: RenderContext | null, response: ResponseBuilder) => ResolverResponse | Promise<ResolverResponse>;
40
43
  type RouteFallbackHandlerFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse;
41
44
  type ApiFallbackHandlerFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse;
@@ -45,8 +48,8 @@ export default class Lambder {
45
48
  private apiVersion;
46
49
  private isCorsEnabled;
47
50
  private publicPath;
48
- private _actionList;
49
- private _hookList;
51
+ private actionList;
52
+ private hookList;
50
53
  private globalErrorHandler;
51
54
  private routeFallbackHandler;
52
55
  private apiFallbackHandler;
package/dist/Lambder.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import querystring from "querystring";
2
2
  import cookieParser from "cookie";
3
+ import { match } from "path-to-regexp";
3
4
  import Resolver from "./Resolver.js";
4
5
  import ResponseBuilder from "./ResponseBuilder.js";
5
6
  export const createContext = (event, lambdaContext) => {
6
7
  const host = event.headers.Host || event.headers.host || "";
7
- const url = event.path;
8
+ const path = event.path;
9
+ const pathParams = null;
8
10
  const get = event.queryStringParameters || {};
9
11
  const method = event.httpMethod;
10
12
  const cookie = cookieParser.parse(event.headers.Cookie || event.headers.cookie || "");
@@ -24,15 +26,15 @@ export const createContext = (event, lambdaContext) => {
24
26
  if (/^(((\d+\.)+\d+)|(([a-f\d]+:)+[a-f\d]+))$/.test(host)) {
25
27
  throw new Error("[404] Host cannot be an ip address: " + host);
26
28
  }
27
- return { host, url, method, get, post, cookie, headers, session, lambdaContext };
29
+ return { host, path, pathParams, method, get, post, cookie, headers, session, lambdaContext };
28
30
  };
29
31
  export default class Lambder {
30
32
  apiPath;
31
33
  apiVersion;
32
34
  isCorsEnabled;
33
35
  publicPath;
34
- _actionList;
35
- _hookList;
36
+ actionList;
37
+ hookList;
36
38
  globalErrorHandler = null;
37
39
  routeFallbackHandler = null;
38
40
  apiFallbackHandler = null;
@@ -41,8 +43,8 @@ export default class Lambder {
41
43
  this.apiPath = apiPath ?? "/api";
42
44
  this.apiVersion = apiVersion ?? null;
43
45
  this.isCorsEnabled = isCorsEnabled ?? false;
44
- this._actionList = [];
45
- this._hookList = {
46
+ this.actionList = [];
47
+ this.hookList = {
46
48
  "beforeRender": [],
47
49
  "afterRender": [],
48
50
  "fallback": [],
@@ -72,62 +74,80 @@ export default class Lambder {
72
74
  }
73
75
  ;
74
76
  async handleNoMatchedAction(ctx, resolver) {
75
- for (const hook of this._hookList["fallback"]) {
77
+ for (const hook of this.hookList["fallback"]) {
76
78
  await hook.hookFn(ctx, resolver);
77
79
  }
78
- if (ctx.url === this.apiPath) {
79
- if (this.apiFallbackHandler) {
80
- resolver.resolve(await this.apiFallbackHandler(ctx, resolver));
81
- }
82
- else {
83
- resolver.resolve({ statusCode: 204, body: "API handler not set.", });
84
- }
80
+ const isAPI = ctx.path === this.apiPath;
81
+ if (isAPI && this.apiFallbackHandler) {
82
+ resolver.resolve(await this.apiFallbackHandler(ctx, resolver));
83
+ }
84
+ else if (isAPI) {
85
+ resolver.resolve({ statusCode: 204, body: "API handler not set.", });
85
86
  }
86
87
  else if (this.routeFallbackHandler) {
87
88
  resolver.resolve(await this.routeFallbackHandler(ctx, resolver));
88
89
  }
89
90
  else {
90
- resolver.resolve({ statusCode: 204, body: "Handler not set.", });
91
+ resolver.resolve({ statusCode: 204, body: "Route handler not set.", });
91
92
  }
92
93
  }
93
94
  async addModule(moduleFn) {
94
95
  await moduleFn(this);
95
96
  }
96
97
  addRoute(condition, actionFn) {
97
- this._actionList.push({
98
- conditionFn: async (ctx) => (ctx.method === "GET" &&
99
- ((typeof condition === "string" && ctx.url === condition) ||
100
- (typeof condition === "function" && (await condition(ctx))) ||
101
- (condition?.constructor == RegExp && condition.test(ctx.url)))),
102
- actionFn: async (ctx, resolver) => await actionFn(ctx, resolver)
98
+ this.actionList.push({
99
+ conditionFn: (ctx) => (ctx.method === "GET" &&
100
+ ((typeof condition === "string" && ctx.path === condition) ||
101
+ (typeof condition === "function" && condition(ctx)) ||
102
+ (condition?.constructor == RegExp && condition.test(ctx.path)))),
103
+ actionFn: async (ctx, resolver) => {
104
+ if (typeof condition === "string") {
105
+ ctx.pathParams = (match(condition))(ctx.path) || {};
106
+ }
107
+ else if (condition?.constructor == RegExp) {
108
+ ctx.pathParams = ctx.path.match(condition);
109
+ }
110
+ return await actionFn(ctx, resolver);
111
+ }
103
112
  });
104
113
  }
105
114
  ;
106
115
  addSessionRoute(condition, actionFn) {
107
- this._actionList.push({
108
- conditionFn: async (ctx) => (ctx.method === "GET" && !!ctx.session &&
109
- ((typeof condition === "string" && ctx.url === condition) ||
110
- (typeof condition === "function" && (await condition(ctx))) ||
111
- (condition?.constructor == RegExp && condition.test(ctx.url)))),
112
- actionFn: async (ctx, resolver) => await actionFn(ctx, resolver)
116
+ this.actionList.push({
117
+ conditionFn: (ctx) => (ctx.method === "GET" &&
118
+ ((typeof condition === "string" && ctx.path === condition) ||
119
+ (typeof condition === "function" && condition(ctx)) ||
120
+ (condition?.constructor == RegExp && condition.test(ctx.path)))),
121
+ actionFn: async (ctx, resolver) => {
122
+ const isSessionValid = this.validateSession(ctx.session);
123
+ if (!isSessionValid)
124
+ throw new Error("Session not found");
125
+ if (typeof condition === "string") {
126
+ ctx.pathParams = (match(condition))(ctx.path) || {};
127
+ }
128
+ else if (condition?.constructor == RegExp) {
129
+ ctx.pathParams = ctx.path.match(condition);
130
+ }
131
+ return await actionFn(ctx, resolver);
132
+ }
113
133
  });
114
134
  }
115
135
  ;
116
136
  addApi(condition, actionFn) {
117
- this._actionList.push({
118
- conditionFn: async (ctx) => (ctx.method === "POST" && ctx.url === this.apiPath &&
137
+ this.actionList.push({
138
+ conditionFn: (ctx) => (ctx.method === "POST" && ctx.path === this.apiPath &&
119
139
  ((typeof condition === "string" && ctx.post?.api === condition) ||
120
- (typeof condition === "function" && (await condition(ctx))) ||
140
+ (typeof condition === "function" && condition(ctx)) ||
121
141
  (condition?.constructor == RegExp && condition.test(ctx.post?.api)))),
122
- actionFn: async (ctx, resolver) => await actionFn(ctx, resolver)
142
+ actionFn: async (ctx, resolver) => await actionFn(ctx, resolver),
123
143
  });
124
144
  }
125
145
  ;
126
146
  addSessionApi(condition, actionFn) {
127
- this._actionList.push({
128
- conditionFn: async (ctx) => (ctx.method === "POST" && ctx.url === this.apiPath && !!ctx.session &&
147
+ this.actionList.push({
148
+ conditionFn: (ctx) => (ctx.method === "POST" && ctx.path === this.apiPath &&
129
149
  ((typeof condition === "string" && ctx.post?.api === condition) ||
130
- (typeof condition === "function" && (await condition(ctx))) ||
150
+ (typeof condition === "function" && condition(ctx)) ||
131
151
  (condition?.constructor == RegExp && condition.test(ctx.post?.api)))),
132
152
  actionFn: async (ctx, resolver) => {
133
153
  const isSessionValid = this.validateSession(ctx.session);
@@ -143,8 +163,8 @@ export default class Lambder {
143
163
  await hookFn(this);
144
164
  }
145
165
  else {
146
- this._hookList[hookEvent].push({ priority, hookFn });
147
- this._hookList[hookEvent].sort((a, b) => a.priority - b.priority);
166
+ this.hookList[hookEvent].push({ priority, hookFn });
167
+ this.hookList[hookEvent].sort((a, b) => a.priority - b.priority);
148
168
  }
149
169
  }
150
170
  getResponseBuilder() {
@@ -173,36 +193,31 @@ export default class Lambder {
173
193
  const resolver = this.getResolver(resolve, reject);
174
194
  if (ctx.method === "OPTIONS")
175
195
  return resolver.cors();
176
- const firstMatchedAction = await (async () => {
177
- for (const action of this._actionList) {
178
- if (await action.conditionFn(ctx))
179
- return action;
180
- }
181
- })();
196
+ const firstMatchedAction = this.actionList.find(action => action.conditionFn(ctx));
182
197
  if (firstMatchedAction) {
183
- for (const hook of this._hookList["beforeRender"]) {
198
+ for (const hook of this.hookList["beforeRender"]) {
184
199
  ctx = await hook.hookFn(ctx, resolver);
185
200
  }
186
- let renderResult = await firstMatchedAction.actionFn(ctx, resolver);
187
- for (const hook of this._hookList["afterRender"]) {
188
- renderResult = await hook.hookFn(ctx, resolver, renderResult);
201
+ let response = await firstMatchedAction.actionFn(ctx, resolver);
202
+ for (const hook of this.hookList["afterRender"]) {
203
+ response = await hook.hookFn(ctx, resolver, response);
189
204
  }
190
- resolve(renderResult);
205
+ resolve(response);
191
206
  }
192
207
  else {
193
208
  return this.handleNoMatchedAction(ctx, resolver);
194
209
  }
195
- }).then(async (renderResult) => {
196
- for (const hook of this._hookList["completed"]) {
197
- renderResult = await hook.hookFn(renderResult);
210
+ }).then(async (response) => {
211
+ for (const hook of this.hookList["completed"]) {
212
+ response = await hook.hookFn(response);
198
213
  }
199
- return renderResult;
214
+ return response;
200
215
  });
201
216
  }
202
217
  catch (err) {
203
- const responseBuilder = this.getResponseBuilder();
204
- const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
205
218
  if (this.globalErrorHandler) {
219
+ const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
220
+ const responseBuilder = this.getResponseBuilder();
206
221
  return this.globalErrorHandler(wrappedError, eventRenderContext, responseBuilder);
207
222
  }
208
223
  return { statusCode: 500, body: "Internal Server Error.", };
@@ -13,14 +13,14 @@ interface DieResolverMethods {
13
13
  api: MethodType<ResponseBuilder, 'api'>;
14
14
  }
15
15
  export default class Resolver extends ResponseBuilder {
16
- resolve: (renderResult: ResolverResponse) => void;
16
+ resolve: (response: ResolverResponse) => void;
17
17
  reject: (err: Error) => void;
18
18
  die: DieResolverMethods;
19
19
  constructor({ isCorsEnabled, publicPath, apiVersion, resolve, reject }: {
20
20
  isCorsEnabled: boolean;
21
21
  publicPath: string;
22
22
  apiVersion?: string | null;
23
- resolve: (renderResult: ResolverResponse) => void;
23
+ resolve: (response: ResolverResponse) => void;
24
24
  reject: (err: Error) => void;
25
25
  });
26
26
  private autoResolve;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambder",
3
- "version": "1.0.41",
3
+ "version": "1.0.44",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -24,6 +24,7 @@
24
24
  "@types/js-cookie": "^3.0.6",
25
25
  "@types/mime-types": "^2.1.4",
26
26
  "@types/node": "^20.11.27",
27
+ "@types/path-to-regexp": "^1.7.0",
27
28
  "@typescript-eslint/eslint-plugin": "^7.2.0",
28
29
  "@typescript-eslint/parser": "^7.2.0",
29
30
  "eslint": "^8.57.0",
package/src/Lambder.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import querystring from "querystring";
2
2
  import cookieParser from "cookie";
3
+ import { match } from "path-to-regexp";
3
4
 
4
5
  import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from "aws-lambda";
5
6
  import Resolver from "./Resolver.js";
6
7
  import ResponseBuilder, { ResolverResponse } from "./ResponseBuilder.js";
7
8
 
8
- type DDBSession = {
9
+ type Session = {
9
10
  userId: string,
10
11
  userIdHash: string;
11
12
  sessionHash: string;
@@ -13,29 +14,30 @@ type DDBSession = {
13
14
  createdTimeStamp: number;
14
15
  expiresTimeStamp: number;
15
16
  data: { [key:string]: any };
16
- } | null;
17
+ };
17
18
 
18
19
  type RenderContext = {
19
20
  host: string;
20
- url: string;
21
+ path: string;
22
+ pathParams: { [key: string]: any } | null;
21
23
  method: string;
22
24
  get: { [key: string]: any };
23
25
  post: { [key: string]: any };
24
26
  cookie: { [key: string]: any };
25
27
  headers: APIGatewayProxyEventHeaders;
26
- session: DDBSession;
28
+ session: Session|null;
27
29
  lambdaContext: Context;
28
30
  };
29
31
 
30
- type ConditionFunction = (ctx: RenderContext) => boolean|Promise<boolean>;
32
+ type ConditionFunction = (ctx: RenderContext) => boolean;
31
33
  type ActionFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse|Promise<ResolverResponse>;
32
- type ActionType = { conditionFn: ConditionFunction, actionFn: ActionFunction };
34
+ type ActionObject = { conditionFn: ConditionFunction, actionFn: ActionFunction };
33
35
 
34
36
  type HookCreatedFunction = (lambderInstance: Lambder) => Promise<void>;
35
37
  type HookBeforeRenderFunction = (ctx: RenderContext, resolver: Resolver) => RenderContext|Promise<RenderContext>;
36
- type HookAfterRenderFunction = (ctx: RenderContext, resolver: Resolver, renderResult: ResolverResponse) => ResolverResponse|Promise<ResolverResponse>;
38
+ type HookAfterRenderFunction = (ctx: RenderContext, resolver: Resolver, response: ResolverResponse) => ResolverResponse|Promise<ResolverResponse>;
37
39
  type HookFallbackFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse|Promise<ResolverResponse>;
38
- type HookCompletedFunction = (renderResult: ResolverResponse) => ResolverResponse|Promise<ResolverResponse>;
40
+ type HookCompletedFunction = (response: ResolverResponse) => ResolverResponse|Promise<ResolverResponse>;
39
41
 
40
42
  type GlobalErrorHandlerFunction = (err: Error, ctx: RenderContext|null, response: ResponseBuilder) => ResolverResponse|Promise<ResolverResponse>;
41
43
  type RouteFallbackHandlerFunction = (ctx:RenderContext, resolver: Resolver) => ResolverResponse;
@@ -52,7 +54,8 @@ export const createContext = (
52
54
  lambdaContext: Context,
53
55
  ):RenderContext => {
54
56
  const host = event.headers.Host || event.headers.host || "";
55
- const url = event.path;
57
+ const path = event.path;
58
+ const pathParams = null;
56
59
  const get: { [key:string]: any } = event.queryStringParameters || {};
57
60
  const method = event.httpMethod;
58
61
  const cookie = cookieParser.parse(event.headers.Cookie || event.headers.cookie || "");
@@ -65,7 +68,7 @@ export const createContext = (
65
68
  catch(e){ post = querystring.parse(decodedBody) || {}; }
66
69
  }catch(e){}
67
70
  if(/^(((\d+\.)+\d+)|(([a-f\d]+:)+[a-f\d]+))$/.test(host)){ throw new Error("[404] Host cannot be an ip address: " + host); }
68
- return { host, url, method, get, post, cookie, headers, session, lambdaContext };
71
+ return { host, path, pathParams, method, get, post, cookie, headers, session, lambdaContext };
69
72
  }
70
73
 
71
74
 
@@ -75,8 +78,8 @@ export default class Lambder {
75
78
  private isCorsEnabled: boolean;
76
79
  private publicPath: string;
77
80
 
78
- private _actionList: ActionType[];
79
- private _hookList: {
81
+ private actionList: ActionObject[];
82
+ private hookList: {
80
83
  "beforeRender": { priority: number, hookFn: HookBeforeRenderFunction }[],
81
84
  "afterRender": { priority: number, hookFn: HookAfterRenderFunction }[],
82
85
  "fallback": { priority: number, hookFn: HookFallbackFunction }[],
@@ -95,8 +98,8 @@ export default class Lambder {
95
98
  this.apiVersion = apiVersion ?? null;
96
99
  this.isCorsEnabled = isCorsEnabled ?? false;
97
100
 
98
- this._actionList = [];
99
- this._hookList = {
101
+ this.actionList = [];
102
+ this.hookList = {
100
103
  "beforeRender": [],
101
104
  "afterRender": [],
102
105
  "fallback": [],
@@ -114,7 +117,7 @@ export default class Lambder {
114
117
  this.globalErrorHandler = globalErrorHandler;
115
118
  }
116
119
 
117
- private async validateSession (session: DDBSession): Promise<boolean>{
120
+ private async validateSession (session: Session|null): Promise<boolean>{
118
121
  if(!session) return false;
119
122
  if(!session.userId || !session.userIdHash || !session.sessionHash || !session.csrfToken) return false;
120
123
  if(!session.createdTimeStamp || !session.expiresTimeStamp) return false;
@@ -124,19 +127,17 @@ export default class Lambder {
124
127
  };
125
128
 
126
129
  private async handleNoMatchedAction(ctx: RenderContext, resolver: Resolver){
127
- for(const hook of this._hookList["fallback"]){
128
- await hook.hookFn(ctx, resolver);
129
- }
130
- if(ctx.url === this.apiPath){
131
- if(this.apiFallbackHandler){
132
- resolver.resolve(await this.apiFallbackHandler(ctx, resolver));
133
- }else{
134
- resolver.resolve({ statusCode: 204, body: "API handler not set.", })
135
- }
130
+ for(const hook of this.hookList["fallback"]){ await hook.hookFn(ctx, resolver); }
131
+
132
+ const isAPI = ctx.path === this.apiPath;
133
+ if(isAPI && this.apiFallbackHandler){
134
+ resolver.resolve(await this.apiFallbackHandler(ctx, resolver));
135
+ }else if(isAPI){
136
+ resolver.resolve({ statusCode: 204, body: "API handler not set.", })
136
137
  }else if(this.routeFallbackHandler){
137
138
  resolver.resolve(await this.routeFallbackHandler(ctx, resolver));
138
139
  }else{
139
- resolver.resolve({ statusCode: 204, body: "Handler not set.", })
140
+ resolver.resolve({ statusCode: 204, body: "Route handler not set.", })
140
141
  }
141
142
  }
142
143
 
@@ -144,54 +145,70 @@ export default class Lambder {
144
145
  await moduleFn(this);
145
146
  }
146
147
  addRoute(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
147
- this._actionList.push({
148
- conditionFn: async (ctx:RenderContext) => (
148
+ this.actionList.push({
149
+ conditionFn: (ctx:RenderContext) => (
149
150
  ctx.method === "GET" &&
150
151
  (
151
- (typeof condition === "string" && ctx.url === condition) ||
152
- (typeof condition === "function" && (await condition(ctx))) ||
153
- (condition?.constructor == RegExp && condition.test(ctx.url))
152
+ (typeof condition === "string" && ctx.path === condition) ||
153
+ (typeof condition === "function" && condition(ctx)) ||
154
+ (condition?.constructor == RegExp && condition.test(ctx.path))
154
155
  )
155
156
  ),
156
- actionFn: async (ctx:RenderContext, resolver: Resolver) => await actionFn(ctx, resolver)
157
+ actionFn: async (ctx:RenderContext, resolver: Resolver) => {
158
+ if(typeof condition === "string"){
159
+ ctx.pathParams = (match(condition))(ctx.path) || {};
160
+ }else if(condition?.constructor == RegExp){
161
+ ctx.pathParams = ctx.path.match(condition);
162
+ }
163
+ return await actionFn(ctx, resolver);
164
+ }
157
165
  });
158
166
  };
159
167
 
160
168
  addSessionRoute(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
161
- this._actionList.push({
162
- conditionFn: async (ctx:RenderContext) => (
163
- ctx.method === "GET" && !!ctx.session &&
169
+ this.actionList.push({
170
+ conditionFn: (ctx:RenderContext) => (
171
+ ctx.method === "GET" &&
164
172
  (
165
- (typeof condition === "string" && ctx.url === condition) ||
166
- (typeof condition === "function" && (await condition(ctx))) ||
167
- (condition?.constructor == RegExp && condition.test(ctx.url))
173
+ (typeof condition === "string" && ctx.path === condition) ||
174
+ (typeof condition === "function" && condition(ctx)) ||
175
+ (condition?.constructor == RegExp && condition.test(ctx.path))
168
176
  )
169
177
  ),
170
- actionFn: async (ctx:RenderContext, resolver: Resolver) => await actionFn(ctx, resolver)
178
+ actionFn: async (ctx:RenderContext, resolver: Resolver) => {
179
+ const isSessionValid = this.validateSession(ctx.session);
180
+ if(!isSessionValid) throw new Error("Session not found");
181
+ if(typeof condition === "string"){
182
+ ctx.pathParams = (match(condition))(ctx.path) || {};
183
+ }else if(condition?.constructor == RegExp){
184
+ ctx.pathParams = ctx.path.match(condition);
185
+ }
186
+ return await actionFn(ctx, resolver);
187
+ }
171
188
  });
172
189
  };
173
190
 
174
191
  addApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
175
- this._actionList.push({
176
- conditionFn: async (ctx:RenderContext) => (
177
- ctx.method === "POST" && ctx.url === this.apiPath &&
192
+ this.actionList.push({
193
+ conditionFn: (ctx:RenderContext) => (
194
+ ctx.method === "POST" && ctx.path === this.apiPath &&
178
195
  (
179
196
  (typeof condition === "string" && ctx.post?.api === condition) ||
180
- (typeof condition === "function" && (await condition(ctx))) ||
197
+ (typeof condition === "function" && condition(ctx)) ||
181
198
  (condition?.constructor == RegExp && condition.test(ctx.post?.api))
182
199
  )
183
200
  ),
184
- actionFn: async (ctx:RenderContext, resolver: Resolver) => await actionFn(ctx, resolver)
201
+ actionFn: async (ctx:RenderContext, resolver: Resolver) => await actionFn(ctx, resolver),
185
202
  });
186
203
  };
187
204
 
188
205
  addSessionApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
189
- this._actionList.push({
190
- conditionFn: async (ctx:RenderContext) => (
191
- ctx.method === "POST" && ctx.url === this.apiPath && !!ctx.session &&
206
+ this.actionList.push({
207
+ conditionFn: (ctx:RenderContext) => (
208
+ ctx.method === "POST" && ctx.path === this.apiPath &&
192
209
  (
193
210
  (typeof condition === "string" && ctx.post?.api === condition) ||
194
- (typeof condition === "function" && (await condition(ctx))) ||
211
+ (typeof condition === "function" && condition(ctx)) ||
195
212
  (condition?.constructor == RegExp && condition.test(ctx.post?.api))
196
213
  )
197
214
  ),
@@ -217,8 +234,8 @@ export default class Lambder {
217
234
  if(hookEvent === "created"){
218
235
  await hookFn(this);
219
236
  }else{
220
- this._hookList[hookEvent].push({ priority, hookFn });
221
- this._hookList[hookEvent].sort((a, b) => a.priority - b.priority);
237
+ this.hookList[hookEvent].push({ priority, hookFn });
238
+ this.hookList[hookEvent].sort((a, b) => a.priority - b.priority);
222
239
  }
223
240
  }
224
241
 
@@ -230,7 +247,7 @@ export default class Lambder {
230
247
  });
231
248
  };
232
249
 
233
- private getResolver(resolve: (renderResult: ResolverResponse) => void, reject: (err: Error) => void){
250
+ private getResolver(resolve: (response: ResolverResponse) => void, reject: (err: Error) => void){
234
251
  return new Resolver({
235
252
  isCorsEnabled: this.isCorsEnabled,
236
253
  publicPath: this.publicPath,
@@ -250,40 +267,29 @@ export default class Lambder {
250
267
  eventRenderContext = ctx;
251
268
 
252
269
  return await new Promise(async (
253
- resolve:(renderResult: ResolverResponse)=>void,
270
+ resolve:(response: ResolverResponse)=>void,
254
271
  reject:(err: Error)=>void
255
272
  )=> {
256
273
  const resolver = this.getResolver(resolve, reject);
257
274
  if(ctx.method === "OPTIONS") return resolver.cors();
258
275
 
259
- const firstMatchedAction = await (async () => {
260
- for(const action of this._actionList){
261
- if(await action.conditionFn(ctx)) return action;
262
- }
263
- })();
264
-
276
+ const firstMatchedAction = this.actionList.find(action => action.conditionFn(ctx));
265
277
  if(firstMatchedAction){
266
- for(const hook of this._hookList["beforeRender"]){
267
- ctx = await hook.hookFn(ctx, resolver);
268
- }
269
- let renderResult = await firstMatchedAction.actionFn(ctx, resolver);
270
- for(const hook of this._hookList["afterRender"]){
271
- renderResult = await hook.hookFn(ctx, resolver, renderResult);
272
- }
273
- resolve(renderResult);
278
+ for(const hook of this.hookList["beforeRender"]){ ctx = await hook.hookFn(ctx, resolver); }
279
+ let response = await firstMatchedAction.actionFn(ctx, resolver);
280
+ for(const hook of this.hookList["afterRender"]){ response = await hook.hookFn(ctx, resolver, response); }
281
+ resolve(response);
274
282
  }else{
275
283
  return this.handleNoMatchedAction(ctx, resolver);
276
284
  }
277
- }).then(async (renderResult: ResolverResponse):Promise<ResolverResponse> => {
278
- for(const hook of this._hookList["completed"]){
279
- renderResult = await hook.hookFn(renderResult);
280
- }
281
- return renderResult;
285
+ }).then(async (response: ResolverResponse):Promise<ResolverResponse> => {
286
+ for(const hook of this.hookList["completed"]){ response = await hook.hookFn(response); }
287
+ return response;
282
288
  });
283
289
  }catch(err){
284
- const responseBuilder = this.getResponseBuilder();
285
- const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
286
290
  if(this.globalErrorHandler){
291
+ const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
292
+ const responseBuilder = this.getResponseBuilder();
287
293
  return this.globalErrorHandler(wrappedError, eventRenderContext, responseBuilder);
288
294
  }
289
295
  return { statusCode: 500, body: "Internal Server Error.", }
package/src/Resolver.ts CHANGED
@@ -16,7 +16,7 @@ interface DieResolverMethods {
16
16
  }
17
17
 
18
18
  export default class Resolver extends ResponseBuilder {
19
- public resolve: (renderResult: ResolverResponse) => void;
19
+ public resolve: (response: ResolverResponse) => void;
20
20
  public reject: (err: Error) => void;
21
21
  public die: DieResolverMethods;
22
22
 
@@ -26,7 +26,7 @@ export default class Resolver extends ResponseBuilder {
26
26
  isCorsEnabled: boolean,
27
27
  publicPath: string,
28
28
  apiVersion?: string|null,
29
- resolve: (renderResult: ResolverResponse) => void,
29
+ resolve: (response: ResolverResponse) => void,
30
30
  reject: (err: Error) => void,
31
31
  }
32
32
  ){