lambder 1.0.40 → 1.0.42
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 +15 -15
- package/dist/Lambder.js +64 -65
- package/dist/Resolver.d.ts +2 -2
- package/package.json +1 -1
- package/src/Lambder.ts +80 -88
- package/src/Resolver.ts +2 -2
package/dist/Lambder.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from "aws-lambda";
|
|
2
2
|
import Resolver from "./Resolver.js";
|
|
3
3
|
import ResponseBuilder, { ResolverResponse } from "./ResponseBuilder.js";
|
|
4
|
-
type
|
|
4
|
+
type Session = {
|
|
5
5
|
userId: string;
|
|
6
6
|
userIdHash: string;
|
|
7
7
|
sessionHash: string;
|
|
@@ -11,7 +11,7 @@ type DDBSession = {
|
|
|
11
11
|
data: {
|
|
12
12
|
[key: string]: any;
|
|
13
13
|
};
|
|
14
|
-
}
|
|
14
|
+
};
|
|
15
15
|
type RenderContext = {
|
|
16
16
|
host: string;
|
|
17
17
|
url: string;
|
|
@@ -26,27 +26,27 @@ type RenderContext = {
|
|
|
26
26
|
[key: string]: any;
|
|
27
27
|
};
|
|
28
28
|
headers: APIGatewayProxyEventHeaders;
|
|
29
|
-
session:
|
|
29
|
+
session: Session | null;
|
|
30
30
|
lambdaContext: Context;
|
|
31
31
|
};
|
|
32
|
-
type ConditionFunction = (
|
|
33
|
-
type ActionFunction = (
|
|
32
|
+
type ConditionFunction = (ctx: RenderContext) => boolean;
|
|
33
|
+
type ActionFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse | Promise<ResolverResponse>;
|
|
34
34
|
type HookCreatedFunction = (lambderInstance: Lambder) => Promise<void>;
|
|
35
|
-
type HookBeforeRenderFunction = (
|
|
36
|
-
type HookAfterRenderFunction = (
|
|
37
|
-
type HookFallbackFunction = (
|
|
38
|
-
type HookCompletedFunction = (
|
|
39
|
-
type GlobalErrorHandlerFunction = (err: Error,
|
|
40
|
-
type RouteFallbackHandlerFunction = (
|
|
41
|
-
type ApiFallbackHandlerFunction = (
|
|
35
|
+
type HookBeforeRenderFunction = (ctx: RenderContext, resolver: Resolver) => RenderContext | Promise<RenderContext>;
|
|
36
|
+
type HookAfterRenderFunction = (ctx: RenderContext, resolver: Resolver, response: ResolverResponse) => ResolverResponse | Promise<ResolverResponse>;
|
|
37
|
+
type HookFallbackFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse | Promise<ResolverResponse>;
|
|
38
|
+
type HookCompletedFunction = (response: ResolverResponse) => ResolverResponse | Promise<ResolverResponse>;
|
|
39
|
+
type GlobalErrorHandlerFunction = (err: Error, ctx: RenderContext | null, response: ResponseBuilder) => ResolverResponse | Promise<ResolverResponse>;
|
|
40
|
+
type RouteFallbackHandlerFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse;
|
|
41
|
+
type ApiFallbackHandlerFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse;
|
|
42
42
|
export declare const createContext: (event: APIGatewayProxyEvent, lambdaContext: Context) => RenderContext;
|
|
43
43
|
export default class Lambder {
|
|
44
44
|
private apiPath;
|
|
45
45
|
private apiVersion;
|
|
46
46
|
private isCorsEnabled;
|
|
47
47
|
private publicPath;
|
|
48
|
-
private
|
|
49
|
-
private
|
|
48
|
+
private actionList;
|
|
49
|
+
private hookList;
|
|
50
50
|
private globalErrorHandler;
|
|
51
51
|
private routeFallbackHandler;
|
|
52
52
|
private apiFallbackHandler;
|
|
@@ -72,7 +72,7 @@ export default class Lambder {
|
|
|
72
72
|
addHook(hookEvent: 'fallback', hookFn: HookFallbackFunction, priority?: number): Promise<void>;
|
|
73
73
|
addHook(hookEvent: 'completed', hookFn: HookCompletedFunction, priority?: number): Promise<void>;
|
|
74
74
|
getResponseBuilder(): ResponseBuilder;
|
|
75
|
-
getResolver
|
|
75
|
+
private getResolver;
|
|
76
76
|
render(event: APIGatewayProxyEvent, lambdaContext: Context): Promise<ResolverResponse>;
|
|
77
77
|
}
|
|
78
78
|
export {};
|
package/dist/Lambder.js
CHANGED
|
@@ -31,8 +31,8 @@ export default class Lambder {
|
|
|
31
31
|
apiVersion;
|
|
32
32
|
isCorsEnabled;
|
|
33
33
|
publicPath;
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
actionList;
|
|
35
|
+
hookList;
|
|
36
36
|
globalErrorHandler = null;
|
|
37
37
|
routeFallbackHandler = null;
|
|
38
38
|
apiFallbackHandler = null;
|
|
@@ -41,8 +41,8 @@ export default class Lambder {
|
|
|
41
41
|
this.apiPath = apiPath ?? "/api";
|
|
42
42
|
this.apiVersion = apiVersion ?? null;
|
|
43
43
|
this.isCorsEnabled = isCorsEnabled ?? false;
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
44
|
+
this.actionList = [];
|
|
45
|
+
this.hookList = {
|
|
46
46
|
"beforeRender": [],
|
|
47
47
|
"afterRender": [],
|
|
48
48
|
"fallback": [],
|
|
@@ -71,20 +71,19 @@ export default class Lambder {
|
|
|
71
71
|
return false;
|
|
72
72
|
}
|
|
73
73
|
;
|
|
74
|
-
async handleNoMatchedAction(
|
|
75
|
-
for (const hook of this.
|
|
76
|
-
await hook.hookFn(
|
|
74
|
+
async handleNoMatchedAction(ctx, resolver) {
|
|
75
|
+
for (const hook of this.hookList["fallback"]) {
|
|
76
|
+
await hook.hookFn(ctx, resolver);
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
78
|
+
const isAPI = ctx.url === this.apiPath;
|
|
79
|
+
if (isAPI && this.apiFallbackHandler) {
|
|
80
|
+
resolver.resolve(await this.apiFallbackHandler(ctx, resolver));
|
|
81
|
+
}
|
|
82
|
+
else if (isAPI) {
|
|
83
|
+
resolver.resolve({ statusCode: 204, body: "API handler not set.", });
|
|
85
84
|
}
|
|
86
85
|
else if (this.routeFallbackHandler) {
|
|
87
|
-
resolver.resolve(await this.routeFallbackHandler(
|
|
86
|
+
resolver.resolve(await this.routeFallbackHandler(ctx, resolver));
|
|
88
87
|
}
|
|
89
88
|
else {
|
|
90
89
|
resolver.resolve({ statusCode: 204, body: "Handler not set.", });
|
|
@@ -94,46 +93,51 @@ export default class Lambder {
|
|
|
94
93
|
await moduleFn(this);
|
|
95
94
|
}
|
|
96
95
|
addRoute(condition, actionFn) {
|
|
97
|
-
this.
|
|
98
|
-
conditionFn:
|
|
99
|
-
((typeof condition === "string" &&
|
|
100
|
-
(typeof condition === "function" &&
|
|
101
|
-
(condition?.constructor == RegExp && condition.test(
|
|
102
|
-
actionFn: async (
|
|
96
|
+
this.actionList.push({
|
|
97
|
+
conditionFn: (ctx) => (ctx.method === "GET" &&
|
|
98
|
+
((typeof condition === "string" && ctx.url === condition) ||
|
|
99
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
100
|
+
(condition?.constructor == RegExp && condition.test(ctx.url)))),
|
|
101
|
+
actionFn: async (ctx, resolver) => await actionFn(ctx, resolver)
|
|
103
102
|
});
|
|
104
103
|
}
|
|
105
104
|
;
|
|
106
105
|
addSessionRoute(condition, actionFn) {
|
|
107
|
-
this.
|
|
108
|
-
conditionFn:
|
|
109
|
-
((typeof condition === "string" &&
|
|
110
|
-
(typeof condition === "function" &&
|
|
111
|
-
(condition?.constructor == RegExp && condition.test(
|
|
112
|
-
actionFn: async (
|
|
106
|
+
this.actionList.push({
|
|
107
|
+
conditionFn: (ctx) => (ctx.method === "GET" &&
|
|
108
|
+
((typeof condition === "string" && ctx.url === condition) ||
|
|
109
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
110
|
+
(condition?.constructor == RegExp && condition.test(ctx.url)))),
|
|
111
|
+
actionFn: async (ctx, resolver) => {
|
|
112
|
+
const isSessionValid = this.validateSession(ctx.session);
|
|
113
|
+
if (!isSessionValid)
|
|
114
|
+
throw new Error("Session not found");
|
|
115
|
+
return await actionFn(ctx, resolver);
|
|
116
|
+
}
|
|
113
117
|
});
|
|
114
118
|
}
|
|
115
119
|
;
|
|
116
120
|
addApi(condition, actionFn) {
|
|
117
|
-
this.
|
|
118
|
-
conditionFn:
|
|
119
|
-
((typeof condition === "string" &&
|
|
120
|
-
(typeof condition === "function" &&
|
|
121
|
-
(condition?.constructor == RegExp && condition.test(
|
|
122
|
-
actionFn: async (
|
|
121
|
+
this.actionList.push({
|
|
122
|
+
conditionFn: (ctx) => (ctx.method === "POST" && ctx.url === this.apiPath &&
|
|
123
|
+
((typeof condition === "string" && ctx.post?.api === condition) ||
|
|
124
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
125
|
+
(condition?.constructor == RegExp && condition.test(ctx.post?.api)))),
|
|
126
|
+
actionFn: async (ctx, resolver) => await actionFn(ctx, resolver),
|
|
123
127
|
});
|
|
124
128
|
}
|
|
125
129
|
;
|
|
126
130
|
addSessionApi(condition, actionFn) {
|
|
127
|
-
this.
|
|
128
|
-
conditionFn:
|
|
129
|
-
((typeof condition === "string" &&
|
|
130
|
-
(typeof condition === "function" &&
|
|
131
|
-
(condition?.constructor == RegExp && condition.test(
|
|
132
|
-
actionFn: async (
|
|
133
|
-
const isSessionValid = this.validateSession(
|
|
131
|
+
this.actionList.push({
|
|
132
|
+
conditionFn: (ctx) => (ctx.method === "POST" && ctx.url === this.apiPath &&
|
|
133
|
+
((typeof condition === "string" && ctx.post?.api === condition) ||
|
|
134
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
135
|
+
(condition?.constructor == RegExp && condition.test(ctx.post?.api)))),
|
|
136
|
+
actionFn: async (ctx, resolver) => {
|
|
137
|
+
const isSessionValid = this.validateSession(ctx.session);
|
|
134
138
|
if (!isSessionValid)
|
|
135
139
|
throw new Error("Session not found");
|
|
136
|
-
return await actionFn(
|
|
140
|
+
return await actionFn(ctx, resolver);
|
|
137
141
|
}
|
|
138
142
|
});
|
|
139
143
|
}
|
|
@@ -143,8 +147,8 @@ export default class Lambder {
|
|
|
143
147
|
await hookFn(this);
|
|
144
148
|
}
|
|
145
149
|
else {
|
|
146
|
-
this.
|
|
147
|
-
this.
|
|
150
|
+
this.hookList[hookEvent].push({ priority, hookFn });
|
|
151
|
+
this.hookList[hookEvent].sort((a, b) => a.priority - b.priority);
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
getResponseBuilder() {
|
|
@@ -167,42 +171,37 @@ export default class Lambder {
|
|
|
167
171
|
async render(event, lambdaContext) {
|
|
168
172
|
let eventRenderContext = null;
|
|
169
173
|
try {
|
|
170
|
-
let
|
|
171
|
-
eventRenderContext =
|
|
174
|
+
let ctx = createContext(event, lambdaContext);
|
|
175
|
+
eventRenderContext = ctx;
|
|
172
176
|
return await new Promise(async (resolve, reject) => {
|
|
173
177
|
const resolver = this.getResolver(resolve, reject);
|
|
174
|
-
if (
|
|
178
|
+
if (ctx.method === "OPTIONS")
|
|
175
179
|
return resolver.cors();
|
|
176
|
-
const firstMatchedAction =
|
|
177
|
-
for (const action of this._actionList) {
|
|
178
|
-
if (await action.conditionFn(renderContext))
|
|
179
|
-
return action;
|
|
180
|
-
}
|
|
181
|
-
})();
|
|
180
|
+
const firstMatchedAction = this.actionList.find(action => action.conditionFn(ctx));
|
|
182
181
|
if (firstMatchedAction) {
|
|
183
|
-
for (const hook of this.
|
|
184
|
-
|
|
182
|
+
for (const hook of this.hookList["beforeRender"]) {
|
|
183
|
+
ctx = await hook.hookFn(ctx, resolver);
|
|
185
184
|
}
|
|
186
|
-
let
|
|
187
|
-
for (const hook of this.
|
|
188
|
-
|
|
185
|
+
let response = await firstMatchedAction.actionFn(ctx, resolver);
|
|
186
|
+
for (const hook of this.hookList["afterRender"]) {
|
|
187
|
+
response = await hook.hookFn(ctx, resolver, response);
|
|
189
188
|
}
|
|
190
|
-
resolve(
|
|
189
|
+
resolve(response);
|
|
191
190
|
}
|
|
192
191
|
else {
|
|
193
|
-
return this.handleNoMatchedAction(
|
|
192
|
+
return this.handleNoMatchedAction(ctx, resolver);
|
|
194
193
|
}
|
|
195
|
-
}).then(async (
|
|
196
|
-
for (const hook of this.
|
|
197
|
-
|
|
194
|
+
}).then(async (response) => {
|
|
195
|
+
for (const hook of this.hookList["completed"]) {
|
|
196
|
+
response = await hook.hookFn(response);
|
|
198
197
|
}
|
|
199
|
-
return
|
|
198
|
+
return response;
|
|
200
199
|
});
|
|
201
200
|
}
|
|
202
201
|
catch (err) {
|
|
203
|
-
const responseBuilder = this.getResponseBuilder();
|
|
204
|
-
const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
|
|
205
202
|
if (this.globalErrorHandler) {
|
|
203
|
+
const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
|
|
204
|
+
const responseBuilder = this.getResponseBuilder();
|
|
206
205
|
return this.globalErrorHandler(wrappedError, eventRenderContext, responseBuilder);
|
|
207
206
|
}
|
|
208
207
|
return { statusCode: 500, body: "Internal Server Error.", };
|
package/dist/Resolver.d.ts
CHANGED
|
@@ -13,14 +13,14 @@ interface DieResolverMethods {
|
|
|
13
13
|
api: MethodType<ResponseBuilder, 'api'>;
|
|
14
14
|
}
|
|
15
15
|
export default class Resolver extends ResponseBuilder {
|
|
16
|
-
resolve: (
|
|
16
|
+
resolve: (response: ResolverResponse) => void;
|
|
17
17
|
reject: (err: Error) => void;
|
|
18
18
|
die: DieResolverMethods;
|
|
19
19
|
constructor({ isCorsEnabled, publicPath, apiVersion, resolve, reject }: {
|
|
20
20
|
isCorsEnabled: boolean;
|
|
21
21
|
publicPath: string;
|
|
22
22
|
apiVersion?: string | null;
|
|
23
|
-
resolve: (
|
|
23
|
+
resolve: (response: ResolverResponse) => void;
|
|
24
24
|
reject: (err: Error) => void;
|
|
25
25
|
});
|
|
26
26
|
private autoResolve;
|
package/package.json
CHANGED
package/src/Lambder.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, Context } from
|
|
|
5
5
|
import Resolver from "./Resolver.js";
|
|
6
6
|
import ResponseBuilder, { ResolverResponse } from "./ResponseBuilder.js";
|
|
7
7
|
|
|
8
|
-
type
|
|
8
|
+
type Session = {
|
|
9
9
|
userId: string,
|
|
10
10
|
userIdHash: string;
|
|
11
11
|
sessionHash: string;
|
|
@@ -13,7 +13,7 @@ type DDBSession = {
|
|
|
13
13
|
createdTimeStamp: number;
|
|
14
14
|
expiresTimeStamp: number;
|
|
15
15
|
data: { [key:string]: any };
|
|
16
|
-
}
|
|
16
|
+
};
|
|
17
17
|
|
|
18
18
|
type RenderContext = {
|
|
19
19
|
host: string;
|
|
@@ -23,23 +23,23 @@ type RenderContext = {
|
|
|
23
23
|
post: { [key: string]: any };
|
|
24
24
|
cookie: { [key: string]: any };
|
|
25
25
|
headers: APIGatewayProxyEventHeaders;
|
|
26
|
-
session:
|
|
26
|
+
session: Session|null;
|
|
27
27
|
lambdaContext: Context;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
type ConditionFunction = (
|
|
31
|
-
type ActionFunction = (
|
|
32
|
-
type
|
|
30
|
+
type ConditionFunction = (ctx: RenderContext) => boolean;
|
|
31
|
+
type ActionFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse|Promise<ResolverResponse>;
|
|
32
|
+
type ActionObject = { conditionFn: ConditionFunction, actionFn: ActionFunction };
|
|
33
33
|
|
|
34
34
|
type HookCreatedFunction = (lambderInstance: Lambder) => Promise<void>;
|
|
35
|
-
type HookBeforeRenderFunction = (
|
|
36
|
-
type HookAfterRenderFunction = (
|
|
37
|
-
type HookFallbackFunction = (
|
|
38
|
-
type HookCompletedFunction = (
|
|
35
|
+
type HookBeforeRenderFunction = (ctx: RenderContext, resolver: Resolver) => RenderContext|Promise<RenderContext>;
|
|
36
|
+
type HookAfterRenderFunction = (ctx: RenderContext, resolver: Resolver, response: ResolverResponse) => ResolverResponse|Promise<ResolverResponse>;
|
|
37
|
+
type HookFallbackFunction = (ctx: RenderContext, resolver: Resolver) => ResolverResponse|Promise<ResolverResponse>;
|
|
38
|
+
type HookCompletedFunction = (response: ResolverResponse) => ResolverResponse|Promise<ResolverResponse>;
|
|
39
39
|
|
|
40
|
-
type GlobalErrorHandlerFunction = (err: Error,
|
|
41
|
-
type RouteFallbackHandlerFunction = (
|
|
42
|
-
type ApiFallbackHandlerFunction = (
|
|
40
|
+
type GlobalErrorHandlerFunction = (err: Error, ctx: RenderContext|null, response: ResponseBuilder) => ResolverResponse|Promise<ResolverResponse>;
|
|
41
|
+
type RouteFallbackHandlerFunction = (ctx:RenderContext, resolver: Resolver) => ResolverResponse;
|
|
42
|
+
type ApiFallbackHandlerFunction = (ctx:RenderContext, resolver: Resolver) => ResolverResponse;
|
|
43
43
|
|
|
44
44
|
type HookEventType = "created"|"beforeRender"|"afterRender"|"fallback"|"completed";
|
|
45
45
|
type HookListType = {
|
|
@@ -75,8 +75,8 @@ export default class Lambder {
|
|
|
75
75
|
private isCorsEnabled: boolean;
|
|
76
76
|
private publicPath: string;
|
|
77
77
|
|
|
78
|
-
private
|
|
79
|
-
private
|
|
78
|
+
private actionList: ActionObject[];
|
|
79
|
+
private hookList: {
|
|
80
80
|
"beforeRender": { priority: number, hookFn: HookBeforeRenderFunction }[],
|
|
81
81
|
"afterRender": { priority: number, hookFn: HookAfterRenderFunction }[],
|
|
82
82
|
"fallback": { priority: number, hookFn: HookFallbackFunction }[],
|
|
@@ -95,8 +95,8 @@ export default class Lambder {
|
|
|
95
95
|
this.apiVersion = apiVersion ?? null;
|
|
96
96
|
this.isCorsEnabled = isCorsEnabled ?? false;
|
|
97
97
|
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
98
|
+
this.actionList = [];
|
|
99
|
+
this.hookList = {
|
|
100
100
|
"beforeRender": [],
|
|
101
101
|
"afterRender": [],
|
|
102
102
|
"fallback": [],
|
|
@@ -114,7 +114,7 @@ export default class Lambder {
|
|
|
114
114
|
this.globalErrorHandler = globalErrorHandler;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
private async validateSession (session:
|
|
117
|
+
private async validateSession (session: Session|null): Promise<boolean>{
|
|
118
118
|
if(!session) return false;
|
|
119
119
|
if(!session.userId || !session.userIdHash || !session.sessionHash || !session.csrfToken) return false;
|
|
120
120
|
if(!session.createdTimeStamp || !session.expiresTimeStamp) return false;
|
|
@@ -123,18 +123,16 @@ export default class Lambder {
|
|
|
123
123
|
return false;
|
|
124
124
|
};
|
|
125
125
|
|
|
126
|
-
private async handleNoMatchedAction(
|
|
127
|
-
for(const hook of this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
resolver.resolve({ statusCode: 204, body: "API handler not set.", })
|
|
135
|
-
}
|
|
126
|
+
private async handleNoMatchedAction(ctx: RenderContext, resolver: Resolver){
|
|
127
|
+
for(const hook of this.hookList["fallback"]){ await hook.hookFn(ctx, resolver); }
|
|
128
|
+
|
|
129
|
+
const isAPI = ctx.url === this.apiPath;
|
|
130
|
+
if(isAPI && this.apiFallbackHandler){
|
|
131
|
+
resolver.resolve(await this.apiFallbackHandler(ctx, resolver));
|
|
132
|
+
}else if(isAPI){
|
|
133
|
+
resolver.resolve({ statusCode: 204, body: "API handler not set.", })
|
|
136
134
|
}else if(this.routeFallbackHandler){
|
|
137
|
-
resolver.resolve(await this.routeFallbackHandler(
|
|
135
|
+
resolver.resolve(await this.routeFallbackHandler(ctx, resolver));
|
|
138
136
|
}else{
|
|
139
137
|
resolver.resolve({ statusCode: 204, body: "Handler not set.", })
|
|
140
138
|
}
|
|
@@ -144,61 +142,65 @@ export default class Lambder {
|
|
|
144
142
|
await moduleFn(this);
|
|
145
143
|
}
|
|
146
144
|
addRoute(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
|
|
147
|
-
this.
|
|
148
|
-
conditionFn:
|
|
149
|
-
|
|
145
|
+
this.actionList.push({
|
|
146
|
+
conditionFn: (ctx:RenderContext) => (
|
|
147
|
+
ctx.method === "GET" &&
|
|
150
148
|
(
|
|
151
|
-
(typeof condition === "string" &&
|
|
152
|
-
(typeof condition === "function" &&
|
|
153
|
-
(condition?.constructor == RegExp && condition.test(
|
|
149
|
+
(typeof condition === "string" && ctx.url === condition) ||
|
|
150
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
151
|
+
(condition?.constructor == RegExp && condition.test(ctx.url))
|
|
154
152
|
)
|
|
155
153
|
),
|
|
156
|
-
actionFn: async (
|
|
154
|
+
actionFn: async (ctx:RenderContext, resolver: Resolver) => await actionFn(ctx, resolver)
|
|
157
155
|
});
|
|
158
156
|
};
|
|
159
157
|
|
|
160
158
|
addSessionRoute(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
|
|
161
|
-
this.
|
|
162
|
-
conditionFn:
|
|
163
|
-
|
|
159
|
+
this.actionList.push({
|
|
160
|
+
conditionFn: (ctx:RenderContext) => (
|
|
161
|
+
ctx.method === "GET" &&
|
|
164
162
|
(
|
|
165
|
-
(typeof condition === "string" &&
|
|
166
|
-
(typeof condition === "function" &&
|
|
167
|
-
(condition?.constructor == RegExp && condition.test(
|
|
163
|
+
(typeof condition === "string" && ctx.url === condition) ||
|
|
164
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
165
|
+
(condition?.constructor == RegExp && condition.test(ctx.url))
|
|
168
166
|
)
|
|
169
167
|
),
|
|
170
|
-
actionFn: async (
|
|
168
|
+
actionFn: async (ctx:RenderContext, resolver: Resolver) => {
|
|
169
|
+
const isSessionValid = this.validateSession(ctx.session);
|
|
170
|
+
if(!isSessionValid) throw new Error("Session not found");
|
|
171
|
+
return await actionFn(ctx, resolver);
|
|
172
|
+
}
|
|
171
173
|
});
|
|
172
174
|
};
|
|
173
175
|
|
|
174
176
|
addApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
|
|
175
|
-
this.
|
|
176
|
-
conditionFn:
|
|
177
|
-
|
|
177
|
+
this.actionList.push({
|
|
178
|
+
conditionFn: (ctx:RenderContext) => (
|
|
179
|
+
ctx.method === "POST" && ctx.url === this.apiPath &&
|
|
178
180
|
(
|
|
179
|
-
(typeof condition === "string" &&
|
|
180
|
-
(typeof condition === "function" &&
|
|
181
|
-
(condition?.constructor == RegExp && condition.test(
|
|
181
|
+
(typeof condition === "string" && ctx.post?.api === condition) ||
|
|
182
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
183
|
+
(condition?.constructor == RegExp && condition.test(ctx.post?.api))
|
|
182
184
|
)
|
|
183
185
|
),
|
|
184
|
-
actionFn: async (
|
|
186
|
+
actionFn: async (ctx:RenderContext, resolver: Resolver) => await actionFn(ctx, resolver),
|
|
185
187
|
});
|
|
186
188
|
};
|
|
187
189
|
|
|
188
190
|
addSessionApi(condition: string|ConditionFunction|RegExp, actionFn: ActionFunction):void{
|
|
189
|
-
this.
|
|
190
|
-
conditionFn:
|
|
191
|
-
|
|
191
|
+
this.actionList.push({
|
|
192
|
+
conditionFn: (ctx:RenderContext) => (
|
|
193
|
+
ctx.method === "POST" && ctx.url === this.apiPath &&
|
|
192
194
|
(
|
|
193
|
-
(typeof condition === "string" &&
|
|
194
|
-
(typeof condition === "function" &&
|
|
195
|
-
(condition?.constructor == RegExp && condition.test(
|
|
195
|
+
(typeof condition === "string" && ctx.post?.api === condition) ||
|
|
196
|
+
(typeof condition === "function" && condition(ctx)) ||
|
|
197
|
+
(condition?.constructor == RegExp && condition.test(ctx.post?.api))
|
|
196
198
|
)
|
|
197
199
|
),
|
|
198
|
-
actionFn: async (
|
|
199
|
-
const isSessionValid = this.validateSession(
|
|
200
|
+
actionFn: async (ctx:RenderContext, resolver: Resolver) => {
|
|
201
|
+
const isSessionValid = this.validateSession(ctx.session);
|
|
200
202
|
if(!isSessionValid) throw new Error("Session not found");
|
|
201
|
-
return await actionFn(
|
|
203
|
+
return await actionFn(ctx, resolver);
|
|
202
204
|
}
|
|
203
205
|
});
|
|
204
206
|
};
|
|
@@ -217,8 +219,8 @@ export default class Lambder {
|
|
|
217
219
|
if(hookEvent === "created"){
|
|
218
220
|
await hookFn(this);
|
|
219
221
|
}else{
|
|
220
|
-
this.
|
|
221
|
-
this.
|
|
222
|
+
this.hookList[hookEvent].push({ priority, hookFn });
|
|
223
|
+
this.hookList[hookEvent].sort((a, b) => a.priority - b.priority);
|
|
222
224
|
}
|
|
223
225
|
}
|
|
224
226
|
|
|
@@ -230,7 +232,7 @@ export default class Lambder {
|
|
|
230
232
|
});
|
|
231
233
|
};
|
|
232
234
|
|
|
233
|
-
|
|
235
|
+
private getResolver(resolve: (response: ResolverResponse) => void, reject: (err: Error) => void){
|
|
234
236
|
return new Resolver({
|
|
235
237
|
isCorsEnabled: this.isCorsEnabled,
|
|
236
238
|
publicPath: this.publicPath,
|
|
@@ -244,45 +246,35 @@ export default class Lambder {
|
|
|
244
246
|
lambdaContext: Context
|
|
245
247
|
): Promise<ResolverResponse>{
|
|
246
248
|
let eventRenderContext:RenderContext|null = null;
|
|
249
|
+
|
|
247
250
|
try {
|
|
248
|
-
let
|
|
249
|
-
eventRenderContext =
|
|
251
|
+
let ctx = createContext(event, lambdaContext);
|
|
252
|
+
eventRenderContext = ctx;
|
|
250
253
|
|
|
251
254
|
return await new Promise(async (
|
|
252
|
-
resolve:(
|
|
255
|
+
resolve:(response: ResolverResponse)=>void,
|
|
253
256
|
reject:(err: Error)=>void
|
|
254
257
|
)=> {
|
|
255
258
|
const resolver = this.getResolver(resolve, reject);
|
|
256
|
-
if(
|
|
257
|
-
|
|
258
|
-
const firstMatchedAction = await (async () => {
|
|
259
|
-
for(const action of this._actionList){
|
|
260
|
-
if(await action.conditionFn(renderContext)) return action;
|
|
261
|
-
}
|
|
262
|
-
})();
|
|
259
|
+
if(ctx.method === "OPTIONS") return resolver.cors();
|
|
263
260
|
|
|
261
|
+
const firstMatchedAction = this.actionList.find(action => action.conditionFn(ctx));
|
|
264
262
|
if(firstMatchedAction){
|
|
265
|
-
for(const hook of this.
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
for(const hook of this._hookList["afterRender"]){
|
|
270
|
-
renderResult = await hook.hookFn(renderContext, resolver, renderResult);
|
|
271
|
-
}
|
|
272
|
-
resolve(renderResult);
|
|
263
|
+
for(const hook of this.hookList["beforeRender"]){ ctx = await hook.hookFn(ctx, resolver); }
|
|
264
|
+
let response = await firstMatchedAction.actionFn(ctx, resolver);
|
|
265
|
+
for(const hook of this.hookList["afterRender"]){ response = await hook.hookFn(ctx, resolver, response); }
|
|
266
|
+
resolve(response);
|
|
273
267
|
}else{
|
|
274
|
-
return this.handleNoMatchedAction(
|
|
275
|
-
}
|
|
276
|
-
}).then(async (renderResult: ResolverResponse):Promise<ResolverResponse> => {
|
|
277
|
-
for(const hook of this._hookList["completed"]){
|
|
278
|
-
renderResult = await hook.hookFn(renderResult);
|
|
268
|
+
return this.handleNoMatchedAction(ctx, resolver);
|
|
279
269
|
}
|
|
280
|
-
|
|
270
|
+
}).then(async (response: ResolverResponse):Promise<ResolverResponse> => {
|
|
271
|
+
for(const hook of this.hookList["completed"]){ response = await hook.hookFn(response); }
|
|
272
|
+
return response;
|
|
281
273
|
});
|
|
282
274
|
}catch(err){
|
|
283
|
-
const responseBuilder = this.getResponseBuilder();
|
|
284
|
-
const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
|
|
285
275
|
if(this.globalErrorHandler){
|
|
276
|
+
const wrappedError = err instanceof Error ? err : new Error("Error: " + String(err));
|
|
277
|
+
const responseBuilder = this.getResponseBuilder();
|
|
286
278
|
return this.globalErrorHandler(wrappedError, eventRenderContext, responseBuilder);
|
|
287
279
|
}
|
|
288
280
|
return { statusCode: 500, body: "Internal Server Error.", }
|
package/src/Resolver.ts
CHANGED
|
@@ -16,7 +16,7 @@ interface DieResolverMethods {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export default class Resolver extends ResponseBuilder {
|
|
19
|
-
public resolve: (
|
|
19
|
+
public resolve: (response: ResolverResponse) => void;
|
|
20
20
|
public reject: (err: Error) => void;
|
|
21
21
|
public die: DieResolverMethods;
|
|
22
22
|
|
|
@@ -26,7 +26,7 @@ export default class Resolver extends ResponseBuilder {
|
|
|
26
26
|
isCorsEnabled: boolean,
|
|
27
27
|
publicPath: string,
|
|
28
28
|
apiVersion?: string|null,
|
|
29
|
-
resolve: (
|
|
29
|
+
resolve: (response: ResolverResponse) => void,
|
|
30
30
|
reject: (err: Error) => void,
|
|
31
31
|
}
|
|
32
32
|
){
|