lambder 1.0.120 → 1.0.122
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 +21 -17
- package/deploy.sh +5 -4
- package/dist/Lambder.d.ts +1 -0
- package/dist/Lambder.js +7 -22
- package/dist/LambderSessionController.d.ts +3 -1
- package/dist/LambderSessionController.js +25 -4
- package/package.json +1 -1
- package/src/Lambder.ts +10 -21
- package/src/LambderSessionController.ts +26 -3
package/Readme.md
CHANGED
|
@@ -37,8 +37,8 @@ const lambder = new Lambder({
|
|
|
37
37
|
|
|
38
38
|
// Enable session
|
|
39
39
|
lambder.enableDdbSession({
|
|
40
|
-
tableName: "website-session",
|
|
41
|
-
tableRegion: "us-east-1",
|
|
40
|
+
tableName: "website-session", // DynamoDB Table Name
|
|
41
|
+
tableRegion: "us-east-1", // DynamoDB Table Region
|
|
42
42
|
sessionSalt: "8p6Vt+4b1w3N8d/dcJ47QF3DRkp9koFg0G" // Change salt
|
|
43
43
|
});
|
|
44
44
|
|
|
@@ -221,13 +221,22 @@ lambder.addModule(async (lambder: Lambder): Promise<void> => {
|
|
|
221
221
|
You can enable session tracking by:
|
|
222
222
|
|
|
223
223
|
```typescript
|
|
224
|
-
// Enable session
|
|
224
|
+
// Enable sessions using a dynamodb session table
|
|
225
225
|
lambder.enableDdbSession({
|
|
226
|
-
tableName: "website-session",
|
|
227
|
-
tableRegion: "us-east-1",
|
|
226
|
+
tableName: "website-session", // DynamoDB Table Name
|
|
227
|
+
tableRegion: "us-east-1", // DynamoDB Table Region
|
|
228
228
|
sessionSalt: "8p6Vt+4b1w3N8d/dcJ47QF3DRkp9koFg0G" // Change salt
|
|
229
229
|
});
|
|
230
230
|
```
|
|
231
|
+
#### DynamoDB Session Table Structure:
|
|
232
|
+
|
|
233
|
+
Session system is enabled by storing data in a DynamoDB session table.
|
|
234
|
+
|
|
235
|
+
- Primary Key: "pk"
|
|
236
|
+
- Sort Key: "sk"
|
|
237
|
+
- TTL Key: "expiresAt" (optional)
|
|
238
|
+
|
|
239
|
+
#### Session Controller
|
|
231
240
|
|
|
232
241
|
After you enable the session, you can access to the session controller:
|
|
233
242
|
|
|
@@ -235,26 +244,26 @@ After you enable the session, you can access to the session controller:
|
|
|
235
244
|
// Create session controller:
|
|
236
245
|
const sessionController = lambder.getSessionController(ctx);
|
|
237
246
|
|
|
238
|
-
|
|
247
|
+
// Type for sessionController
|
|
239
248
|
sessionController: {
|
|
240
|
-
async createSession(sessionKey, data, ttlInSeconds):
|
|
249
|
+
async createSession(sessionKey, data, ttlInSeconds): session
|
|
241
250
|
// Starts a new session and persists the session data to DDB.
|
|
242
251
|
|
|
243
|
-
async fetchSession():
|
|
252
|
+
async fetchSession(): session
|
|
244
253
|
// Fetch and validate if there is an existing session
|
|
245
254
|
// This is automatically done for addSessionRoute and addSessionApi
|
|
246
255
|
// Throws if session not found
|
|
247
256
|
|
|
248
|
-
async fetchSessionIfExists():
|
|
257
|
+
async fetchSessionIfExists(): session|null
|
|
249
258
|
// Runs fetchSession and returns the session if found. Otherwise return null
|
|
250
259
|
|
|
251
|
-
async updateSessionData(updatedData):
|
|
260
|
+
async updateSessionData(updatedData): updatedSession
|
|
252
261
|
// Updates the active sessions data and persist it to ddb.
|
|
253
262
|
|
|
254
|
-
async endSession():
|
|
263
|
+
async endSession():
|
|
255
264
|
// End session and delete from DDB.
|
|
256
265
|
|
|
257
|
-
async endSessionAll():
|
|
266
|
+
async endSessionAll():
|
|
258
267
|
// Ends and deletes all registered sessions for this sessionKey across all devices
|
|
259
268
|
}
|
|
260
269
|
*/
|
|
@@ -474,13 +483,8 @@ const loadPageData = async () => {
|
|
|
474
483
|
console.error("Failed to fetch page data:", error);
|
|
475
484
|
}
|
|
476
485
|
};
|
|
477
|
-
|
|
478
486
|
```
|
|
479
487
|
|
|
480
|
-
## Advanced Configuration
|
|
481
|
-
|
|
482
|
-
Lambder is designed to be flexible and extensible, allowing for customized behaviors through hooks and custom error handling mechanisms.
|
|
483
|
-
|
|
484
488
|
## Contributing
|
|
485
489
|
|
|
486
490
|
Contributions are welcome! Especially for documentation. If you have an idea for an improvement or have found a bug, please open an issue or submit a pull request.
|
package/deploy.sh
CHANGED
package/dist/Lambder.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export type LambderRenderContext = {
|
|
|
20
20
|
lambdaContext: Context;
|
|
21
21
|
_otherInternal: {
|
|
22
22
|
isApiCall: boolean;
|
|
23
|
+
sessionCookieHeader: null | Record<"Set-Cookie", string[]>;
|
|
23
24
|
};
|
|
24
25
|
};
|
|
25
26
|
type LambderModuleFunction = (lambderInstance: Lambder) => void | Promise<void>;
|
package/dist/Lambder.js
CHANGED
|
@@ -36,7 +36,7 @@ export const createContext = (event, lambdaContext, apiPath) => {
|
|
|
36
36
|
get, post, cookie,
|
|
37
37
|
apiName, apiPayload,
|
|
38
38
|
headers, session, lambdaContext,
|
|
39
|
-
_otherInternal: { isApiCall }
|
|
39
|
+
_otherInternal: { isApiCall, sessionCookieHeader: null }
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
export default class Lambder {
|
|
@@ -194,6 +194,7 @@ export default class Lambder {
|
|
|
194
194
|
return new LambderSessionController({
|
|
195
195
|
lambderSessionManager: this.lambderSessionManager,
|
|
196
196
|
sessionTokenCookieKey: this.sessionTokenCookieKey,
|
|
197
|
+
sessionCsrfCookieKey: this.sessionCsrfCookieKey,
|
|
197
198
|
ctx,
|
|
198
199
|
});
|
|
199
200
|
}
|
|
@@ -247,27 +248,11 @@ export default class Lambder {
|
|
|
247
248
|
response = hookResponse;
|
|
248
249
|
}
|
|
249
250
|
// Apply session cookie if needed.
|
|
250
|
-
if ((ctx.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"Set-Cookie": [
|
|
256
|
-
`${this.sessionTokenCookieKey}=${ctx.session.sessionToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
257
|
-
`${this.sessionCsrfCookieKey}=${ctx.session.csrfToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
258
|
-
],
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
// Delete session cookies
|
|
263
|
-
response.multiValueHeaders = {
|
|
264
|
-
...(response.multiValueHeaders || {}),
|
|
265
|
-
"Set-Cookie": [
|
|
266
|
-
`${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
267
|
-
`${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
268
|
-
],
|
|
269
|
-
};
|
|
270
|
-
}
|
|
251
|
+
if ((ctx._otherInternal.sessionCookieHeader)) {
|
|
252
|
+
response.multiValueHeaders = {
|
|
253
|
+
...(response.multiValueHeaders || {}),
|
|
254
|
+
...(ctx._otherInternal.sessionCookieHeader || {}),
|
|
255
|
+
};
|
|
271
256
|
}
|
|
272
257
|
resolve(response);
|
|
273
258
|
}
|
|
@@ -4,10 +4,12 @@ import type { LambderSessionContext } from "./LambderSessionManager.js";
|
|
|
4
4
|
export default class LambderSessionController {
|
|
5
5
|
lambderSessionManager: LambderSessionManager;
|
|
6
6
|
sessionTokenCookieKey: string;
|
|
7
|
+
sessionCsrfCookieKey: string;
|
|
7
8
|
ctx: LambderRenderContext;
|
|
8
|
-
constructor({ lambderSessionManager, sessionTokenCookieKey, ctx, }: {
|
|
9
|
+
constructor({ lambderSessionManager, sessionTokenCookieKey, sessionCsrfCookieKey, ctx, }: {
|
|
9
10
|
lambderSessionManager: LambderSessionManager;
|
|
10
11
|
sessionTokenCookieKey: string;
|
|
12
|
+
sessionCsrfCookieKey: string;
|
|
11
13
|
ctx: LambderRenderContext;
|
|
12
14
|
});
|
|
13
15
|
private areRequestSessionTokensValid;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export default class LambderSessionController {
|
|
2
2
|
lambderSessionManager;
|
|
3
3
|
sessionTokenCookieKey;
|
|
4
|
+
sessionCsrfCookieKey;
|
|
4
5
|
ctx;
|
|
5
|
-
constructor({ lambderSessionManager, sessionTokenCookieKey, ctx, }) {
|
|
6
|
-
this.ctx = ctx;
|
|
7
|
-
this.sessionTokenCookieKey = sessionTokenCookieKey;
|
|
6
|
+
constructor({ lambderSessionManager, sessionTokenCookieKey, sessionCsrfCookieKey, ctx, }) {
|
|
8
7
|
this.lambderSessionManager = lambderSessionManager;
|
|
8
|
+
this.sessionTokenCookieKey = sessionTokenCookieKey;
|
|
9
|
+
this.sessionCsrfCookieKey = sessionCsrfCookieKey;
|
|
10
|
+
this.ctx = ctx;
|
|
9
11
|
}
|
|
10
12
|
;
|
|
11
13
|
areRequestSessionTokensValid() {
|
|
@@ -22,7 +24,14 @@ export default class LambderSessionController {
|
|
|
22
24
|
}
|
|
23
25
|
;
|
|
24
26
|
async createSession(sessionKey, data, ttlInSeconds) {
|
|
25
|
-
|
|
27
|
+
const session = await this.lambderSessionManager.createSession(sessionKey, data, ttlInSeconds);
|
|
28
|
+
this.ctx._otherInternal.sessionCookieHeader = {
|
|
29
|
+
"Set-Cookie": [
|
|
30
|
+
`${this.sessionTokenCookieKey}=${session.sessionToken}; Expires=${new Date(session.expiresAt * 1000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
31
|
+
`${this.sessionCsrfCookieKey}=${session.csrfToken}; Expires=${new Date(session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
this.ctx.session = session;
|
|
26
35
|
return this.ctx.session;
|
|
27
36
|
}
|
|
28
37
|
;
|
|
@@ -74,6 +83,12 @@ export default class LambderSessionController {
|
|
|
74
83
|
if (!this.ctx.session)
|
|
75
84
|
throw new Error("Session not found.");
|
|
76
85
|
await this.lambderSessionManager.deleteSession(this.ctx.session);
|
|
86
|
+
this.ctx._otherInternal.sessionCookieHeader = {
|
|
87
|
+
"Set-Cookie": [
|
|
88
|
+
`${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
89
|
+
`${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
90
|
+
],
|
|
91
|
+
};
|
|
77
92
|
this.ctx.session = null;
|
|
78
93
|
}
|
|
79
94
|
;
|
|
@@ -81,6 +96,12 @@ export default class LambderSessionController {
|
|
|
81
96
|
if (!this.ctx.session)
|
|
82
97
|
throw new Error("Session not found.");
|
|
83
98
|
await this.lambderSessionManager.deleteSessionAll(this.ctx.session);
|
|
99
|
+
this.ctx._otherInternal.sessionCookieHeader = {
|
|
100
|
+
"Set-Cookie": [
|
|
101
|
+
`${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
102
|
+
`${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
103
|
+
],
|
|
104
|
+
};
|
|
84
105
|
this.ctx.session = null;
|
|
85
106
|
}
|
|
86
107
|
;
|
package/package.json
CHANGED
package/src/Lambder.ts
CHANGED
|
@@ -24,7 +24,10 @@ export type LambderRenderContext = {
|
|
|
24
24
|
headers: APIGatewayProxyEventHeaders;
|
|
25
25
|
session: LambderSessionContext|null;
|
|
26
26
|
lambdaContext: Context;
|
|
27
|
-
_otherInternal: {
|
|
27
|
+
_otherInternal: {
|
|
28
|
+
isApiCall: boolean,
|
|
29
|
+
sessionCookieHeader: null|Record<"Set-Cookie",string[]>
|
|
30
|
+
};
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
type LambderModuleFunction = (lambderInstance: Lambder) => void | Promise<void>;
|
|
@@ -76,7 +79,7 @@ export const createContext = (
|
|
|
76
79
|
get, post, cookie,
|
|
77
80
|
apiName, apiPayload,
|
|
78
81
|
headers, session, lambdaContext,
|
|
79
|
-
_otherInternal: { isApiCall }
|
|
82
|
+
_otherInternal: { isApiCall, sessionCookieHeader: null }
|
|
80
83
|
};
|
|
81
84
|
}
|
|
82
85
|
|
|
@@ -279,6 +282,7 @@ export default class Lambder {
|
|
|
279
282
|
return new LambderSessionController({
|
|
280
283
|
lambderSessionManager: this.lambderSessionManager,
|
|
281
284
|
sessionTokenCookieKey: this.sessionTokenCookieKey,
|
|
285
|
+
sessionCsrfCookieKey: this.sessionCsrfCookieKey,
|
|
282
286
|
ctx,
|
|
283
287
|
});
|
|
284
288
|
}
|
|
@@ -338,25 +342,10 @@ export default class Lambder {
|
|
|
338
342
|
response = hookResponse;
|
|
339
343
|
}
|
|
340
344
|
// Apply session cookie if needed.
|
|
341
|
-
if((ctx.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
...(response.multiValueHeaders || {}),
|
|
346
|
-
"Set-Cookie": [
|
|
347
|
-
`${this.sessionTokenCookieKey}=${ctx.session.sessionToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
348
|
-
`${this.sessionCsrfCookieKey}=${ctx.session.csrfToken}; Expires=${new Date(ctx.session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
349
|
-
],
|
|
350
|
-
};
|
|
351
|
-
}else{
|
|
352
|
-
// Delete session cookies
|
|
353
|
-
response.multiValueHeaders = {
|
|
354
|
-
...(response.multiValueHeaders || {}),
|
|
355
|
-
"Set-Cookie": [
|
|
356
|
-
`${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
357
|
-
`${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
358
|
-
],
|
|
359
|
-
};
|
|
345
|
+
if((ctx._otherInternal.sessionCookieHeader)){
|
|
346
|
+
response.multiValueHeaders = {
|
|
347
|
+
...(response.multiValueHeaders || {}),
|
|
348
|
+
...(ctx._otherInternal.sessionCookieHeader || {}),
|
|
360
349
|
}
|
|
361
350
|
}
|
|
362
351
|
resolve(response);
|
|
@@ -5,22 +5,26 @@ import type { LambderSessionContext } from "./LambderSessionManager.js";
|
|
|
5
5
|
export default class LambderSessionController {
|
|
6
6
|
lambderSessionManager: LambderSessionManager;
|
|
7
7
|
sessionTokenCookieKey: string;
|
|
8
|
+
sessionCsrfCookieKey: string;
|
|
8
9
|
ctx: LambderRenderContext;
|
|
9
10
|
|
|
10
11
|
constructor(
|
|
11
12
|
{
|
|
12
13
|
lambderSessionManager,
|
|
13
14
|
sessionTokenCookieKey,
|
|
15
|
+
sessionCsrfCookieKey,
|
|
14
16
|
ctx,
|
|
15
17
|
}: {
|
|
16
18
|
lambderSessionManager: LambderSessionManager,
|
|
17
19
|
sessionTokenCookieKey: string,
|
|
20
|
+
sessionCsrfCookieKey: string,
|
|
18
21
|
ctx: LambderRenderContext,
|
|
19
22
|
}
|
|
20
23
|
){
|
|
21
|
-
this.ctx = ctx;
|
|
22
|
-
this.sessionTokenCookieKey = sessionTokenCookieKey;
|
|
23
24
|
this.lambderSessionManager = lambderSessionManager;
|
|
25
|
+
this.sessionTokenCookieKey = sessionTokenCookieKey;
|
|
26
|
+
this.sessionCsrfCookieKey = sessionCsrfCookieKey;
|
|
27
|
+
this.ctx = ctx;
|
|
24
28
|
};
|
|
25
29
|
|
|
26
30
|
private areRequestSessionTokensValid(): boolean {
|
|
@@ -37,7 +41,14 @@ export default class LambderSessionController {
|
|
|
37
41
|
};
|
|
38
42
|
|
|
39
43
|
async createSession (sessionKey: string, data?: any, ttlInSeconds?: number): Promise<LambderSessionContext> {
|
|
40
|
-
|
|
44
|
+
const session = await this.lambderSessionManager.createSession(sessionKey, data, ttlInSeconds);
|
|
45
|
+
this.ctx._otherInternal.sessionCookieHeader = {
|
|
46
|
+
"Set-Cookie": [
|
|
47
|
+
`${this.sessionTokenCookieKey}=${session.sessionToken}; Expires=${new Date(session.expiresAt * 1000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
48
|
+
`${this.sessionCsrfCookieKey}=${session.csrfToken}; Expires=${new Date(session.expiresAt * 1000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
this.ctx.session = session;
|
|
41
52
|
return this.ctx.session;
|
|
42
53
|
};
|
|
43
54
|
|
|
@@ -83,12 +94,24 @@ export default class LambderSessionController {
|
|
|
83
94
|
async endSession (){
|
|
84
95
|
if(!this.ctx.session) throw new Error("Session not found.");
|
|
85
96
|
await this.lambderSessionManager.deleteSession(this.ctx.session);
|
|
97
|
+
this.ctx._otherInternal.sessionCookieHeader = {
|
|
98
|
+
"Set-Cookie": [
|
|
99
|
+
`${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
100
|
+
`${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
101
|
+
],
|
|
102
|
+
};
|
|
86
103
|
this.ctx.session = null
|
|
87
104
|
};
|
|
88
105
|
|
|
89
106
|
async endSessionAll (){
|
|
90
107
|
if(!this.ctx.session) throw new Error("Session not found.");
|
|
91
108
|
await this.lambderSessionManager.deleteSessionAll(this.ctx.session);
|
|
109
|
+
this.ctx._otherInternal.sessionCookieHeader = {
|
|
110
|
+
"Set-Cookie": [
|
|
111
|
+
`${this.sessionTokenCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; HttpOnly; SameSite=Lax; Secure`,
|
|
112
|
+
`${this.sessionCsrfCookieKey}=0; Expires=${new Date(Date.now() - 100000).toUTCString()}; Path=/; SameSite=Lax; Secure`,
|
|
113
|
+
],
|
|
114
|
+
};
|
|
92
115
|
this.ctx.session = null
|
|
93
116
|
};
|
|
94
117
|
};
|