lambder 1.0.14 → 1.0.16
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/.vscode/settings.json +5 -2
- package/dist/Resolver.d.ts +1 -1
- package/dist/Resolver.js +17 -16
- package/dist/index.d.ts +16 -4
- package/dist/index.js +50 -52
- package/package.json +1 -1
- package/src/Resolver.ts +18 -17
- package/src/index.ts +71 -52
package/.vscode/settings.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"editor.codeActionsOnSave": {
|
|
3
|
-
"source.fixAll.eslint":
|
|
3
|
+
"source.fixAll.eslint": "explicit"
|
|
4
4
|
},
|
|
5
5
|
"eslint.validate": [
|
|
6
6
|
"javascript",
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"**/dist/": true,
|
|
17
17
|
"**/package-lock.json": true,
|
|
18
18
|
"**/.git/": true,
|
|
19
|
-
|
|
19
|
+
},
|
|
20
|
+
"cSpell.words": [
|
|
21
|
+
"lambder"
|
|
22
|
+
],
|
|
20
23
|
}
|
|
21
24
|
|
package/dist/Resolver.d.ts
CHANGED
|
@@ -52,7 +52,7 @@ export default class Resolver {
|
|
|
52
52
|
private apiVersion;
|
|
53
53
|
resolve: Function;
|
|
54
54
|
reject: Function;
|
|
55
|
-
die:
|
|
55
|
+
die: IResolverMethods;
|
|
56
56
|
constructor({ isCorsEnabled, publicPath, apiVersion, resolve, reject }: {
|
|
57
57
|
isCorsEnabled: boolean;
|
|
58
58
|
publicPath: string;
|
package/dist/Resolver.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as path from "path";
|
|
3
3
|
import mimeTypeResolver from "mime-types";
|
|
4
4
|
const convertToMultiHeader = (headers) => Object.fromEntries(Object.entries(headers || {}).map(([k, v]) => [k, Array.isArray(v) ? v : [v]]));
|
|
5
5
|
const CORS_HEADERS = convertToMultiHeader({
|
|
@@ -21,22 +21,23 @@ export default class Resolver {
|
|
|
21
21
|
this.apiVersion = apiVersion ?? null;
|
|
22
22
|
this.resolve = resolve;
|
|
23
23
|
this.reject = reject;
|
|
24
|
-
this.die =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
this.die = {
|
|
25
|
+
raw: this.raw,
|
|
26
|
+
json: this.json,
|
|
27
|
+
xml: this.xml,
|
|
28
|
+
html: this.html,
|
|
29
|
+
status301: this.status301,
|
|
30
|
+
status404: this.status404,
|
|
31
|
+
cors: this.cors,
|
|
32
|
+
fileBase64: this.fileBase64,
|
|
33
|
+
file: this.file,
|
|
34
|
+
api: this.api,
|
|
35
|
+
};
|
|
35
36
|
}
|
|
36
37
|
;
|
|
37
38
|
readFileSync(filePath) {
|
|
38
|
-
const publicPath =
|
|
39
|
-
const absolutePath =
|
|
39
|
+
const publicPath = path.resolve(this.publicPath);
|
|
40
|
+
const absolutePath = path.join(publicPath, filePath);
|
|
40
41
|
console.log("readFileSync", { filePath, publicPath, absolutePath });
|
|
41
42
|
if (!absolutePath.includes(publicPath)) {
|
|
42
43
|
return "forbiddenpath";
|
|
@@ -45,8 +46,8 @@ export default class Resolver {
|
|
|
45
46
|
}
|
|
46
47
|
;
|
|
47
48
|
checkFileExist(filePath) {
|
|
48
|
-
const publicPath =
|
|
49
|
-
const absolutePath =
|
|
49
|
+
const publicPath = path.resolve(this.publicPath);
|
|
50
|
+
const absolutePath = path.join(this.publicPath, filePath);
|
|
50
51
|
console.log("checkFileExist", { filePath, publicPath, absolutePath });
|
|
51
52
|
if (!absolutePath.includes(publicPath)) {
|
|
52
53
|
return false;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from "aws-lambda";
|
|
2
2
|
import Resolver, { ResolverResponse } from "./Resolver.js";
|
|
3
|
+
type DDBSession = {
|
|
4
|
+
userId: string;
|
|
5
|
+
userIdHash: string;
|
|
6
|
+
sessionHash: string;
|
|
7
|
+
csrfToken: string;
|
|
8
|
+
createdTimeStamp: number;
|
|
9
|
+
expiresTimeStamp: number;
|
|
10
|
+
data: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
} | null;
|
|
3
14
|
type RenderContext = {
|
|
4
15
|
host: string;
|
|
5
16
|
url: string;
|
|
@@ -14,6 +25,7 @@ type RenderContext = {
|
|
|
14
25
|
[key: string]: any;
|
|
15
26
|
};
|
|
16
27
|
headers: APIGatewayProxyEventHeaders;
|
|
28
|
+
session: DDBSession;
|
|
17
29
|
lambdaContext: Context;
|
|
18
30
|
};
|
|
19
31
|
type ConditionFunction = (renderContext: RenderContext) => boolean | Promise<boolean>;
|
|
@@ -39,18 +51,18 @@ export default class Lambder {
|
|
|
39
51
|
apiVersion?: string;
|
|
40
52
|
isCorsEnabled?: boolean;
|
|
41
53
|
});
|
|
42
|
-
private apiHandler;
|
|
43
|
-
private pathHandler;
|
|
44
54
|
setFallbackHandler(fallbackHandler: (renderContext: RenderContext, resolver: Resolver) => ResolverResponse): void;
|
|
45
55
|
setGlobalErrorHandler(globalErrorHandler: (err: Error) => ResolverResponse): void;
|
|
46
|
-
|
|
56
|
+
addModule(moduleFn: Function): Promise<void>;
|
|
57
|
+
private validateSession;
|
|
47
58
|
addPath(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
|
|
59
|
+
addPublicApi(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
|
|
60
|
+
addSessionApi(condition: string | ConditionFunction | RegExp, actionFn: ActionFunction): void;
|
|
48
61
|
addHook(hookEvent: 'created', hookFn: HookCreatedFunction, priority?: number): Promise<void>;
|
|
49
62
|
addHook(hookEvent: 'beforeRender', hookFn: HookBeforeRenderFunction, priority?: number): Promise<void>;
|
|
50
63
|
addHook(hookEvent: 'afterRender', hookFn: HookAfterRenderFunction, priority?: number): Promise<void>;
|
|
51
64
|
addHook(hookEvent: 'fallback', hookFn: HookFallbackFunction, priority?: number): Promise<void>;
|
|
52
65
|
addHook(hookEvent: 'completed', hookFn: HookCompletedFunction, priority?: number): Promise<void>;
|
|
53
|
-
addModule(moduleFn: Function): Promise<void>;
|
|
54
66
|
render(event: APIGatewayProxyEvent, lambdaContext: Context): Promise<ResolverResponse>;
|
|
55
67
|
}
|
|
56
68
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export const createContext = (event, lambdaContext, resolve, reject) => {
|
|
|
9
9
|
const cookie = cookieParser.parse(event.headers.Cookie || event.headers.cookie || "");
|
|
10
10
|
const headers = event.headers;
|
|
11
11
|
let post = {};
|
|
12
|
+
const session = null;
|
|
12
13
|
try {
|
|
13
14
|
const decodedBody = event.isBase64Encoded ? (event.body ? Buffer.from(event.body, "base64").toString() : "{}") : (event.body || "{}");
|
|
14
15
|
try {
|
|
@@ -22,7 +23,7 @@ export const createContext = (event, lambdaContext, resolve, reject) => {
|
|
|
22
23
|
if (/^(((\d+\.)+\d+)|(([a-f\d]+:)+[a-f\d]+))$/.test(host)) {
|
|
23
24
|
reject(new Error("[404] Host cannot be an ip address: " + host));
|
|
24
25
|
}
|
|
25
|
-
return { host, url, method, get, post, cookie, headers, lambdaContext };
|
|
26
|
+
return { host, url, method, get, post, cookie, headers, session, lambdaContext };
|
|
26
27
|
};
|
|
27
28
|
export default class Lambder {
|
|
28
29
|
apiPath;
|
|
@@ -46,56 +47,57 @@ export default class Lambder {
|
|
|
46
47
|
"completed": []
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
|
-
async apiHandler(renderContext, resolver, actionFn) {
|
|
50
|
-
// Do context stuff;
|
|
51
|
-
return await actionFn(renderContext, resolver);
|
|
52
|
-
}
|
|
53
|
-
async pathHandler(renderContext, resolver, actionFn) {
|
|
54
|
-
// Do context stuff;
|
|
55
|
-
return await actionFn(renderContext, resolver);
|
|
56
|
-
}
|
|
57
50
|
setFallbackHandler(fallbackHandler) {
|
|
58
51
|
this.fallbackHandler = fallbackHandler;
|
|
59
52
|
}
|
|
60
53
|
setGlobalErrorHandler(globalErrorHandler) {
|
|
61
54
|
this.globalErrorHandler = globalErrorHandler;
|
|
62
55
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
56
|
+
async addModule(moduleFn) {
|
|
57
|
+
await moduleFn(this);
|
|
58
|
+
}
|
|
59
|
+
async validateSession(session) {
|
|
60
|
+
if (!session)
|
|
61
|
+
return false;
|
|
62
|
+
if (!session.userId || !session.userIdHash || !session.sessionHash || !session.csrfToken)
|
|
63
|
+
return false;
|
|
64
|
+
if (!session.createdTimeStamp || !session.expiresTimeStamp)
|
|
65
|
+
return false;
|
|
66
|
+
if (session.expiresTimeStamp > Date.now())
|
|
67
|
+
return false;
|
|
68
|
+
// Check DDB;
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
addPath(condition, actionFn) {
|
|
77
72
|
this._actionList.push({
|
|
78
|
-
conditionFn
|
|
79
|
-
|
|
73
|
+
conditionFn: async (renderContext) => (renderContext.method === "GET" &&
|
|
74
|
+
((typeof condition === "string" && renderContext.url === condition) ||
|
|
75
|
+
(typeof condition === "function" && (await condition(renderContext))) ||
|
|
76
|
+
(condition?.constructor == RegExp && condition.test(renderContext.url)))),
|
|
77
|
+
actionFn: async (renderContext, resolver) => await actionFn(renderContext, resolver)
|
|
80
78
|
});
|
|
81
79
|
}
|
|
82
|
-
|
|
83
|
-
let conditionFn = (renderContext) => false;
|
|
84
|
-
if (typeof condition === "string") {
|
|
85
|
-
conditionFn = (renderContext) => renderContext.method === "GET" && renderContext.url === condition;
|
|
86
|
-
}
|
|
87
|
-
else if (typeof condition === "function") {
|
|
88
|
-
conditionFn = async (renderContext) => renderContext.method === "GET" && (await condition(renderContext));
|
|
89
|
-
}
|
|
90
|
-
else if (condition?.constructor == RegExp) {
|
|
91
|
-
conditionFn = (renderContext) => renderContext.method === "GET" && condition.test(renderContext.url);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
throw "Unsupported Path Condition";
|
|
95
|
-
}
|
|
80
|
+
addPublicApi(condition, actionFn) {
|
|
96
81
|
this._actionList.push({
|
|
97
|
-
conditionFn
|
|
98
|
-
|
|
82
|
+
conditionFn: async (renderContext) => (renderContext.method === "POST" && renderContext.url === this.apiPath &&
|
|
83
|
+
((typeof condition === "string" && renderContext.post?.api === condition) ||
|
|
84
|
+
(typeof condition === "function" && (await condition(renderContext))) ||
|
|
85
|
+
(condition?.constructor == RegExp && condition.test(renderContext.post?.api)))),
|
|
86
|
+
actionFn: async (renderContext, resolver) => await actionFn(renderContext, resolver)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
addSessionApi(condition, actionFn) {
|
|
90
|
+
this._actionList.push({
|
|
91
|
+
conditionFn: async (renderContext) => (renderContext.method === "POST" && renderContext.url === this.apiPath &&
|
|
92
|
+
((typeof condition === "string" && renderContext.post?.api === condition) ||
|
|
93
|
+
(typeof condition === "function" && (await condition(renderContext))) ||
|
|
94
|
+
(condition?.constructor == RegExp && condition.test(renderContext.post?.api)))),
|
|
95
|
+
actionFn: async (renderContext, resolver) => {
|
|
96
|
+
const isSessionValid = this.validateSession(renderContext.session);
|
|
97
|
+
if (!isSessionValid)
|
|
98
|
+
throw new Error("Session not found");
|
|
99
|
+
return await actionFn(renderContext, resolver);
|
|
100
|
+
}
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
103
|
async addHook(hookEvent, hookFn, priority = 0) {
|
|
@@ -107,9 +109,6 @@ export default class Lambder {
|
|
|
107
109
|
this._hookList[hookEvent].sort((a, b) => a.priority - b.priority);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
|
-
async addModule(moduleFn) {
|
|
111
|
-
await moduleFn(this);
|
|
112
|
-
}
|
|
113
112
|
async render(event, lambdaContext) {
|
|
114
113
|
return await new Promise(async (resolve, reject) => {
|
|
115
114
|
const resolver = new Resolver({
|
|
@@ -121,14 +120,12 @@ export default class Lambder {
|
|
|
121
120
|
let renderContext = createContext(event, lambdaContext, resolve, reject);
|
|
122
121
|
if (renderContext.method === "OPTIONS")
|
|
123
122
|
return resolver.cors();
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
firstMatchedAction = action;
|
|
129
|
-
break;
|
|
123
|
+
const firstMatchedAction = await (async () => {
|
|
124
|
+
for (const action of this._actionList) {
|
|
125
|
+
if (await action.conditionFn(renderContext))
|
|
126
|
+
return action;
|
|
130
127
|
}
|
|
131
|
-
}
|
|
128
|
+
})();
|
|
132
129
|
if (firstMatchedAction) {
|
|
133
130
|
for (const hook of this._hookList["beforeRender"]) {
|
|
134
131
|
renderContext = await hook.hookFn(renderContext, resolver);
|
|
@@ -140,8 +137,9 @@ export default class Lambder {
|
|
|
140
137
|
resolve(renderResult);
|
|
141
138
|
}
|
|
142
139
|
else {
|
|
143
|
-
for (const hook of this._hookList["fallback"])
|
|
140
|
+
for (const hook of this._hookList["fallback"]) {
|
|
144
141
|
await hook.hookFn(renderContext, resolver);
|
|
142
|
+
}
|
|
145
143
|
if (this.fallbackHandler) {
|
|
146
144
|
const renderResult = await this.fallbackHandler(renderContext, resolver);
|
|
147
145
|
resolve(renderResult);
|
package/package.json
CHANGED
package/src/Resolver.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as path from "path";
|
|
3
3
|
import mimeTypeResolver from "mime-types";
|
|
4
4
|
|
|
5
5
|
const convertToMultiHeader = (
|
|
@@ -49,7 +49,7 @@ export default class Resolver {
|
|
|
49
49
|
private apiVersion: string|null;
|
|
50
50
|
resolve: Function;
|
|
51
51
|
reject: Function;
|
|
52
|
-
die:
|
|
52
|
+
die: IResolverMethods;
|
|
53
53
|
|
|
54
54
|
constructor(
|
|
55
55
|
{ isCorsEnabled, publicPath, apiVersion, resolve, reject }:
|
|
@@ -66,30 +66,31 @@ export default class Resolver {
|
|
|
66
66
|
this.apiVersion = apiVersion ?? null;
|
|
67
67
|
this.resolve = resolve;
|
|
68
68
|
this.reject = reject;
|
|
69
|
-
this.die =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
this.die = {
|
|
70
|
+
raw: this.raw,
|
|
71
|
+
json: this.json,
|
|
72
|
+
xml: this.xml,
|
|
73
|
+
html: this.html,
|
|
74
|
+
status301: this.status301,
|
|
75
|
+
status404: this.status404,
|
|
76
|
+
cors: this.cors,
|
|
77
|
+
fileBase64: this.fileBase64,
|
|
78
|
+
file: this.file,
|
|
79
|
+
api: this.api,
|
|
80
|
+
}
|
|
80
81
|
};
|
|
81
82
|
|
|
82
83
|
private readFileSync(filePath: string){
|
|
83
|
-
const publicPath =
|
|
84
|
-
const absolutePath =
|
|
84
|
+
const publicPath = path.resolve(this.publicPath);
|
|
85
|
+
const absolutePath = path.join(publicPath, filePath);
|
|
85
86
|
console.log("readFileSync", { filePath, publicPath, absolutePath });
|
|
86
87
|
if(!absolutePath.includes(publicPath)){ return "forbiddenpath"; }
|
|
87
88
|
return fs.readFileSync(absolutePath);
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
private checkFileExist(filePath: string){
|
|
91
|
-
const publicPath =
|
|
92
|
-
const absolutePath =
|
|
92
|
+
const publicPath = path.resolve(this.publicPath);
|
|
93
|
+
const absolutePath = path.join(this.publicPath, filePath);
|
|
93
94
|
console.log("checkFileExist", { filePath, publicPath, absolutePath });
|
|
94
95
|
if(!absolutePath.includes(publicPath)){ return false; }
|
|
95
96
|
return fs.existsSync(absolutePath) && fs.statSync(absolutePath).isFile();
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,16 @@ 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
|
+
type DDBSession = {
|
|
8
|
+
userId: string,
|
|
9
|
+
userIdHash: string;
|
|
10
|
+
sessionHash: string;
|
|
11
|
+
csrfToken: string;
|
|
12
|
+
createdTimeStamp: number;
|
|
13
|
+
expiresTimeStamp: number;
|
|
14
|
+
data: { [key:string]: any };
|
|
15
|
+
} | null;
|
|
16
|
+
|
|
7
17
|
type RenderContext = {
|
|
8
18
|
host: string;
|
|
9
19
|
url: string;
|
|
@@ -12,6 +22,7 @@ type RenderContext = {
|
|
|
12
22
|
post: { [key: string]: any };
|
|
13
23
|
cookie: { [key: string]: any };
|
|
14
24
|
headers: APIGatewayProxyEventHeaders;
|
|
25
|
+
session: DDBSession;
|
|
15
26
|
lambdaContext: Context;
|
|
16
27
|
};
|
|
17
28
|
|
|
@@ -44,13 +55,14 @@ export const createContext = (
|
|
|
44
55
|
const cookie = cookieParser.parse(event.headers.Cookie || event.headers.cookie || "");
|
|
45
56
|
const headers = event.headers;
|
|
46
57
|
let post:{ [key:string]: any } = {};
|
|
58
|
+
const session = null;
|
|
47
59
|
try {
|
|
48
60
|
const decodedBody = event.isBase64Encoded ? ( event.body ? Buffer.from(event.body,"base64").toString() : "{}" ) : ( event.body || "{}" );
|
|
49
61
|
try { post = JSON.parse(decodedBody) || {}; }
|
|
50
62
|
catch(e){ post = querystring.parse(decodedBody) || {}; }
|
|
51
63
|
}catch(e){}
|
|
52
64
|
if(/^(((\d+\.)+\d+)|(([a-f\d]+:)+[a-f\d]+))$/.test(host)){ reject(new Error("[404] Host cannot be an ip address: " + host)); }
|
|
53
|
-
return { host, url, method, get, post, cookie, headers, lambdaContext };
|
|
65
|
+
return { host, url, method, get, post, cookie, headers, session, lambdaContext };
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
|
|
@@ -88,14 +100,6 @@ export default class Lambder {
|
|
|
88
100
|
};
|
|
89
101
|
}
|
|
90
102
|
|
|
91
|
-
private async apiHandler (renderContext:RenderContext, resolver: Resolver, actionFn: ActionFunction){
|
|
92
|
-
// Do context stuff;
|
|
93
|
-
return await actionFn(renderContext, resolver);
|
|
94
|
-
}
|
|
95
|
-
private async pathHandler (renderContext:RenderContext, resolver: Resolver, actionFn: ActionFunction){
|
|
96
|
-
// Do context stuff;
|
|
97
|
-
return await actionFn(renderContext, resolver);
|
|
98
|
-
}
|
|
99
103
|
setFallbackHandler(fallbackHandler: (renderContext:RenderContext, resolver: Resolver)=>ResolverResponse){
|
|
100
104
|
this.fallbackHandler = fallbackHandler;
|
|
101
105
|
}
|
|
@@ -103,42 +107,64 @@ export default class Lambder {
|
|
|
103
107
|
this.globalErrorHandler = globalErrorHandler;
|
|
104
108
|
}
|
|
105
109
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}else { throw "Unsupported API Condition"; }
|
|
118
|
-
this._actionList.push({
|
|
119
|
-
conditionFn,
|
|
120
|
-
actionFn: async (renderContext:RenderContext, resolver: Resolver) => await this.apiHandler(renderContext, resolver, actionFn)
|
|
121
|
-
});
|
|
110
|
+
async addModule(moduleFn: Function): Promise<void>{
|
|
111
|
+
await moduleFn(this);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private async validateSession (session: DDBSession): Promise<boolean>{
|
|
115
|
+
if(!session) return false;
|
|
116
|
+
if(!session.userId || !session.userIdHash || !session.sessionHash || !session.csrfToken) return false;
|
|
117
|
+
if(!session.createdTimeStamp || !session.expiresTimeStamp) return false;
|
|
118
|
+
if(session.expiresTimeStamp > Date.now()) return false;
|
|
119
|
+
// Check DDB;
|
|
120
|
+
return false;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
addPath(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
|
|
125
|
-
let conditionFn: ConditionFunction = (renderContext:RenderContext) => false;
|
|
126
|
-
if(typeof condition === "string"){
|
|
127
|
-
conditionFn = (renderContext:RenderContext) =>
|
|
128
|
-
renderContext.method === "GET" && renderContext.url === condition;
|
|
129
|
-
}else if(typeof condition === "function"){
|
|
130
|
-
conditionFn = async (renderContext:RenderContext) =>
|
|
131
|
-
renderContext.method === "GET" && (await condition(renderContext));
|
|
132
|
-
}else if(condition?.constructor == RegExp){
|
|
133
|
-
conditionFn = (renderContext:RenderContext) =>
|
|
134
|
-
renderContext.method === "GET" && condition.test(renderContext.url);
|
|
135
|
-
}else { throw "Unsupported Path Condition"; }
|
|
136
124
|
this._actionList.push({
|
|
137
|
-
conditionFn
|
|
138
|
-
|
|
125
|
+
conditionFn: async (renderContext:RenderContext) => (
|
|
126
|
+
renderContext.method === "GET" &&
|
|
127
|
+
(
|
|
128
|
+
(typeof condition === "string" && renderContext.url === condition) ||
|
|
129
|
+
(typeof condition === "function" && (await condition(renderContext))) ||
|
|
130
|
+
(condition?.constructor == RegExp && condition.test(renderContext.url))
|
|
131
|
+
)
|
|
132
|
+
),
|
|
133
|
+
actionFn: async (renderContext:RenderContext, resolver: Resolver) => await actionFn(renderContext, resolver)
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
addPublicApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
|
|
138
|
+
this._actionList.push({
|
|
139
|
+
conditionFn: async (renderContext:RenderContext) => (
|
|
140
|
+
renderContext.method === "POST" && renderContext.url === this.apiPath &&
|
|
141
|
+
(
|
|
142
|
+
(typeof condition === "string" && renderContext.post?.api === condition) ||
|
|
143
|
+
(typeof condition === "function" && (await condition(renderContext))) ||
|
|
144
|
+
(condition?.constructor == RegExp && condition.test(renderContext.post?.api))
|
|
145
|
+
)
|
|
146
|
+
),
|
|
147
|
+
actionFn: async (renderContext:RenderContext, resolver: Resolver) => await actionFn(renderContext, resolver)
|
|
139
148
|
});
|
|
140
149
|
}
|
|
141
150
|
|
|
151
|
+
addSessionApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
|
|
152
|
+
this._actionList.push({
|
|
153
|
+
conditionFn: async (renderContext:RenderContext) => (
|
|
154
|
+
renderContext.method === "POST" && renderContext.url === this.apiPath &&
|
|
155
|
+
(
|
|
156
|
+
(typeof condition === "string" && renderContext.post?.api === condition) ||
|
|
157
|
+
(typeof condition === "function" && (await condition(renderContext))) ||
|
|
158
|
+
(condition?.constructor == RegExp && condition.test(renderContext.post?.api))
|
|
159
|
+
)
|
|
160
|
+
),
|
|
161
|
+
actionFn: async (renderContext:RenderContext, resolver: Resolver) => {
|
|
162
|
+
const isSessionValid = this.validateSession(renderContext.session);
|
|
163
|
+
if(!isSessionValid) throw new Error("Session not found");
|
|
164
|
+
return await actionFn(renderContext, resolver);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
142
168
|
|
|
143
169
|
|
|
144
170
|
async addHook(hookEvent: 'created', hookFn: HookCreatedFunction, priority?: number): Promise<void>;
|
|
@@ -159,10 +185,6 @@ export default class Lambder {
|
|
|
159
185
|
}
|
|
160
186
|
}
|
|
161
187
|
|
|
162
|
-
async addModule(moduleFn: Function): Promise<void>{
|
|
163
|
-
await moduleFn(this);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
188
|
async render(
|
|
167
189
|
event: APIGatewayProxyEvent,
|
|
168
190
|
lambdaContext: Context
|
|
@@ -171,7 +193,6 @@ export default class Lambder {
|
|
|
171
193
|
resolve:(renderResult: ResolverResponse)=>void,
|
|
172
194
|
reject:(err: Error)=>void
|
|
173
195
|
)=> {
|
|
174
|
-
|
|
175
196
|
const resolver = new Resolver({
|
|
176
197
|
isCorsEnabled: this.isCorsEnabled,
|
|
177
198
|
publicPath: this.publicPath,
|
|
@@ -179,17 +200,13 @@ export default class Lambder {
|
|
|
179
200
|
resolve, reject,
|
|
180
201
|
});
|
|
181
202
|
let renderContext:RenderContext = createContext(event, lambdaContext, resolve, reject)
|
|
182
|
-
|
|
183
203
|
if(renderContext.method === "OPTIONS") return resolver.cors();
|
|
184
204
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if(isConditionMet){
|
|
189
|
-
firstMatchedAction = action;
|
|
190
|
-
break;
|
|
205
|
+
const firstMatchedAction = await (async () => {
|
|
206
|
+
for (const action of this._actionList) {
|
|
207
|
+
if (await action.conditionFn(renderContext)) return action;
|
|
191
208
|
}
|
|
192
|
-
}
|
|
209
|
+
})();
|
|
193
210
|
|
|
194
211
|
if(firstMatchedAction){
|
|
195
212
|
for(const hook of this._hookList["beforeRender"]){
|
|
@@ -201,7 +218,9 @@ export default class Lambder {
|
|
|
201
218
|
}
|
|
202
219
|
resolve(renderResult);
|
|
203
220
|
}else{
|
|
204
|
-
for(const hook of this._hookList["fallback"])
|
|
221
|
+
for(const hook of this._hookList["fallback"]){
|
|
222
|
+
await hook.hookFn(renderContext, resolver);
|
|
223
|
+
}
|
|
205
224
|
if(this.fallbackHandler){
|
|
206
225
|
const renderResult = await this.fallbackHandler(renderContext, resolver);
|
|
207
226
|
resolve(renderResult);
|