lambder 1.0.18 → 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;
@@ -55,8 +56,9 @@ export default class Lambder {
55
56
  setRouteFallbackHandler(routeFallbackHandler: (renderContext: RenderContext, resolver: Resolver) => ResolverResponse): void;
56
57
  setApiFallbackHandler(apiFallbackHandler: (renderContext: RenderContext, resolver: Resolver) => ResolverResponse): void;
57
58
  setGlobalErrorHandler(globalErrorHandler: (err: Error) => ResolverResponse): void;
58
- addModule(moduleFn: Function): Promise<void>;
59
59
  private validateSession;
60
+ private handleNoMatchedAction;
61
+ addModule(moduleFn: Function): Promise<void>;
60
62
  addRoute(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
61
63
  addSessionRoute(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
62
64
  addApi(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
@@ -68,4 +70,3 @@ export default class Lambder {
68
70
  addHook(hookEvent: 'completed', hookFn: HookCompletedFunction, priority?: number): Promise<void>;
69
71
  render(event: APIGatewayProxyEvent, lambdaContext: Context): Promise<ResolverResponse>;
70
72
  }
71
- 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;
@@ -57,9 +58,6 @@ export default class Lambder {
57
58
  setGlobalErrorHandler(globalErrorHandler) {
58
59
  this.globalErrorHandler = globalErrorHandler;
59
60
  }
60
- async addModule(moduleFn) {
61
- await moduleFn(this);
62
- }
63
61
  async validateSession(session) {
64
62
  if (!session)
65
63
  return false;
@@ -73,6 +71,28 @@ export default class Lambder {
73
71
  return false;
74
72
  }
75
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
+ }
76
96
  addRoute(condition, actionFn) {
77
97
  this._actionList.push({
78
98
  conditionFn: async (renderContext) => (renderContext.method === "GET" &&
@@ -155,18 +175,7 @@ export default class Lambder {
155
175
  resolve(renderResult);
156
176
  }
157
177
  else {
158
- for (const hook of this._hookList["fallback"]) {
159
- await hook.hookFn(renderContext, resolver);
160
- }
161
- if (renderContext.url === this.apiPath && this.apiFallbackHandler) {
162
- resolve(await this.apiFallbackHandler(renderContext, resolver));
163
- }
164
- else if (this.routeFallbackHandler) {
165
- resolve(await this.routeFallbackHandler(renderContext, resolver));
166
- }
167
- else {
168
- resolve({ statusCode: 204, body: "Fallback handler not set.", });
169
- }
178
+ return this.handleNoMatchedAction(renderContext, resolver);
170
179
  }
171
180
  }).then(async (renderResult) => {
172
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.18",
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;
@@ -111,10 +113,6 @@ export default class Lambder {
111
113
  this.globalErrorHandler = globalErrorHandler;
112
114
  }
113
115
 
114
- async addModule(moduleFn: Function): Promise<void>{
115
- await moduleFn(this);
116
- }
117
-
118
116
  private async validateSession (session: DDBSession): Promise<boolean>{
119
117
  if(!session) return false;
120
118
  if(!session.userId || !session.userIdHash || !session.sessionHash || !session.csrfToken) return false;
@@ -124,6 +122,26 @@ export default class Lambder {
124
122
  return false;
125
123
  };
126
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
+ }
140
+ }
141
+
142
+ async addModule(moduleFn: Function): Promise<void>{
143
+ await moduleFn(this);
144
+ }
127
145
  addRoute(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
128
146
  this._actionList.push({
129
147
  conditionFn: async (renderContext:RenderContext) => (
@@ -203,6 +221,7 @@ export default class Lambder {
203
221
  }
204
222
  }
205
223
 
224
+
206
225
  async render(
207
226
  event: APIGatewayProxyEvent,
208
227
  lambdaContext: Context
@@ -236,16 +255,7 @@ export default class Lambder {
236
255
  }
237
256
  resolve(renderResult);
238
257
  }else{
239
- for(const hook of this._hookList["fallback"]){
240
- await hook.hookFn(renderContext, resolver);
241
- }
242
- if(renderContext.url === this.apiPath && this.apiFallbackHandler){
243
- resolve(await this.apiFallbackHandler(renderContext, resolver));
244
- }else if(this.routeFallbackHandler){
245
- resolve(await this.routeFallbackHandler(renderContext, resolver));
246
- }else{
247
- resolve({ statusCode: 204, body: "Fallback handler not set.", })
248
- }
258
+ return this.handleNoMatchedAction(renderContext, resolver);
249
259
  }
250
260
  }).then(async (renderResult: ResolverResponse):Promise<ResolverResponse> => {
251
261
  for(const hook of this._hookList["completed"]){