lambder 1.0.109 → 1.0.111

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
@@ -82,6 +82,12 @@ 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
+ startSession: (userKey: string, data?: any, ttlInSeconds?: number) => Promise<LambderSessionContext>;
87
+ editSession: (newData: any) => Promise<LambderSessionContext>;
88
+ deleteSession: () => Promise<void>;
89
+ deleteSessionAll: () => Promise<void>;
90
+ };
85
91
  getResponseBuilder(): LambderResponseBuilder;
86
92
  private getResolver;
87
93
  render(event: APIGatewayProxyEvent, lambdaContext: Context): Promise<LambderResolverResponse>;
package/dist/Lambder.js CHANGED
@@ -46,7 +46,7 @@ export default class Lambder {
46
46
  utils;
47
47
  lambderSession;
48
48
  sessionTokenCookieKey = "LMDRSESSIONTKID";
49
- sessionCsrfCookieKey = "LMDRSESSIONCSID";
49
+ sessionCsrfCookieKey = "LMDRSESSIONCSTK";
50
50
  constructor({ publicPath, apiPath, ejsPath, apiVersion }) {
51
51
  this.publicPath = publicPath || "/incorrect-path-not-found";
52
52
  this.ejsPath = ejsPath || "/incorrect-ejs-path-not-found";
@@ -213,6 +213,40 @@ export default class Lambder {
213
213
  this.hookList[hookEvent].sort((a, b) => a.priority - b.priority);
214
214
  }
215
215
  }
216
+ getSessionController(ctx) {
217
+ return {
218
+ startSession: async (userKey, data, ttlInSeconds) => {
219
+ if (!this.lambderSession)
220
+ throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
221
+ ctx.session = await this.lambderSession.createSession(userKey, data, ttlInSeconds);
222
+ return ctx.session;
223
+ },
224
+ editSession: async (newData) => {
225
+ if (!this.lambderSession)
226
+ throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
227
+ if (!ctx.session)
228
+ throw "Session not found.";
229
+ ctx.session = await this.lambderSession.editSession(ctx.session, newData);
230
+ return ctx.session;
231
+ },
232
+ deleteSession: async () => {
233
+ if (!this.lambderSession)
234
+ throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
235
+ if (!ctx.session)
236
+ throw "Session not found.";
237
+ await this.lambderSession.deleteSession(ctx.session);
238
+ ctx.session = null;
239
+ },
240
+ deleteSessionAll: async () => {
241
+ if (!this.lambderSession)
242
+ throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
243
+ if (!ctx.session)
244
+ throw "Session not found.";
245
+ await this.lambderSession.deleteSessionAll(ctx.session);
246
+ ctx.session = null;
247
+ },
248
+ };
249
+ }
216
250
  getResponseBuilder() {
217
251
  return new LambderResponseBuilder({
218
252
  isCorsEnabled: this.isCorsEnabled,
@@ -244,6 +278,7 @@ export default class Lambder {
244
278
  return resolver.cors();
245
279
  const firstMatchedAction = this.actionList.find(action => action.conditionFn(ctx));
246
280
  if (firstMatchedAction) {
281
+ // Run beforeRender hooks
247
282
  for (const hook of this.hookList["beforeRender"]) {
248
283
  const hookCtx = await hook.hookFn(ctx, resolver);
249
284
  if (hookCtx instanceof Error) {
@@ -251,7 +286,9 @@ export default class Lambder {
251
286
  }
252
287
  ctx = hookCtx;
253
288
  }
289
+ // Run matched action
254
290
  let response = await firstMatchedAction.actionFn(ctx, resolver);
291
+ // Run afterRender hooks
255
292
  for (const hook of this.hookList["afterRender"]) {
256
293
  const hookResponse = await hook.hookFn(ctx, resolver, response);
257
294
  if (hookResponse instanceof Error) {
@@ -259,6 +296,29 @@ export default class Lambder {
259
296
  }
260
297
  response = hookResponse;
261
298
  }
299
+ // Apply session cookie if needed.
300
+ if ((ctx.session?.sessionToken ?? null) !== (ctx?.cookie?.[this.sessionTokenCookieKey] ?? null)) {
301
+ // Add session cookies
302
+ if (ctx.session?.sessionToken) {
303
+ response.multiValueHeaders = {
304
+ ...(response.multiValueHeaders || {}),
305
+ "Set-Cookie": [
306
+ `${this.sessionTokenCookieKey}=${ctx.session.sessionToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
307
+ `${this.sessionCsrfCookieKey}=${ctx.session.csrfToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
308
+ ],
309
+ };
310
+ }
311
+ else {
312
+ // Delete session cookies
313
+ response.multiValueHeaders = {
314
+ ...(response.multiValueHeaders || {}),
315
+ "Set-Cookie": [
316
+ `${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
317
+ `${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
318
+ ],
319
+ };
320
+ }
321
+ }
262
322
  resolve(response);
263
323
  }
264
324
  else {
@@ -38,7 +38,7 @@ export default class LambderCaller {
38
38
  activeFetchList: this.fetchTrackerList.filter(v => !v.done)
39
39
  });
40
40
  const version = this.apiVersion;
41
- const token = Cookies.get("LMBDRTOKEN") || "";
41
+ const token = Cookies.get("LMDRSESSIONCSTK") || "";
42
42
  const siteHost = window.location.hostname;
43
43
  let data = await fetch(this.apiPath, {
44
44
  method: 'POST', mode: 'same-origin', cache: 'no-cache',
@@ -28,6 +28,7 @@ export default class LambderSession {
28
28
  private ddbQueryAllByPartitionKey;
29
29
  private ddbDeleteAllByPartitionKey;
30
30
  createSession(userKey: string, data?: any, ttlInSeconds?: number): Promise<LambderSessionContext>;
31
+ editSession(session: LambderSessionContext, newData?: any): Promise<LambderSessionContext>;
31
32
  getSession(sessionToken: string): Promise<LambderSessionContext | null>;
32
33
  isSessionValid(session: any, sessionToken: any, csrfToken: any, skipCsrfTokenCheck?: boolean): boolean;
33
34
  deleteSession(session: Record<string, any>): Promise<boolean>;
@@ -80,6 +80,13 @@ export default class LambderSession {
80
80
  await this.ddbPutItem(session);
81
81
  return session;
82
82
  }
83
+ async editSession(session, newData) {
84
+ if (!session)
85
+ throw "Invalid session";
86
+ session.data = newData;
87
+ await this.ddbPutItem(session);
88
+ return session;
89
+ }
83
90
  async getSession(sessionToken) {
84
91
  const [userKeyHash, sessionSortKey] = sessionToken.split(":");
85
92
  if (!userKeyHash || !sessionSortKey)
package/dist/index.d.ts CHANGED
@@ -3,3 +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";
package/dist/index.js CHANGED
@@ -3,3 +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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambder",
3
- "version": "1.0.109",
3
+ "version": "1.0.111",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/Lambder.ts CHANGED
@@ -92,7 +92,7 @@ export default class Lambder {
92
92
 
93
93
  private lambderSession?: LambderSession;
94
94
  private sessionTokenCookieKey = "LMDRSESSIONTKID";
95
- private sessionCsrfCookieKey = "LMDRSESSIONCSID";
95
+ private sessionCsrfCookieKey = "LMDRSESSIONCSTK";
96
96
 
97
97
  constructor(
98
98
  { publicPath, apiPath, ejsPath, apiVersion }:
@@ -288,6 +288,34 @@ export default class Lambder {
288
288
  }
289
289
  }
290
290
 
291
+ public getSessionController(ctx: LambderRenderContext){
292
+ return {
293
+ startSession: async (userKey: string, data?: any, ttlInSeconds?: number): Promise<LambderSessionContext> => {
294
+ if(!this.lambderSession) throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
295
+ ctx.session = await this.lambderSession.createSession(userKey, data, ttlInSeconds);
296
+ return ctx.session;
297
+ },
298
+ editSession: async (newData: any): Promise<LambderSessionContext> => {
299
+ if(!this.lambderSession) throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
300
+ if(!ctx.session) throw "Session not found.";
301
+ ctx.session = await this.lambderSession.editSession(ctx.session, newData);
302
+ return ctx.session;
303
+ },
304
+ deleteSession: async () => {
305
+ if(!this.lambderSession) throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
306
+ if(!ctx.session) throw "Session not found.";
307
+ await this.lambderSession.deleteSession(ctx.session);
308
+ ctx.session = null
309
+ },
310
+ deleteSessionAll: async () => {
311
+ if(!this.lambderSession) throw "Session is not enabled. Use lambder.enableDdbSession(...) to configure.";
312
+ if(!ctx.session) throw "Session not found.";
313
+ await this.lambderSession.deleteSessionAll(ctx.session);
314
+ ctx.session = null
315
+ },
316
+ }
317
+ }
318
+
291
319
  public getResponseBuilder(){
292
320
  return new LambderResponseBuilder({
293
321
  isCorsEnabled: this.isCorsEnabled,
@@ -328,21 +356,47 @@ export default class Lambder {
328
356
 
329
357
  const firstMatchedAction = this.actionList.find(action => action.conditionFn(ctx));
330
358
  if(firstMatchedAction){
359
+ // Run beforeRender hooks
331
360
  for(const hook of this.hookList["beforeRender"]){
332
361
  const hookCtx = await hook.hookFn(ctx, resolver);
333
362
  if(hookCtx instanceof Error){ throw hookCtx; }
334
363
  ctx = hookCtx;
335
364
  }
365
+ // Run matched action
336
366
  let response = await firstMatchedAction.actionFn(ctx, resolver);
367
+ // Run afterRender hooks
337
368
  for(const hook of this.hookList["afterRender"]){
338
369
  const hookResponse = await hook.hookFn(ctx, resolver, response);
339
370
  if(hookResponse instanceof Error){ throw hookResponse; }
340
371
  response = hookResponse;
341
372
  }
373
+ // Apply session cookie if needed.
374
+ if((ctx.session?.sessionToken ?? null) !== (ctx?.cookie?.[this.sessionTokenCookieKey] ?? null)){
375
+ // Add session cookies
376
+ if(ctx.session?.sessionToken){
377
+ response.multiValueHeaders = {
378
+ ...(response.multiValueHeaders || {}),
379
+ "Set-Cookie": [
380
+ `${this.sessionTokenCookieKey}=${ctx.session.sessionToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
381
+ `${this.sessionCsrfCookieKey}=${ctx.session.csrfToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
382
+ ],
383
+ };
384
+ }else{
385
+ // Delete session cookies
386
+ response.multiValueHeaders = {
387
+ ...(response.multiValueHeaders || {}),
388
+ "Set-Cookie": [
389
+ `${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
390
+ `${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
391
+ ],
392
+ };
393
+ }
394
+ }
342
395
  resolve(response);
343
396
  }else{
344
397
  return this.handleNoMatchedAction(ctx, resolver);
345
398
  }
399
+
346
400
  } catch(err){
347
401
  const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
348
402
  reject(wrappedError);
@@ -101,7 +101,7 @@ export default class LambderCaller {
101
101
  activeFetchList: this.fetchTrackerList.filter(v=>!v.done)
102
102
  });
103
103
  const version = this.apiVersion;
104
- const token = Cookies.get("LMBDRTOKEN") || "";
104
+ const token = Cookies.get("LMDRSESSIONCSTK") || "";
105
105
  const siteHost = window.location.hostname;
106
106
  let data = await fetch(this.apiPath, {
107
107
  method: 'POST', mode: 'same-origin', cache: 'no-cache',
@@ -116,6 +116,16 @@ export default class LambderSession{
116
116
  return session;
117
117
  }
118
118
 
119
+ public async editSession(
120
+ session: LambderSessionContext,
121
+ newData?: any
122
+ ): Promise<LambderSessionContext> {
123
+ if(!session) throw "Invalid session";
124
+ session.data = newData;
125
+ await this.ddbPutItem(session);
126
+ return session;
127
+ }
128
+
119
129
  public async getSession(sessionToken: string): Promise<LambderSessionContext|null>{
120
130
  const [ userKeyHash, sessionSortKey ] = sessionToken.split(":");
121
131
  if(!userKeyHash || !sessionSortKey) return null;
package/src/index.ts CHANGED
@@ -3,4 +3,5 @@ import Lambder from './Lambder.js';
3
3
  export default Lambder;
4
4
  export { default as LambderCaller } from "./LambderCaller.js";
5
5
  export { default as LambderResponseBuilder } from "./LambderResponseBuilder.js";
6
- export { default as LambderResolver } from "./LambderResolver.js";
6
+ export { default as LambderResolver } from "./LambderResolver.js";
7
+ export { default as LambderSession } from "./LambderSession.js";