lambder 1.0.115 → 1.0.117

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
@@ -243,6 +243,10 @@ After you enable the session, you can access to the session controller:
243
243
  async fetchSession():
244
244
  // Fetch and validate if there is an existing session
245
245
  // This is automatically done for addSessionRoute and addSessionApi
246
+ // Throws if session not found
247
+
248
+ async fetchSessionIfExists():
249
+ // Runs fetchSession and returns the session if found. Otherwise return null
246
250
 
247
251
  async updateSessionData(updatedData):
248
252
  // Updates the active sessions data and persist it to ddb.
package/dist/Lambder.d.ts CHANGED
@@ -2,9 +2,10 @@ import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from
2
2
  import LambderResolver from "./LambderResolver.js";
3
3
  import LambderResponseBuilder, { LambderResolverResponse } from "./LambderResponseBuilder.js";
4
4
  import LambderUtils from "./LambderUtils.js";
5
- import { type LambderSessionContext } from "./LambderSession.js";
5
+ import { type LambderSessionContext } from "./LambderSessionManager.js";
6
+ import LambderSessionController from "./LambderSessionController.js";
6
7
  type Path = `/${string}`;
7
- type LambderRenderContext = {
8
+ export type LambderRenderContext = {
8
9
  host: string;
9
10
  path: string;
10
11
  pathParams: Record<string, any> | null;
@@ -17,6 +18,9 @@ type LambderRenderContext = {
17
18
  headers: APIGatewayProxyEventHeaders;
18
19
  session: LambderSessionContext | null;
19
20
  lambdaContext: Context;
21
+ _otherInternal: {
22
+ isApiCall: boolean;
23
+ };
20
24
  };
21
25
  type LambderModuleFunction = (lambderInstance: Lambder) => void | Promise<void>;
22
26
  type ConditionFunction = (ctx: LambderRenderContext) => boolean;
@@ -41,7 +45,7 @@ export default class Lambder {
41
45
  private routeFallbackHandler;
42
46
  private apiFallbackHandler;
43
47
  utils: LambderUtils;
44
- private lambderSession?;
48
+ private lambderSessionManager?;
45
49
  private sessionTokenCookieKey;
46
50
  private sessionCsrfCookieKey;
47
51
  constructor({ publicPath, apiPath, ejsPath, apiVersion }: {
@@ -65,10 +69,6 @@ export default class Lambder {
65
69
  setGlobalErrorHandler(globalErrorHandler: GlobalErrorHandlerFunction): void;
66
70
  private getPatternMatch;
67
71
  private testPatternMatch;
68
- fetchSessionIfExist(ctx: LambderRenderContext): Promise<LambderSessionContext | null>;
69
- fetchSession(ctx: LambderRenderContext): Promise<LambderSessionContext>;
70
- private areRequestSessionTokensValid;
71
- private isSessionValid;
72
72
  private handleNoMatchedAction;
73
73
  addModule(moduleFn: LambderModuleFunction): Promise<void>;
74
74
  importModule(moduleImport: Promise<{
@@ -82,13 +82,7 @@ export default class Lambder {
82
82
  addHook(hookEvent: 'beforeRender', hookFn: HookBeforeRenderFunction, priority?: number): Promise<void>;
83
83
  addHook(hookEvent: 'afterRender', hookFn: HookAfterRenderFunction, priority?: number): Promise<void>;
84
84
  addHook(hookEvent: 'fallback', hookFn: HookFallbackFunction, priority?: number): Promise<void>;
85
- getSessionController(ctx: LambderRenderContext): {
86
- createSession: (sessionKey: string, data?: any, ttlInSeconds?: number) => Promise<LambderSessionContext>;
87
- fetchSession: () => Promise<LambderSessionContext>;
88
- updateSessionData: (newData: any) => Promise<LambderSessionContext>;
89
- endSession: () => Promise<void>;
90
- endSessionAll: () => Promise<void>;
91
- };
85
+ getSessionController(ctx: LambderRenderContext): LambderSessionController;
92
86
  getResponseBuilder(): LambderResponseBuilder;
93
87
  private getResolver;
94
88
  render(event: APIGatewayProxyEvent, lambdaContext: Context): Promise<LambderResolverResponse>;
package/dist/Lambder.js CHANGED
@@ -4,10 +4,8 @@ import { match } from "path-to-regexp";
4
4
  import LambderResolver from "./LambderResolver.js";
5
5
  import LambderResponseBuilder from "./LambderResponseBuilder.js";
6
6
  import LambderUtils from "./LambderUtils.js";
7
- import LambderSession from "./LambderSession.js";
8
- const isApiCallChecker = (method, path, post, apiPath) => {
9
- return method === "POST" && apiPath && path === apiPath && post.apiName;
10
- };
7
+ import LambderSessionManager from "./LambderSessionManager.js";
8
+ import LambderSessionController from "./LambderSessionController.js";
11
9
  export const createContext = (event, lambdaContext, apiPath) => {
12
10
  const host = event.headers.Host || event.headers.host || "";
13
11
  const path = event.path;
@@ -30,10 +28,16 @@ export const createContext = (event, lambdaContext, apiPath) => {
30
28
  }
31
29
  catch (e) { }
32
30
  // Parse api variables
33
- const isApiCall = isApiCallChecker(method, path, post, apiPath);
31
+ const isApiCall = method === "POST" && apiPath && path === apiPath && post.apiName;
34
32
  const apiName = isApiCall ? post.apiName : null;
35
33
  const apiPayload = isApiCall ? post.payload : null;
36
- return { host, path, pathParams, method, get, post, cookie, apiName, apiPayload, headers, session, lambdaContext };
34
+ return {
35
+ host, path, pathParams, method,
36
+ get, post, cookie,
37
+ apiName, apiPayload,
38
+ headers, session, lambdaContext,
39
+ _otherInternal: { isApiCall }
40
+ };
37
41
  };
38
42
  export default class Lambder {
39
43
  apiPath;
@@ -47,7 +51,7 @@ export default class Lambder {
47
51
  routeFallbackHandler = null;
48
52
  apiFallbackHandler = null;
49
53
  utils;
50
- lambderSession;
54
+ lambderSessionManager;
51
55
  sessionTokenCookieKey = "LMDRSESSIONTKID";
52
56
  sessionCsrfCookieKey = "LMDRSESSIONCSTK";
53
57
  constructor({ publicPath, apiPath, ejsPath, apiVersion }) {
@@ -67,7 +71,7 @@ export default class Lambder {
67
71
  this.isCorsEnabled = isCorsEnabled;
68
72
  }
69
73
  enableDdbSession({ tableName, tableRegion, sessionSalt }, { partitionKey, sortKey } = { partitionKey: "pk", sortKey: "sk" }) {
70
- this.lambderSession = new LambderSession({
74
+ this.lambderSessionManager = new LambderSessionManager({
71
75
  tableName, tableRegion, partitionKey, sortKey, sessionSalt
72
76
  });
73
77
  }
@@ -93,59 +97,6 @@ export default class Lambder {
93
97
  testPatternMatch(pattern, path) {
94
98
  return (match(pattern, { decode: decodeURIComponent }))(path) !== false;
95
99
  }
96
- async fetchSessionIfExist(ctx) {
97
- try {
98
- return await this.fetchSession(ctx);
99
- }
100
- catch (err) {
101
- return null;
102
- }
103
- }
104
- async fetchSession(ctx) {
105
- if (!this.lambderSession)
106
- throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
107
- if (!this.areRequestSessionTokensValid(ctx)) {
108
- throw new Error("Session tokens are invalid");
109
- }
110
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
111
- if (!sessionToken)
112
- throw new Error("Session token not found");
113
- const session = await this.lambderSession.getSession(sessionToken);
114
- if (!session)
115
- throw new Error("Session not found");
116
- if (!this.isSessionValid(ctx, session))
117
- throw new Error("Invalid session");
118
- ctx.session = session;
119
- return session;
120
- }
121
- ;
122
- areRequestSessionTokensValid(ctx) {
123
- const isApiCall = isApiCallChecker(ctx.method, ctx.path, ctx.post, this.apiPath);
124
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
125
- const isSessionTokenValid = sessionToken && sessionToken?.split(":")?.length === 2;
126
- if (isApiCall) {
127
- const csrfToken = ctx.post?.token;
128
- const isCsrfTokenValid = typeof csrfToken === "string" && csrfToken.length > 0;
129
- return isSessionTokenValid && isCsrfTokenValid;
130
- }
131
- else {
132
- return isSessionTokenValid;
133
- }
134
- }
135
- isSessionValid(ctx, session) {
136
- if (!this.lambderSession)
137
- return false;
138
- const isApiCall = isApiCallChecker(ctx.method, ctx.path, ctx.post, this.apiPath);
139
- if (isApiCall) {
140
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
141
- const csrfToken = ctx.post?.token;
142
- return this.lambderSession.isSessionValid(session, sessionToken, csrfToken);
143
- }
144
- else {
145
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
146
- return this.lambderSession.isSessionValid(session, sessionToken, null, true);
147
- }
148
- }
149
100
  async handleNoMatchedAction(ctx, resolver) {
150
101
  for (const hook of this.hookList["fallback"]) {
151
102
  await hook.hookFn(ctx, resolver);
@@ -195,7 +146,7 @@ export default class Lambder {
195
146
  (typeof condition === "function" && condition(ctx)) ||
196
147
  (condition?.constructor == RegExp && condition.test(ctx.path)))),
197
148
  actionFn: async (ctx, resolver) => {
198
- await this.fetchSession(ctx);
149
+ await this.getSessionController(ctx).fetchSession();
199
150
  if (typeof condition === "string") {
200
151
  ctx.pathParams = this.getPatternMatch(condition, ctx.path);
201
152
  }
@@ -222,7 +173,7 @@ export default class Lambder {
222
173
  (typeof apiName === "function" && apiName(ctx)) ||
223
174
  (apiName?.constructor == RegExp && apiName.test(ctx.apiName)))),
224
175
  actionFn: async (ctx, resolver) => {
225
- await this.fetchSession(ctx);
176
+ await this.getSessionController(ctx).fetchSession();
226
177
  return await actionFn(ctx, resolver);
227
178
  }
228
179
  });
@@ -238,43 +189,13 @@ export default class Lambder {
238
189
  }
239
190
  }
240
191
  getSessionController(ctx) {
241
- return {
242
- createSession: async (sessionKey, data, ttlInSeconds) => {
243
- if (!this.lambderSession)
244
- throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
245
- ctx.session = await this.lambderSession.createSession(sessionKey, data, ttlInSeconds);
246
- return ctx.session;
247
- },
248
- fetchSession: async () => {
249
- if (!this.lambderSession)
250
- throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
251
- return this.fetchSession(ctx);
252
- },
253
- updateSessionData: async (newData) => {
254
- if (!this.lambderSession)
255
- throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
256
- if (!ctx.session)
257
- throw new Error("Session not found.");
258
- ctx.session = await this.lambderSession.updateSessionData(ctx.session, newData);
259
- return ctx.session;
260
- },
261
- endSession: async () => {
262
- if (!this.lambderSession)
263
- throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
264
- if (!ctx.session)
265
- throw new Error("Session not found.");
266
- await this.lambderSession.deleteSession(ctx.session);
267
- ctx.session = null;
268
- },
269
- endSessionAll: async () => {
270
- if (!this.lambderSession)
271
- throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
272
- if (!ctx.session)
273
- throw new Error("Session not found.");
274
- await this.lambderSession.deleteSessionAll(ctx.session);
275
- ctx.session = null;
276
- },
277
- };
192
+ if (!this.lambderSessionManager)
193
+ throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
194
+ return new LambderSessionController({
195
+ lambderSessionManager: this.lambderSessionManager,
196
+ sessionTokenCookieKey: this.sessionTokenCookieKey,
197
+ ctx,
198
+ });
278
199
  }
279
200
  getResponseBuilder() {
280
201
  return new LambderResponseBuilder({
@@ -0,0 +1,21 @@
1
+ import { LambderRenderContext } from "./Lambder.js";
2
+ import type LambderSessionManager from "./LambderSessionManager.js";
3
+ import type { LambderSessionContext } from "./LambderSessionManager.js";
4
+ export default class LambderSessionController {
5
+ lambderSessionManager: LambderSessionManager;
6
+ sessionTokenCookieKey: string;
7
+ ctx: LambderRenderContext;
8
+ constructor({ lambderSessionManager, sessionTokenCookieKey, ctx, }: {
9
+ lambderSessionManager: LambderSessionManager;
10
+ sessionTokenCookieKey: string;
11
+ ctx: LambderRenderContext;
12
+ });
13
+ private areRequestSessionTokensValid;
14
+ createSession(sessionKey: string, data?: any, ttlInSeconds?: number): Promise<LambderSessionContext>;
15
+ fetchSession(): Promise<LambderSessionContext>;
16
+ fetchSessionIfExists(): Promise<LambderSessionContext | null>;
17
+ isSessionValid(session: any): boolean;
18
+ updateSessionData(newData: any): Promise<LambderSessionContext>;
19
+ endSession(): Promise<void>;
20
+ endSessionAll(): Promise<void>;
21
+ }
@@ -0,0 +1,88 @@
1
+ export default class LambderSessionController {
2
+ lambderSessionManager;
3
+ sessionTokenCookieKey;
4
+ ctx;
5
+ constructor({ lambderSessionManager, sessionTokenCookieKey, ctx, }) {
6
+ this.ctx = ctx;
7
+ this.sessionTokenCookieKey = sessionTokenCookieKey;
8
+ this.lambderSessionManager = lambderSessionManager;
9
+ }
10
+ ;
11
+ areRequestSessionTokensValid() {
12
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
13
+ const isSessionTokenValid = sessionToken && sessionToken?.split(":")?.length === 2;
14
+ if (this.ctx._otherInternal.isApiCall) {
15
+ const csrfToken = this.ctx.post?.token;
16
+ const isCsrfTokenValid = typeof csrfToken === "string" && csrfToken.length > 0;
17
+ return isSessionTokenValid && isCsrfTokenValid;
18
+ }
19
+ else {
20
+ return isSessionTokenValid;
21
+ }
22
+ }
23
+ ;
24
+ async createSession(sessionKey, data, ttlInSeconds) {
25
+ this.ctx.session = await this.lambderSessionManager.createSession(sessionKey, data, ttlInSeconds);
26
+ return this.ctx.session;
27
+ }
28
+ ;
29
+ async fetchSession() {
30
+ if (!this.areRequestSessionTokensValid()) {
31
+ throw new Error("Session tokens are invalid");
32
+ }
33
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
34
+ if (!sessionToken)
35
+ throw new Error("Session token not found");
36
+ const session = await this.lambderSessionManager.getSession(sessionToken);
37
+ if (!session)
38
+ throw new Error("Session not found");
39
+ if (!this.isSessionValid(session))
40
+ throw new Error("Invalid session");
41
+ this.ctx.session = session;
42
+ return session;
43
+ }
44
+ ;
45
+ async fetchSessionIfExists() {
46
+ try {
47
+ return await this.fetchSession();
48
+ }
49
+ catch (err) {
50
+ return null;
51
+ }
52
+ }
53
+ ;
54
+ isSessionValid(session) {
55
+ if (this.ctx._otherInternal.isApiCall) {
56
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
57
+ const csrfToken = this.ctx.post?.token;
58
+ return this.lambderSessionManager.isSessionValid(session, sessionToken, csrfToken);
59
+ }
60
+ else {
61
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
62
+ return this.lambderSessionManager.isSessionValid(session, sessionToken, null, true);
63
+ }
64
+ }
65
+ ;
66
+ async updateSessionData(newData) {
67
+ if (!this.ctx.session)
68
+ throw new Error("Session not found.");
69
+ this.ctx.session = await this.lambderSessionManager.updateSessionData(this.ctx.session, newData);
70
+ return this.ctx.session;
71
+ }
72
+ ;
73
+ async endSession() {
74
+ if (!this.ctx.session)
75
+ throw new Error("Session not found.");
76
+ await this.lambderSessionManager.deleteSession(this.ctx.session);
77
+ this.ctx.session = null;
78
+ }
79
+ ;
80
+ async endSessionAll() {
81
+ if (!this.ctx.session)
82
+ throw new Error("Session not found.");
83
+ await this.lambderSessionManager.deleteSessionAll(this.ctx.session);
84
+ this.ctx.session = null;
85
+ }
86
+ ;
87
+ }
88
+ ;
@@ -8,7 +8,7 @@ export type LambderSessionContext = {
8
8
  expiresAt: number;
9
9
  ttlInSeconds: number;
10
10
  };
11
- export default class LambderSession {
11
+ export default class LambderSessionManager {
12
12
  private tableName;
13
13
  private sessionSalt;
14
14
  private partitionKey;
@@ -1,7 +1,7 @@
1
1
  import crypto from "crypto";
2
2
  import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
3
3
  import { DynamoDBDocumentClient, QueryCommand, DeleteCommand, PutCommand, GetCommand } from "@aws-sdk/lib-dynamodb";
4
- export default class LambderSession {
4
+ export default class LambderSessionManager {
5
5
  tableName;
6
6
  sessionSalt;
7
7
  partitionKey;
package/dist/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export default Lambder;
3
3
  export { default as LambderCaller } from "./LambderCaller.js";
4
4
  export { default as LambderResponseBuilder } from "./LambderResponseBuilder.js";
5
5
  export { default as LambderResolver } from "./LambderResolver.js";
6
- export { default as LambderSession } from "./LambderSession.js";
6
+ export { default as LambderSessionManager } from "./LambderSessionManager.js";
package/dist/index.js CHANGED
@@ -3,4 +3,4 @@ export default Lambder;
3
3
  export { default as LambderCaller } from "./LambderCaller.js";
4
4
  export { default as LambderResponseBuilder } from "./LambderResponseBuilder.js";
5
5
  export { default as LambderResolver } from "./LambderResolver.js";
6
- export { default as LambderSession } from "./LambderSession.js";
6
+ export { default as LambderSessionManager } from "./LambderSessionManager.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambder",
3
- "version": "1.0.115",
3
+ "version": "1.0.117",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/Lambder.ts CHANGED
@@ -6,11 +6,12 @@ import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from
6
6
  import LambderResolver from "./LambderResolver.js";
7
7
  import LambderResponseBuilder, { LambderResolverResponse } from "./LambderResponseBuilder.js";
8
8
  import LambderUtils from "./LambderUtils.js";
9
- import LambderSession, { type LambderSessionContext } from "./LambderSession.js";
9
+ import LambderSessionManager, { type LambderSessionContext } from "./LambderSessionManager.js";
10
+ import LambderSessionController from "./LambderSessionController.js";
10
11
 
11
12
  type Path = `/${string}`;
12
13
 
13
- type LambderRenderContext = {
14
+ export type LambderRenderContext = {
14
15
  host: string;
15
16
  path: string;
16
17
  pathParams: Record<string, any> | null;
@@ -23,6 +24,7 @@ type LambderRenderContext = {
23
24
  headers: APIGatewayProxyEventHeaders;
24
25
  session: LambderSessionContext|null;
25
26
  lambdaContext: Context;
27
+ _otherInternal: { isApiCall: boolean };
26
28
  };
27
29
 
28
30
  type LambderModuleFunction = (lambderInstance: Lambder) => void | Promise<void>;
@@ -41,9 +43,6 @@ type GlobalErrorHandlerFunction = (err: Error, ctx: LambderRenderContext|null, r
41
43
  type RouteFallbackHandlerFunction = (ctx:LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse;
42
44
  type ApiFallbackHandlerFunction = (ctx:LambderRenderContext, resolver: LambderResolver) => LambderResolverResponse;
43
45
 
44
- const isApiCallChecker = (method: string, path: string, post: Record<any,any>, apiPath: string): boolean => {
45
- return method === "POST" && apiPath && path === apiPath && post.apiName;
46
- }
47
46
 
48
47
  export const createContext = (
49
48
  event: APIGatewayProxyEvent,
@@ -58,6 +57,7 @@ export const createContext = (
58
57
  const cookie = cookieParser.parse(event.headers.Cookie || event.headers.cookie || "");
59
58
  const headers = event.headers;
60
59
  const session = null;
60
+
61
61
  // Decode body for the post
62
62
  let post: Record<string, any> = {};
63
63
  try {
@@ -66,11 +66,18 @@ export const createContext = (
66
66
  catch(e){ post = querystring.parse(decodedBody) || {}; }
67
67
  }catch(e){}
68
68
  // Parse api variables
69
- const isApiCall = isApiCallChecker(method, path, post, apiPath);
69
+
70
+ const isApiCall = method === "POST" && apiPath && path === apiPath && post.apiName;
70
71
  const apiName:string = isApiCall ? post.apiName : null;
71
72
  const apiPayload:string = isApiCall ? post.payload : null;
72
73
 
73
- return { host, path, pathParams, method, get, post, cookie, apiName, apiPayload, headers, session, lambdaContext };
74
+ return {
75
+ host, path, pathParams, method,
76
+ get, post, cookie,
77
+ apiName, apiPayload,
78
+ headers, session, lambdaContext,
79
+ _otherInternal: { isApiCall }
80
+ };
74
81
  }
75
82
 
76
83
 
@@ -93,7 +100,7 @@ export default class Lambder {
93
100
 
94
101
  public utils: LambderUtils;
95
102
 
96
- private lambderSession?: LambderSession;
103
+ private lambderSessionManager?: LambderSessionManager;
97
104
  private sessionTokenCookieKey = "LMDRSESSIONTKID";
98
105
  private sessionCsrfCookieKey = "LMDRSESSIONCSTK";
99
106
 
@@ -124,7 +131,7 @@ export default class Lambder {
124
131
  { tableName, tableRegion, sessionSalt }: { tableName: string; tableRegion: string; sessionSalt: string; },
125
132
  { partitionKey, sortKey }: { partitionKey: string, sortKey: string } = { partitionKey: "pk", sortKey: "sk" }
126
133
  ){
127
- this.lambderSession = new LambderSession({
134
+ this.lambderSessionManager = new LambderSessionManager({
128
135
  tableName, tableRegion, partitionKey, sortKey, sessionSalt
129
136
  });
130
137
  }
@@ -151,56 +158,6 @@ export default class Lambder {
151
158
  private testPatternMatch(pattern: string, path: string): boolean{
152
159
  return (match(pattern, { decode: decodeURIComponent }))(path) !== false;
153
160
  }
154
-
155
- async fetchSessionIfExist(ctx: LambderRenderContext): Promise<LambderSessionContext|null>{
156
- try {
157
- return await this.fetchSession(ctx);
158
- }catch(err){
159
- return null;
160
- }
161
- }
162
-
163
- async fetchSession (ctx: LambderRenderContext): Promise<LambderSessionContext>{
164
- if(!this.lambderSession) throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
165
- if(!this.areRequestSessionTokensValid(ctx)){ throw new Error("Session tokens are invalid"); }
166
-
167
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
168
- if(!sessionToken) throw new Error("Session token not found");
169
-
170
- const session = await this.lambderSession.getSession(sessionToken);
171
- if(!session) throw new Error("Session not found");
172
-
173
- if(!this.isSessionValid(ctx, session)) throw new Error("Invalid session");
174
- ctx.session = session;
175
- return session;
176
- };
177
-
178
- private areRequestSessionTokensValid(ctx: LambderRenderContext): boolean {
179
- const isApiCall = isApiCallChecker(ctx.method, ctx.path, ctx.post, this.apiPath);
180
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
181
- const isSessionTokenValid = sessionToken && sessionToken?.split(":")?.length === 2;
182
-
183
- if(isApiCall){
184
- const csrfToken = ctx.post?.token;
185
- const isCsrfTokenValid = typeof csrfToken === "string" && csrfToken.length > 0
186
- return isSessionTokenValid && isCsrfTokenValid;
187
- }else{
188
- return isSessionTokenValid;
189
- }
190
- }
191
-
192
- private isSessionValid(ctx: LambderRenderContext, session: any): boolean {
193
- if(!this.lambderSession) return false;
194
- const isApiCall = isApiCallChecker(ctx.method, ctx.path, ctx.post, this.apiPath);
195
- if(isApiCall){
196
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
197
- const csrfToken = ctx.post?.token;
198
- return this.lambderSession.isSessionValid(session, sessionToken, csrfToken);
199
- }else{
200
- const sessionToken = ctx.cookie?.[this.sessionTokenCookieKey];
201
- return this.lambderSession.isSessionValid(session, sessionToken, null, true);
202
- }
203
- }
204
161
 
205
162
  private async handleNoMatchedAction(ctx: LambderRenderContext, resolver: LambderResolver){
206
163
  for(const hook of this.hookList["fallback"]){ await hook.hookFn(ctx, resolver); }
@@ -258,7 +215,8 @@ export default class Lambder {
258
215
  )
259
216
  ),
260
217
  actionFn: async (ctx:LambderRenderContext, resolver: LambderResolver) => {
261
- await this.fetchSession(ctx);
218
+ await this.getSessionController(ctx).fetchSession();
219
+
262
220
  if(typeof condition === "string"){
263
221
  ctx.pathParams = this.getPatternMatch(condition, ctx.path);
264
222
  }else if(condition?.constructor == RegExp){
@@ -292,7 +250,7 @@ export default class Lambder {
292
250
  )
293
251
  ),
294
252
  actionFn: async (ctx:LambderRenderContext, resolver: LambderResolver) => {
295
- await this.fetchSession(ctx);
253
+ await this.getSessionController(ctx).fetchSession();
296
254
  return await actionFn(ctx, resolver);
297
255
  }
298
256
  });
@@ -315,36 +273,14 @@ export default class Lambder {
315
273
  }
316
274
  }
317
275
 
318
- getSessionController(ctx: LambderRenderContext){
319
- return {
320
- createSession: async (sessionKey: string, data?: any, ttlInSeconds?: number): Promise<LambderSessionContext> => {
321
- if(!this.lambderSession) throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
322
- ctx.session = await this.lambderSession.createSession(sessionKey, data, ttlInSeconds);
323
- return ctx.session;
324
- },
325
- fetchSession: async (): Promise<LambderSessionContext> => {
326
- if(!this.lambderSession) throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
327
- return this.fetchSession(ctx);
328
- },
329
- updateSessionData: async (newData: any): Promise<LambderSessionContext> => {
330
- if(!this.lambderSession) throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
331
- if(!ctx.session) throw new Error("Session not found.");
332
- ctx.session = await this.lambderSession.updateSessionData(ctx.session, newData);
333
- return ctx.session;
334
- },
335
- endSession: async () => {
336
- if(!this.lambderSession) throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
337
- if(!ctx.session) throw new Error("Session not found.");
338
- await this.lambderSession.deleteSession(ctx.session);
339
- ctx.session = null
340
- },
341
- endSessionAll: async () => {
342
- if(!this.lambderSession) throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
343
- if(!ctx.session) throw new Error("Session not found.");
344
- await this.lambderSession.deleteSessionAll(ctx.session);
345
- ctx.session = null
346
- },
347
- }
276
+ getSessionController(ctx: LambderRenderContext): LambderSessionController{
277
+ if(!this.lambderSessionManager) throw new Error("Session is not enabled. Use lambder.enableDdbSession(...) to enable.");
278
+
279
+ return new LambderSessionController({
280
+ lambderSessionManager: this.lambderSessionManager,
281
+ sessionTokenCookieKey: this.sessionTokenCookieKey,
282
+ ctx,
283
+ });
348
284
  }
349
285
 
350
286
  getResponseBuilder(){
@@ -0,0 +1,94 @@
1
+ import { LambderRenderContext } from "./Lambder.js";
2
+ import type LambderSessionManager from "./LambderSessionManager.js";
3
+ import type { LambderSessionContext } from "./LambderSessionManager.js";
4
+
5
+ export default class LambderSessionController {
6
+ lambderSessionManager: LambderSessionManager;
7
+ sessionTokenCookieKey: string;
8
+ ctx: LambderRenderContext;
9
+
10
+ constructor(
11
+ {
12
+ lambderSessionManager,
13
+ sessionTokenCookieKey,
14
+ ctx,
15
+ }: {
16
+ lambderSessionManager: LambderSessionManager,
17
+ sessionTokenCookieKey: string,
18
+ ctx: LambderRenderContext,
19
+ }
20
+ ){
21
+ this.ctx = ctx;
22
+ this.sessionTokenCookieKey = sessionTokenCookieKey;
23
+ this.lambderSessionManager = lambderSessionManager;
24
+ };
25
+
26
+ private areRequestSessionTokensValid(): boolean {
27
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
28
+ const isSessionTokenValid = sessionToken && sessionToken?.split(":")?.length === 2;
29
+
30
+ if(this.ctx._otherInternal.isApiCall){
31
+ const csrfToken = this.ctx.post?.token;
32
+ const isCsrfTokenValid = typeof csrfToken === "string" && csrfToken.length > 0
33
+ return isSessionTokenValid && isCsrfTokenValid;
34
+ }else{
35
+ return isSessionTokenValid;
36
+ }
37
+ };
38
+
39
+ async createSession (sessionKey: string, data?: any, ttlInSeconds?: number): Promise<LambderSessionContext> {
40
+ this.ctx.session = await this.lambderSessionManager.createSession(sessionKey, data, ttlInSeconds);
41
+ return this.ctx.session;
42
+ };
43
+
44
+ async fetchSession (): Promise<LambderSessionContext>{
45
+ if(!this.areRequestSessionTokensValid()){ throw new Error("Session tokens are invalid"); }
46
+
47
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
48
+ if(!sessionToken) throw new Error("Session token not found");
49
+
50
+ const session = await this.lambderSessionManager.getSession(sessionToken);
51
+ if(!session) throw new Error("Session not found");
52
+
53
+ if(!this.isSessionValid(session)) throw new Error("Invalid session");
54
+ this.ctx.session = session;
55
+ return session;
56
+ };
57
+
58
+ async fetchSessionIfExists (): Promise<LambderSessionContext|null> {
59
+ try {
60
+ return await this.fetchSession();
61
+ }catch(err){
62
+ return null;
63
+ }
64
+ };
65
+
66
+ isSessionValid(session: any): boolean {
67
+ if(this.ctx._otherInternal.isApiCall){
68
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
69
+ const csrfToken = this.ctx.post?.token;
70
+ return this.lambderSessionManager.isSessionValid(session, sessionToken, csrfToken);
71
+ }else{
72
+ const sessionToken = this.ctx.cookie?.[this.sessionTokenCookieKey];
73
+ return this.lambderSessionManager.isSessionValid(session, sessionToken, null, true);
74
+ }
75
+ };
76
+
77
+ async updateSessionData (newData: any): Promise<LambderSessionContext> {
78
+ if(!this.ctx.session) throw new Error("Session not found.");
79
+ this.ctx.session = await this.lambderSessionManager.updateSessionData(this.ctx.session, newData);
80
+ return this.ctx.session;
81
+ };
82
+
83
+ async endSession (){
84
+ if(!this.ctx.session) throw new Error("Session not found.");
85
+ await this.lambderSessionManager.deleteSession(this.ctx.session);
86
+ this.ctx.session = null
87
+ };
88
+
89
+ async endSessionAll (){
90
+ if(!this.ctx.session) throw new Error("Session not found.");
91
+ await this.lambderSessionManager.deleteSessionAll(this.ctx.session);
92
+ this.ctx.session = null
93
+ };
94
+ };
@@ -14,7 +14,7 @@ export type LambderSessionContext = {
14
14
  };
15
15
 
16
16
 
17
- export default class LambderSession{
17
+ export default class LambderSessionManager{
18
18
  private tableName: string;
19
19
  private sessionSalt: string;
20
20
  private partitionKey: string;
package/src/index.ts CHANGED
@@ -4,4 +4,4 @@ export default Lambder;
4
4
  export { default as LambderCaller } from "./LambderCaller.js";
5
5
  export { default as LambderResponseBuilder } from "./LambderResponseBuilder.js";
6
6
  export { default as LambderResolver } from "./LambderResolver.js";
7
- export { default as LambderSession } from "./LambderSession.js";
7
+ export { default as LambderSessionManager } from "./LambderSessionManager.js";