lambder 1.0.17 → 1.0.19

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.
@@ -18,7 +18,7 @@
18
18
  "**/.git/": true,
19
19
  },
20
20
  "cSpell.words": [
21
- "lambder"
21
+ "lambder",
22
22
  ],
23
23
  }
24
24
 
@@ -0,0 +1,39 @@
1
+ type VoidFunction = () => void | Promise<void>;
2
+ type StartEndEventHandler = (activeFetchList: {
3
+ apiName: string;
4
+ done: boolean;
5
+ }[]) => void | Promise<void>;
6
+ type ErrorHandler = (err: Error) => void | Promise<void>;
7
+ type MessageHandler = (message: any) => void | Promise<void>;
8
+ export default class LambderCaller {
9
+ isCorsEnabled: boolean;
10
+ apiPath: string;
11
+ apiVersion?: string;
12
+ fetchTrackerList: {
13
+ apiName: string;
14
+ done: boolean;
15
+ }[];
16
+ versionExpiredHandler?: VoidFunction;
17
+ sessionExpiredHandler?: VoidFunction;
18
+ messageHandler?: MessageHandler;
19
+ errorMessageHandler?: MessageHandler;
20
+ notAuthorizedHandler?: VoidFunction;
21
+ errorHandler?: ErrorHandler;
22
+ fetchStartedHandler?: StartEndEventHandler;
23
+ fetchEndedHandler?: StartEndEventHandler;
24
+ constructor({ isCorsEnabled, apiPath, apiVersion, versionExpiredHandler, sessionExpiredHandler, messageHandler, errorMessageHandler, notAuthorizedHandler, errorHandler, fetchStartedHandler, fetchEndedHandler, }: {
25
+ isCorsEnabled: boolean;
26
+ apiPath: string;
27
+ apiVersion?: string;
28
+ versionExpiredHandler?: VoidFunction;
29
+ sessionExpiredHandler?: VoidFunction;
30
+ messageHandler?: MessageHandler;
31
+ errorMessageHandler?: MessageHandler;
32
+ notAuthorizedHandler?: VoidFunction;
33
+ errorHandler?: ErrorHandler;
34
+ fetchStartedHandler?: StartEndEventHandler;
35
+ fetchEndedHandler?: StartEndEventHandler;
36
+ });
37
+ private api;
38
+ }
39
+ export {};
@@ -0,0 +1,93 @@
1
+ import Cookies from 'js-cookie';
2
+ export default class LambderCaller {
3
+ isCorsEnabled;
4
+ apiPath;
5
+ apiVersion;
6
+ fetchTrackerList = [];
7
+ versionExpiredHandler;
8
+ sessionExpiredHandler;
9
+ messageHandler;
10
+ errorMessageHandler;
11
+ notAuthorizedHandler;
12
+ errorHandler;
13
+ fetchStartedHandler;
14
+ fetchEndedHandler;
15
+ constructor({ isCorsEnabled, apiPath, apiVersion, versionExpiredHandler, sessionExpiredHandler, messageHandler, errorMessageHandler, notAuthorizedHandler, errorHandler, fetchStartedHandler, fetchEndedHandler, }) {
16
+ this.isCorsEnabled = isCorsEnabled;
17
+ this.apiPath = apiPath;
18
+ this.apiVersion = apiVersion;
19
+ this.versionExpiredHandler = versionExpiredHandler;
20
+ this.sessionExpiredHandler = sessionExpiredHandler;
21
+ this.messageHandler = messageHandler;
22
+ this.errorMessageHandler = errorMessageHandler;
23
+ this.notAuthorizedHandler = notAuthorizedHandler;
24
+ this.errorHandler = errorHandler;
25
+ this.fetchStartedHandler = fetchStartedHandler;
26
+ this.fetchEndedHandler = fetchEndedHandler;
27
+ }
28
+ ;
29
+ async api(apiName, payload, headers) {
30
+ const fetchTracker = { apiName, done: false };
31
+ try {
32
+ this.fetchTrackerList.push(fetchTracker);
33
+ if (this.fetchStartedHandler)
34
+ await this.fetchStartedHandler(this.fetchTrackerList.filter(v => !v.done));
35
+ const version = this.apiVersion;
36
+ const token = Cookies.get("LMBRTOKEN") || "";
37
+ const siteHost = window.location.hostname;
38
+ let data = await fetch(this.apiPath, {
39
+ method: 'POST', mode: 'same-origin', cache: 'no-cache',
40
+ credentials: 'same-origin', redirect: 'follow', referrerPolicy: 'origin',
41
+ headers: { 'Content-Type': 'application/json', ...(headers || {}) },
42
+ body: JSON.stringify({ api: apiName, version, token, siteHost, payload, }),
43
+ }).then(res => {
44
+ if (res.status >= 500)
45
+ throw new Error("Request failed: " + res.status + " - " + res.statusText);
46
+ return res.json();
47
+ });
48
+ if (data && data.versionExpired) {
49
+ if (this.versionExpiredHandler) {
50
+ await this.versionExpiredHandler();
51
+ }
52
+ else if (this.errorHandler) {
53
+ await this.errorHandler(new Error("Version Expired; Please refresh;"));
54
+ }
55
+ return null;
56
+ }
57
+ if (data && data.sessionExpired) {
58
+ Cookies.set('LMBRAUTHID', '', { expires: -1 });
59
+ Cookies.set('LMBRTOKEN', '', { expires: -1 });
60
+ if (this.sessionExpiredHandler) {
61
+ await this.sessionExpiredHandler();
62
+ }
63
+ else if (this.errorHandler) {
64
+ await this.errorHandler(new Error("Version Expired; Please refresh;"));
65
+ }
66
+ return null;
67
+ }
68
+ if (data && data.notAuthorized) {
69
+ if (this.notAuthorizedHandler) {
70
+ await this.notAuthorizedHandler();
71
+ }
72
+ else if (this.errorHandler) {
73
+ await this.errorHandler(new Error("Version Expired; Please refresh;"));
74
+ }
75
+ return null;
76
+ }
77
+ if (data && data.message && this.messageHandler) {
78
+ await this.messageHandler(data.message);
79
+ }
80
+ if (data && data.errorMessage && this.errorMessageHandler) {
81
+ await this.errorMessageHandler(data.errorMessage);
82
+ }
83
+ return data.payload ?? null;
84
+ }
85
+ catch (err) {
86
+ fetchTracker.done = true;
87
+ if (this.errorHandler) {
88
+ this.errorHandler(err instanceof Error ? err : new Error("Error: " + String(err)));
89
+ }
90
+ }
91
+ }
92
+ ;
93
+ }
@@ -85,9 +85,13 @@ export default class Resolver {
85
85
  file(filePath: string, headers?: {
86
86
  [key: string]: string | string[];
87
87
  }, fallbackFilePath?: string): ResolverResponse;
88
- api({ payload, error, ...other }: {
88
+ api({ payload, versionExpired, sessionExpired, notAuthorized, message, errorMessage, ...other }: {
89
89
  payload?: any;
90
- error?: any;
90
+ versionExpired?: boolean;
91
+ sessionExpired?: boolean;
92
+ notAuthorized?: boolean;
93
+ message?: any;
94
+ errorMessage?: any;
91
95
  }, headers?: {
92
96
  [key: string]: string | string[];
93
97
  }): ResolverResponse;
package/dist/Resolver.js CHANGED
@@ -136,15 +136,17 @@ export default class Resolver {
136
136
  return this.fileBase64(bodyBase64, mimeType || "", headers);
137
137
  }
138
138
  ;
139
- api({ payload, error = null, ...other }, headers) {
140
- if (error)
141
- console.log("ERROR: ", error);
139
+ api({ payload, versionExpired, sessionExpired, notAuthorized, message = null, errorMessage = null, ...other }, headers) {
142
140
  if (Object.keys(other).length)
143
141
  console.log("ERROR: Unexpected key in result: " + Object.keys(other).join(", "));
144
142
  return this.json({
145
143
  apiVersion: this.apiVersion,
146
144
  payload,
147
- ...(error ? { error } : {}),
145
+ ...(versionExpired ? { versionExpired } : {}),
146
+ ...(sessionExpired ? { sessionExpired } : {}),
147
+ ...(notAuthorized ? { notAuthorized } : {}),
148
+ ...(message ? { message } : {}),
149
+ ...(errorMessage ? { errorMessage } : {}),
148
150
  }, headers);
149
151
  }
150
152
  ;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from "aws-lambda";
2
2
  import Resolver, { ResolverResponse } from "./Resolver.js";
3
+ export { default as LambderCaller } from "./LambderCaller.js";
3
4
  type DDBSession = {
4
5
  userId: string;
5
6
  userIdHash: string;
@@ -44,17 +45,20 @@ export default class Lambder {
44
45
  private _actionList;
45
46
  private _hookList;
46
47
  private globalErrorHandler;
47
- private fallbackHandler;
48
+ private routeFallbackHandler;
49
+ private apiFallbackHandler;
48
50
  constructor({ publicPath, apiPath, apiVersion, isCorsEnabled, }: {
49
51
  publicPath: string;
50
52
  apiPath?: string;
51
53
  apiVersion?: string;
52
54
  isCorsEnabled?: boolean;
53
55
  });
54
- setFallbackHandler(fallbackHandler: (renderContext: RenderContext, resolver: Resolver) => ResolverResponse): void;
56
+ setRouteFallbackHandler(routeFallbackHandler: (renderContext: RenderContext, resolver: Resolver) => ResolverResponse): void;
57
+ setApiFallbackHandler(apiFallbackHandler: (renderContext: RenderContext, resolver: Resolver) => ResolverResponse): void;
55
58
  setGlobalErrorHandler(globalErrorHandler: (err: Error) => ResolverResponse): void;
56
- addModule(moduleFn: Function): Promise<void>;
57
59
  private validateSession;
60
+ private handleNoMatchedAction;
61
+ addModule(moduleFn: Function): Promise<void>;
58
62
  addRoute(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
59
63
  addSessionRoute(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
60
64
  addApi(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
@@ -66,4 +70,3 @@ export default class Lambder {
66
70
  addHook(hookEvent: 'completed', hookFn: HookCompletedFunction, priority?: number): Promise<void>;
67
71
  render(event: APIGatewayProxyEvent, lambdaContext: Context): Promise<ResolverResponse>;
68
72
  }
69
- export {};
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import querystring from "querystring";
2
2
  import cookieParser from "cookie";
3
3
  import Resolver from "./Resolver.js";
4
+ export { default as LambderCaller } from "./LambderCaller.js";
4
5
  export const createContext = (event, lambdaContext, resolve, reject) => {
5
6
  const host = event.headers.Host || event.headers.host || "";
6
7
  const url = event.path;
@@ -33,7 +34,8 @@ export default class Lambder {
33
34
  _actionList;
34
35
  _hookList;
35
36
  globalErrorHandler = null;
36
- fallbackHandler = null;
37
+ routeFallbackHandler = null;
38
+ apiFallbackHandler = null;
37
39
  constructor({ publicPath, apiPath, apiVersion, isCorsEnabled, }) {
38
40
  this.publicPath = publicPath || "/incorrect-path-not-found";
39
41
  this.apiPath = apiPath ?? "/api";
@@ -47,15 +49,15 @@ export default class Lambder {
47
49
  "completed": []
48
50
  };
49
51
  }
50
- setFallbackHandler(fallbackHandler) {
51
- this.fallbackHandler = fallbackHandler;
52
+ setRouteFallbackHandler(routeFallbackHandler) {
53
+ this.routeFallbackHandler = routeFallbackHandler;
54
+ }
55
+ setApiFallbackHandler(apiFallbackHandler) {
56
+ this.apiFallbackHandler = apiFallbackHandler;
52
57
  }
53
58
  setGlobalErrorHandler(globalErrorHandler) {
54
59
  this.globalErrorHandler = globalErrorHandler;
55
60
  }
56
- async addModule(moduleFn) {
57
- await moduleFn(this);
58
- }
59
61
  async validateSession(session) {
60
62
  if (!session)
61
63
  return false;
@@ -68,6 +70,29 @@ export default class Lambder {
68
70
  // Check DDB;
69
71
  return false;
70
72
  }
73
+ ;
74
+ async handleNoMatchedAction(renderContext, resolver) {
75
+ for (const hook of this._hookList["fallback"]) {
76
+ await hook.hookFn(renderContext, resolver);
77
+ }
78
+ if (renderContext.url === this.apiPath) {
79
+ if (this.apiFallbackHandler) {
80
+ resolver.resolve(await this.apiFallbackHandler(renderContext, resolver));
81
+ }
82
+ else {
83
+ resolver.resolve({ statusCode: 204, body: "API handler not set.", });
84
+ }
85
+ }
86
+ else if (this.routeFallbackHandler) {
87
+ resolver.resolve(await this.routeFallbackHandler(renderContext, resolver));
88
+ }
89
+ else {
90
+ resolver.resolve({ statusCode: 204, body: "Handler not set.", });
91
+ }
92
+ }
93
+ async addModule(moduleFn) {
94
+ await moduleFn(this);
95
+ }
71
96
  addRoute(condition, actionFn) {
72
97
  this._actionList.push({
73
98
  conditionFn: async (renderContext) => (renderContext.method === "GET" &&
@@ -77,6 +102,7 @@ export default class Lambder {
77
102
  actionFn: async (renderContext, resolver) => await actionFn(renderContext, resolver)
78
103
  });
79
104
  }
105
+ ;
80
106
  addSessionRoute(condition, actionFn) {
81
107
  this._actionList.push({
82
108
  conditionFn: async (renderContext) => (renderContext.method === "GET" &&
@@ -86,6 +112,7 @@ export default class Lambder {
86
112
  actionFn: async (renderContext, resolver) => await actionFn(renderContext, resolver)
87
113
  });
88
114
  }
115
+ ;
89
116
  addApi(condition, actionFn) {
90
117
  this._actionList.push({
91
118
  conditionFn: async (renderContext) => (renderContext.method === "POST" && renderContext.url === this.apiPath &&
@@ -95,6 +122,7 @@ export default class Lambder {
95
122
  actionFn: async (renderContext, resolver) => await actionFn(renderContext, resolver)
96
123
  });
97
124
  }
125
+ ;
98
126
  addSessionApi(condition, actionFn) {
99
127
  this._actionList.push({
100
128
  conditionFn: async (renderContext) => (renderContext.method === "POST" && renderContext.url === this.apiPath &&
@@ -109,6 +137,7 @@ export default class Lambder {
109
137
  }
110
138
  });
111
139
  }
140
+ ;
112
141
  async addHook(hookEvent, hookFn, priority = 0) {
113
142
  if (hookEvent === "created") {
114
143
  await hookFn(this);
@@ -146,16 +175,7 @@ export default class Lambder {
146
175
  resolve(renderResult);
147
176
  }
148
177
  else {
149
- for (const hook of this._hookList["fallback"]) {
150
- await hook.hookFn(renderContext, resolver);
151
- }
152
- if (this.fallbackHandler) {
153
- const renderResult = await this.fallbackHandler(renderContext, resolver);
154
- resolve(renderResult);
155
- }
156
- else {
157
- resolve({ statusCode: 204, body: "Fallback handler not set.", });
158
- }
178
+ return this.handleNoMatchedAction(renderContext, resolver);
159
179
  }
160
180
  }).then(async (renderResult) => {
161
181
  for (const hook of this._hookList["completed"]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambder",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,12 +14,14 @@
14
14
  "license": "ISC",
15
15
  "dependencies": {
16
16
  "cookie": "^0.6.0",
17
+ "js-cookie": "^3.0.5",
17
18
  "mime-types": "^2.1.35",
18
19
  "querystring": "^0.2.1"
19
20
  },
20
21
  "devDependencies": {
21
22
  "@types/aws-lambda": "^8.10.136",
22
23
  "@types/cookie": "^0.6.0",
24
+ "@types/js-cookie": "^3.0.6",
23
25
  "@types/mime-types": "^2.1.4",
24
26
  "@types/node": "^20.11.27",
25
27
  "@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -0,0 +1,121 @@
1
+ import Cookies from 'js-cookie';
2
+
3
+ type VoidFunction = ()=>void|Promise<void>;
4
+ type StartEndEventHandler = (activeFetchList:{ apiName: string, done: boolean}[])=>void|Promise<void>;
5
+ type ErrorHandler = (err: Error) => void|Promise<void>;
6
+ type MessageHandler = (message:any) => void|Promise<void>;
7
+
8
+ export default class LambderCaller {
9
+ isCorsEnabled: boolean;
10
+ apiPath: string;
11
+ apiVersion?: string;
12
+
13
+ fetchTrackerList: { apiName: string, done: boolean}[] = [];
14
+ versionExpiredHandler?: VoidFunction;
15
+ sessionExpiredHandler?: VoidFunction;
16
+
17
+ messageHandler?: MessageHandler;
18
+ errorMessageHandler?: MessageHandler;
19
+ notAuthorizedHandler?: VoidFunction;
20
+ errorHandler?: ErrorHandler;
21
+
22
+ fetchStartedHandler?: StartEndEventHandler;
23
+ fetchEndedHandler?: StartEndEventHandler;
24
+
25
+ constructor(
26
+ {
27
+ isCorsEnabled, apiPath, apiVersion,
28
+ versionExpiredHandler, sessionExpiredHandler,
29
+ messageHandler, errorMessageHandler,
30
+ notAuthorizedHandler, errorHandler,
31
+ fetchStartedHandler, fetchEndedHandler,
32
+ }:
33
+ {
34
+ isCorsEnabled: boolean,
35
+ apiPath: string,
36
+ apiVersion?: string,
37
+ versionExpiredHandler?: VoidFunction,
38
+ sessionExpiredHandler?: VoidFunction,
39
+ messageHandler?: MessageHandler,
40
+ errorMessageHandler?: MessageHandler,
41
+ notAuthorizedHandler?: VoidFunction,
42
+ errorHandler?: ErrorHandler,
43
+ fetchStartedHandler?: StartEndEventHandler,
44
+ fetchEndedHandler?: StartEndEventHandler,
45
+ }
46
+ ){
47
+ this.isCorsEnabled = isCorsEnabled;
48
+ this.apiPath = apiPath;
49
+ this.apiVersion = apiVersion;
50
+
51
+ this.versionExpiredHandler = versionExpiredHandler;
52
+ this.sessionExpiredHandler = sessionExpiredHandler;
53
+
54
+ this.messageHandler = messageHandler;
55
+ this.errorMessageHandler = errorMessageHandler;
56
+ this.notAuthorizedHandler = notAuthorizedHandler;
57
+ this.errorHandler = errorHandler;
58
+
59
+ this.fetchStartedHandler = fetchStartedHandler;
60
+ this.fetchEndedHandler = fetchEndedHandler;
61
+
62
+ };
63
+
64
+ private async api(apiName: string, payload: any, headers?: { [key:string]: any }){
65
+ const fetchTracker = { apiName, done: false };
66
+ try {
67
+ this.fetchTrackerList.push(fetchTracker);
68
+ if(this.fetchStartedHandler) await this.fetchStartedHandler(this.fetchTrackerList.filter(v=>!v.done));
69
+ const version = this.apiVersion;
70
+ const token = Cookies.get("LMBRTOKEN") || "";
71
+ const siteHost = window.location.hostname;
72
+ let data = await fetch(this.apiPath, {
73
+ method: 'POST', mode: 'same-origin', cache: 'no-cache',
74
+ credentials: 'same-origin', redirect: 'follow', referrerPolicy: 'origin',
75
+ headers: { 'Content-Type': 'application/json', ...(headers || {}) },
76
+ body: JSON.stringify({ api: apiName, version, token, siteHost, payload, }),
77
+ }).then(res=>{
78
+ if(res.status >= 500) throw new Error("Request failed: " + res.status + " - " + res.statusText);
79
+ return res.json();
80
+ });
81
+ if(data && data.versionExpired){
82
+ if(this.versionExpiredHandler){
83
+ await this.versionExpiredHandler();
84
+ }else if(this.errorHandler){
85
+ await this.errorHandler(new Error("Version Expired; Please refresh;"));
86
+ }
87
+ return null;
88
+ }
89
+ if(data && data.sessionExpired){
90
+ Cookies.set('LMBRAUTHID', '', { expires: -1 });
91
+ Cookies.set('LMBRTOKEN', '', { expires: -1 });
92
+ if(this.sessionExpiredHandler){
93
+ await this.sessionExpiredHandler();
94
+ }else if(this.errorHandler){
95
+ await this.errorHandler(new Error("Version Expired; Please refresh;"));
96
+ }
97
+ return null;
98
+ }
99
+ if(data && data.notAuthorized){
100
+ if(this.notAuthorizedHandler){
101
+ await this.notAuthorizedHandler();
102
+ }else if(this.errorHandler){
103
+ await this.errorHandler(new Error("Version Expired; Please refresh;"));
104
+ }
105
+ return null;
106
+ }
107
+ if(data && data.message && this.messageHandler){
108
+ await this.messageHandler(data.message);
109
+ }
110
+ if(data && data.errorMessage && this.errorMessageHandler){
111
+ await this.errorMessageHandler(data.errorMessage);
112
+ }
113
+ return data.payload ?? null;
114
+ }catch(err){
115
+ fetchTracker.done = true
116
+ if(this.errorHandler){
117
+ this.errorHandler(err instanceof Error ? err : new Error("Error: " + String(err)));
118
+ }
119
+ }
120
+ };
121
+ }
package/src/Resolver.ts CHANGED
@@ -198,16 +198,32 @@ export default class Resolver {
198
198
  return this.fileBase64(bodyBase64, mimeType || "", headers);
199
199
  };
200
200
 
201
- api(
202
- { payload, error=null, ...other }: { payload?: any; error?: any; },
201
+ api(
202
+ {
203
+ payload,
204
+ versionExpired, sessionExpired, notAuthorized,
205
+ message = null, errorMessage = null,
206
+ ...other
207
+ }: {
208
+ payload?: any;
209
+ versionExpired?: boolean;
210
+ sessionExpired?: boolean;
211
+ notAuthorized?: boolean;
212
+ message?: any;
213
+ errorMessage?: any;
214
+ },
203
215
  headers?: { [key:string]: string|string[] },
204
- ):ResolverResponse{
205
- if(error) console.log("ERROR: ", error);
216
+ ): ResolverResponse {
206
217
  if(Object.keys(other).length) console.log("ERROR: Unexpected key in result: " + Object.keys(other).join(", "));
207
218
  return this.json({
208
219
  apiVersion: this.apiVersion,
209
- payload,
210
- ...(error ? {error} : {}),
220
+ payload,
221
+ ...(versionExpired ? {versionExpired} : {}),
222
+ ...(sessionExpired ? {sessionExpired} : {}),
223
+ ...(notAuthorized ? {notAuthorized} : {}),
224
+ ...(message ? {message} : {}),
225
+ ...(errorMessage ? {errorMessage} : {}),
211
226
  }, headers);
212
227
  };
228
+
213
229
  }
package/src/index.ts CHANGED
@@ -4,6 +4,8 @@ import cookieParser from "cookie";
4
4
  import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from "aws-lambda";
5
5
  import Resolver, { ResolverResponse } from "./Resolver.js";
6
6
 
7
+ export { default as LambderCaller } from "./LambderCaller.js";
8
+
7
9
  type DDBSession = {
8
10
  userId: string,
9
11
  userIdHash: string;
@@ -80,7 +82,8 @@ export default class Lambder {
80
82
  "completed": { priority: number, hookFn: HookCompletedFunction }[]
81
83
  };
82
84
  private globalErrorHandler: Function|null = null;
83
- private fallbackHandler: Function|null = null;
85
+ private routeFallbackHandler: Function|null = null;
86
+ private apiFallbackHandler: Function|null = null;
84
87
 
85
88
  constructor(
86
89
  { publicPath, apiPath, apiVersion, isCorsEnabled, }:
@@ -100,17 +103,16 @@ export default class Lambder {
100
103
  };
101
104
  }
102
105
 
103
- setFallbackHandler(fallbackHandler: (renderContext:RenderContext, resolver: Resolver)=>ResolverResponse){
104
- this.fallbackHandler = fallbackHandler;
106
+ setRouteFallbackHandler(routeFallbackHandler: (renderContext:RenderContext, resolver: Resolver)=>ResolverResponse){
107
+ this.routeFallbackHandler = routeFallbackHandler;
108
+ }
109
+ setApiFallbackHandler(apiFallbackHandler: (renderContext:RenderContext, resolver: Resolver)=>ResolverResponse){
110
+ this.apiFallbackHandler = apiFallbackHandler;
105
111
  }
106
112
  setGlobalErrorHandler(globalErrorHandler: (err: Error)=>ResolverResponse){
107
113
  this.globalErrorHandler = globalErrorHandler;
108
114
  }
109
115
 
110
- async addModule(moduleFn: Function): Promise<void>{
111
- await moduleFn(this);
112
- }
113
-
114
116
  private async validateSession (session: DDBSession): Promise<boolean>{
115
117
  if(!session) return false;
116
118
  if(!session.userId || !session.userIdHash || !session.sessionHash || !session.csrfToken) return false;
@@ -118,8 +120,28 @@ export default class Lambder {
118
120
  if(session.expiresTimeStamp > Date.now()) return false;
119
121
  // Check DDB;
120
122
  return false;
123
+ };
124
+
125
+ private async handleNoMatchedAction(renderContext: RenderContext, resolver: Resolver){
126
+ for(const hook of this._hookList["fallback"]){
127
+ await hook.hookFn(renderContext, resolver);
128
+ }
129
+ if(renderContext.url === this.apiPath){
130
+ if(this.apiFallbackHandler){
131
+ resolver.resolve(await this.apiFallbackHandler(renderContext, resolver));
132
+ }else{
133
+ resolver.resolve({ statusCode: 204, body: "API handler not set.", })
134
+ }
135
+ }else if(this.routeFallbackHandler){
136
+ resolver.resolve(await this.routeFallbackHandler(renderContext, resolver));
137
+ }else{
138
+ resolver.resolve({ statusCode: 204, body: "Handler not set.", })
139
+ }
121
140
  }
122
141
 
142
+ async addModule(moduleFn: Function): Promise<void>{
143
+ await moduleFn(this);
144
+ }
123
145
  addRoute(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
124
146
  this._actionList.push({
125
147
  conditionFn: async (renderContext:RenderContext) => (
@@ -132,7 +154,7 @@ export default class Lambder {
132
154
  ),
133
155
  actionFn: async (renderContext:RenderContext, resolver: Resolver) => await actionFn(renderContext, resolver)
134
156
  });
135
- }
157
+ };
136
158
 
137
159
  addSessionRoute(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
138
160
  this._actionList.push({
@@ -146,7 +168,7 @@ export default class Lambder {
146
168
  ),
147
169
  actionFn: async (renderContext:RenderContext, resolver: Resolver) => await actionFn(renderContext, resolver)
148
170
  });
149
- }
171
+ };
150
172
 
151
173
  addApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
152
174
  this._actionList.push({
@@ -160,7 +182,7 @@ export default class Lambder {
160
182
  ),
161
183
  actionFn: async (renderContext:RenderContext, resolver: Resolver) => await actionFn(renderContext, resolver)
162
184
  });
163
- }
185
+ };
164
186
 
165
187
  addSessionApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
166
188
  this._actionList.push({
@@ -178,7 +200,7 @@ export default class Lambder {
178
200
  return await actionFn(renderContext, resolver);
179
201
  }
180
202
  });
181
- }
203
+ };
182
204
 
183
205
 
184
206
  async addHook(hookEvent: 'created', hookFn: HookCreatedFunction, priority?: number): Promise<void>;
@@ -199,6 +221,7 @@ export default class Lambder {
199
221
  }
200
222
  }
201
223
 
224
+
202
225
  async render(
203
226
  event: APIGatewayProxyEvent,
204
227
  lambdaContext: Context
@@ -217,8 +240,8 @@ export default class Lambder {
217
240
  if(renderContext.method === "OPTIONS") return resolver.cors();
218
241
 
219
242
  const firstMatchedAction = await (async () => {
220
- for (const action of this._actionList) {
221
- if (await action.conditionFn(renderContext)) return action;
243
+ for(const action of this._actionList){
244
+ if(await action.conditionFn(renderContext)) return action;
222
245
  }
223
246
  })();
224
247
 
@@ -232,15 +255,7 @@ export default class Lambder {
232
255
  }
233
256
  resolve(renderResult);
234
257
  }else{
235
- for(const hook of this._hookList["fallback"]){
236
- await hook.hookFn(renderContext, resolver);
237
- }
238
- if(this.fallbackHandler){
239
- const renderResult = await this.fallbackHandler(renderContext, resolver);
240
- resolve(renderResult);
241
- }else{
242
- resolve({ statusCode: 204, body: "Fallback handler not set.", })
243
- }
258
+ return this.handleNoMatchedAction(renderContext, resolver);
244
259
  }
245
260
  }).then(async (renderResult: ResolverResponse):Promise<ResolverResponse> => {
246
261
  for(const hook of this._hookList["completed"]){