@flink-app/flink 0.12.1-alpha.9 → 0.13.1
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/CHANGELOG.md +13 -0
- package/dist/cli/build.js +2 -2
- package/dist/cli/clean.js +2 -2
- package/dist/cli/cli-utils.js +1 -2
- package/dist/cli/run.js +2 -2
- package/dist/src/FlinkApp.d.ts +6 -1
- package/dist/src/FlinkApp.js +28 -14
- package/dist/src/FlinkErrors.d.ts +69 -0
- package/dist/src/FlinkErrors.js +87 -8
- package/dist/src/FlinkHttpHandler.d.ts +14 -1
- package/dist/src/FlinkLog.d.ts +2 -2
- package/dist/src/FlinkRepo.d.ts +8 -1
- package/dist/src/FlinkRepo.js +9 -2
- package/dist/src/FlinkResponse.d.ts +0 -3
- package/dist/src/FsUtils.js +5 -6
- package/dist/src/TypeScriptCompiler.d.ts +10 -0
- package/dist/src/TypeScriptCompiler.js +196 -49
- package/dist/src/TypeScriptUtils.js +7 -8
- package/dist/src/index.d.ts +1 -0
- package/dist/src/utils.js +13 -14
- package/package.json +67 -69
- package/spec/TypeScriptCompiler.spec.ts +11 -1
- package/spec/mock-project/dist/src/handlers/GetCar.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCar2.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +2 -2
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +2 -2
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +3 -4
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +3 -4
- package/spec/mock-project/dist/src/handlers/PostCar.js +2 -2
- package/spec/mock-project/dist/src/handlers/PostLogin.js +2 -2
- package/spec/mock-project/dist/src/handlers/{GetCarWithOmitSchema.js → PostLogout.js} +16 -20
- package/spec/mock-project/dist/src/handlers/PutCar.js +2 -2
- package/spec/mock-project/dist/src/index.js +2 -2
- package/spec/mock-project/src/handlers/PostLogout.ts +19 -0
- package/spec/mock-project/tsconfig.json +1 -1
- package/src/FlinkApp.ts +24 -5
- package/src/FlinkErrors.ts +86 -6
- package/src/FlinkHttpHandler.ts +95 -96
- package/src/FlinkRepo.ts +8 -1
- package/src/FlinkResponse.ts +36 -39
- package/src/TypeScriptCompiler.ts +172 -39
- package/src/index.ts +12 -0
- package/tsconfig.json +1 -1
- package/dist/cli/generate-schemas.d.ts +0 -2
- package/dist/cli/generate-schemas.js +0 -140
- package/spec/mock-project/dist/src/handlers/GetCarWithTypeSchema.js +0 -60
- package/spec/mock-project/package-lock.json +0 -108
package/src/FlinkErrors.ts
CHANGED
|
@@ -4,6 +4,17 @@ import { FlinkResponse } from "./FlinkResponse";
|
|
|
4
4
|
// A marker for FlinkError, but all it means is that data is undefined
|
|
5
5
|
export type FlinkError = undefined;
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Returns a 404 Not Found error response.
|
|
9
|
+
* Use when a requested resource doesn't exist (e.g., invalid ID, missing entity).
|
|
10
|
+
*
|
|
11
|
+
* @param detail - Optional custom error message
|
|
12
|
+
* @param code - Optional custom error code
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* if (!user) return notFound("User not found");
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
7
18
|
export function notFound(detail?: string, code?: string ): FlinkResponse<FlinkError> {
|
|
8
19
|
return {
|
|
9
20
|
status: 404,
|
|
@@ -11,11 +22,22 @@ export function notFound(detail?: string, code?: string ): FlinkResponse<FlinkEr
|
|
|
11
22
|
id: v4(),
|
|
12
23
|
title: "Not Found",
|
|
13
24
|
detail: detail || "The requested resource does not exist",
|
|
14
|
-
code : code ||
|
|
25
|
+
code : code || "notFound"
|
|
15
26
|
},
|
|
16
27
|
};
|
|
17
28
|
}
|
|
18
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Returns a 409 Conflict error response.
|
|
32
|
+
* Use when a request conflicts with existing data (e.g., duplicate username/email).
|
|
33
|
+
*
|
|
34
|
+
* @param detail - Optional custom error message
|
|
35
|
+
* @param code - Optional custom error code
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* if (existingUser) return conflict("Email already registered");
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
19
41
|
export function conflict(detail?: string, code?: string ): FlinkResponse<FlinkError> {
|
|
20
42
|
return {
|
|
21
43
|
status: 409,
|
|
@@ -23,13 +45,24 @@ export function conflict(detail?: string, code?: string ): FlinkResponse<FlinkEr
|
|
|
23
45
|
id: v4(),
|
|
24
46
|
title: "Conflict",
|
|
25
47
|
detail: detail || "An identical entity exits",
|
|
26
|
-
code : code ||
|
|
48
|
+
code : code || "conflict"
|
|
27
49
|
},
|
|
28
50
|
};
|
|
29
51
|
}
|
|
30
52
|
|
|
31
53
|
|
|
32
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Returns a 400 Bad Request error response.
|
|
57
|
+
* Use when the request is malformed or contains invalid data (e.g., validation errors).
|
|
58
|
+
*
|
|
59
|
+
* @param detail - Optional custom error message
|
|
60
|
+
* @param code - Optional custom error code
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* if (!email || !password) return badRequest("Email and password are required");
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
33
66
|
export function badRequest(detail?: string, code?: string): FlinkResponse<FlinkError> {
|
|
34
67
|
return {
|
|
35
68
|
status: 400,
|
|
@@ -37,11 +70,23 @@ export function badRequest(detail?: string, code?: string): FlinkResponse<FlinkE
|
|
|
37
70
|
id: v4(),
|
|
38
71
|
title: "Bad Request",
|
|
39
72
|
detail: detail || "Invalid request",
|
|
40
|
-
code : code ||
|
|
73
|
+
code : code || "badRequest"
|
|
41
74
|
},
|
|
42
75
|
};
|
|
43
76
|
}
|
|
44
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Returns a 401 Unauthorized error response.
|
|
80
|
+
* Use when authentication is required but missing or invalid (e.g., no token, expired token).
|
|
81
|
+
* This means "who are you?" - the user needs to identify themselves first.
|
|
82
|
+
*
|
|
83
|
+
* @param detail - Optional custom error message
|
|
84
|
+
* @param code - Optional custom error code
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* if (!ctx.auth?.user) return unauthorized("Authentication required");
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
45
90
|
export function unauthorized(detail?: string, code?: string): FlinkResponse<FlinkError> {
|
|
46
91
|
return {
|
|
47
92
|
status: 401,
|
|
@@ -49,12 +94,47 @@ export function unauthorized(detail?: string, code?: string): FlinkResponse<Flin
|
|
|
49
94
|
id: v4(),
|
|
50
95
|
title: "Unauthorized",
|
|
51
96
|
detail:
|
|
52
|
-
detail || "
|
|
53
|
-
code : code ||
|
|
97
|
+
detail || "Authentication required",
|
|
98
|
+
code : code || "unauthorized"
|
|
54
99
|
},
|
|
55
100
|
};
|
|
56
101
|
}
|
|
57
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Returns a 403 Forbidden error response.
|
|
105
|
+
* Use when the user is authenticated but lacks permission to access the resource.
|
|
106
|
+
* This means "I know who you are, but you're not allowed to do this."
|
|
107
|
+
*
|
|
108
|
+
* @param detail - Optional custom error message
|
|
109
|
+
* @param code - Optional custom error code
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* if (ctx.auth?.user?.role !== "admin") return forbidden("Admin access required");
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export function forbidden(detail?: string, code?: string): FlinkResponse<FlinkError> {
|
|
116
|
+
return {
|
|
117
|
+
status: 403,
|
|
118
|
+
error: {
|
|
119
|
+
id: v4(),
|
|
120
|
+
title: "Forbidden",
|
|
121
|
+
detail: detail || "You do not have permission to access this resource",
|
|
122
|
+
code : code || "forbidden"
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Returns a 500 Internal Server Error response.
|
|
129
|
+
* Use when an unexpected error occurs on the server side.
|
|
130
|
+
*
|
|
131
|
+
* @param detail - Optional custom error message
|
|
132
|
+
* @param code - Optional custom error code
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* try { ... } catch (error) { return internalServerError("Failed to process request"); }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
58
138
|
export function internalServerError(
|
|
59
139
|
detail?: string,
|
|
60
140
|
code?: string
|
|
@@ -65,7 +145,7 @@ export function internalServerError(
|
|
|
65
145
|
id: v4(),
|
|
66
146
|
title: "Internal Server Error",
|
|
67
147
|
detail: detail || "Something unexpected went wrong",
|
|
68
|
-
code : code ||
|
|
148
|
+
code : code || "internalServerError"
|
|
69
149
|
},
|
|
70
150
|
};
|
|
71
151
|
}
|
package/src/FlinkHttpHandler.ts
CHANGED
|
@@ -5,24 +5,25 @@ import { FlinkError } from "./FlinkErrors";
|
|
|
5
5
|
import { FlinkResponse } from "./FlinkResponse";
|
|
6
6
|
|
|
7
7
|
export enum HttpMethod {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
get = "get",
|
|
9
|
+
post = "post",
|
|
10
|
+
put = "put",
|
|
11
|
+
delete = "delete",
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
type Params = Request["params"];
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Query type for request query parameters.
|
|
18
|
+
* Does currently not allow nested objects, although
|
|
19
|
+
* underlying express Request does allow it.
|
|
20
|
+
*/
|
|
21
|
+
type Query = Record<string, string | string[] | undefined>;
|
|
16
22
|
|
|
17
23
|
/**
|
|
18
24
|
* Flink request extends express Request but adds reqId and user object.
|
|
19
25
|
*/
|
|
20
|
-
export type FlinkRequest<T = any, P = Params, Q = Query> = Request<
|
|
21
|
-
P,
|
|
22
|
-
any,
|
|
23
|
-
T,
|
|
24
|
-
Q
|
|
25
|
-
> & { reqId: string; user?: any };
|
|
26
|
+
export type FlinkRequest<T = any, P = Params, Q = Query> = Request<P, any, T, Q> & { reqId: string; user?: any };
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Route props to control routing.
|
|
@@ -31,66 +32,69 @@ export type FlinkRequest<T = any, P = Params, Q = Query> = Request<
|
|
|
31
32
|
* instructs express web server how to route traffic.
|
|
32
33
|
*/
|
|
33
34
|
export interface RouteProps {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
35
|
+
/**
|
|
36
|
+
* HTTP method which this handlers responds to.
|
|
37
|
+
*
|
|
38
|
+
* Will if not set attempt to extract HTTP method based
|
|
39
|
+
* on handler file name prefix, for example `GetFoo.ts` will assume
|
|
40
|
+
* HTTP method `GET`.
|
|
41
|
+
*/
|
|
42
|
+
method?: HttpMethod;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Route path including any path params.
|
|
46
|
+
* Example: `/user/:id`
|
|
47
|
+
*/
|
|
48
|
+
path: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generates mock response based on handlers response schema.
|
|
52
|
+
*
|
|
53
|
+
* Will be ignored if handler does not have any response schema defined.
|
|
54
|
+
*
|
|
55
|
+
* This should only be used during development 💥
|
|
56
|
+
*/
|
|
57
|
+
mockApi?: boolean;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Set permissions needed to access route if route requires authentication.
|
|
61
|
+
*/
|
|
62
|
+
permissions?: string | string[];
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Optional documentation of endpoint. Can be used for example in API docs.
|
|
66
|
+
* Supports markdown strings.
|
|
67
|
+
*/
|
|
68
|
+
docs?: string; // TODO
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* If handler should not be auto registered
|
|
72
|
+
*/
|
|
73
|
+
skipAutoRegister?: boolean;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* I.e. filename or plugin name that describes where handler origins from
|
|
77
|
+
*/
|
|
78
|
+
origin?: string;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Order handler should be registered in.
|
|
82
|
+
*
|
|
83
|
+
* By default all handlers has order 0 and in most cases this is fine,
|
|
84
|
+
* but if for example you want to register a handler before all others
|
|
85
|
+
* to avoid conflicts you can set a negative order.
|
|
86
|
+
*/
|
|
87
|
+
order?: number;
|
|
78
88
|
}
|
|
79
89
|
|
|
80
90
|
/**
|
|
81
91
|
* Http handler function that handlers implements in order to
|
|
82
92
|
* handle HTTP requests and return a JSON response.
|
|
83
93
|
*/
|
|
84
|
-
export type Handler<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
P extends Params = Params,
|
|
89
|
-
Q extends Query = Query
|
|
90
|
-
> = (props: {
|
|
91
|
-
req: FlinkRequest<ReqSchema, P, Q>;
|
|
92
|
-
ctx: Ctx;
|
|
93
|
-
origin?: string;
|
|
94
|
+
export type Handler<Ctx extends FlinkContext, ReqSchema = any, ResSchema = any, P extends Params = Params, Q extends Query = Query> = (props: {
|
|
95
|
+
req: FlinkRequest<ReqSchema, P, Q>;
|
|
96
|
+
ctx: Ctx;
|
|
97
|
+
origin?: string;
|
|
94
98
|
}) => Promise<FlinkResponse<ResSchema | FlinkError>>;
|
|
95
99
|
|
|
96
100
|
/**
|
|
@@ -99,12 +103,7 @@ export type Handler<
|
|
|
99
103
|
*
|
|
100
104
|
* Just syntactic sugar on top op `HandlerFn`
|
|
101
105
|
*/
|
|
102
|
-
export type GetHandler<
|
|
103
|
-
Ctx extends FlinkContext,
|
|
104
|
-
ResSchema = any,
|
|
105
|
-
P extends Params = Params,
|
|
106
|
-
Q extends Query = Query
|
|
107
|
-
> = Handler<Ctx, any, ResSchema, P, Q>;
|
|
106
|
+
export type GetHandler<Ctx extends FlinkContext, ResSchema = any, P extends Params = Params, Q extends Query = Query> = Handler<Ctx, any, ResSchema, P, Q>;
|
|
108
107
|
|
|
109
108
|
/**
|
|
110
109
|
* Type for Handler file. Describes shape of exports when using
|
|
@@ -113,32 +112,32 @@ export type GetHandler<
|
|
|
113
112
|
* `import * as FooHandler from "./src/handlers/FooHandler"
|
|
114
113
|
*/
|
|
115
114
|
export type HandlerFile = {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
115
|
+
default: Handler<any, any, any, any, any>;
|
|
116
|
+
Route?: RouteProps;
|
|
117
|
+
/**
|
|
118
|
+
* Name of schemas, is set at compile time by Flink compiler.
|
|
119
|
+
*/
|
|
120
|
+
__schemas?: {
|
|
121
|
+
reqSchema?: JSONSchema;
|
|
122
|
+
resSchema?: JSONSchema;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Typescript source file name, is set at compile time by Flink compiler.
|
|
126
|
+
*/
|
|
127
|
+
__file?: string;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Description of query params, is set at compile time by Flink compiler.
|
|
131
|
+
*/
|
|
132
|
+
__query?: QueryParamMetadata[];
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Description of path params, is set at compile time by Flink compiler.
|
|
136
|
+
*/
|
|
137
|
+
__params?: QueryParamMetadata[];
|
|
139
138
|
};
|
|
140
139
|
|
|
141
140
|
export type QueryParamMetadata = {
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
name: string;
|
|
142
|
+
description: string;
|
|
144
143
|
};
|
package/src/FlinkRepo.ts
CHANGED
|
@@ -82,7 +82,14 @@ export abstract class FlinkRepo<C extends FlinkContext, Model extends Document>
|
|
|
82
82
|
return deletedCount || 0;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Helper to ensure the id is always an ObjectId.
|
|
87
|
+
* If a string is passed, it will be converted to an ObjectId.
|
|
88
|
+
* If an ObjectId is passed, it will be returned as is.
|
|
89
|
+
* @param id
|
|
90
|
+
* @returns
|
|
91
|
+
*/
|
|
92
|
+
buildId(id: string | ObjectId) {
|
|
86
93
|
let oid: ObjectId | string;
|
|
87
94
|
|
|
88
95
|
if (typeof id === "string") {
|
package/src/FlinkResponse.ts
CHANGED
|
@@ -1,48 +1,45 @@
|
|
|
1
1
|
import { Response, Request } from "express";
|
|
2
2
|
|
|
3
3
|
export interface FlinkResponse<T = any> {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Unique id of request.
|
|
6
|
+
* Used to track request in logs.
|
|
7
|
+
*/
|
|
8
|
+
reqId?: string;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
/**
|
|
11
|
+
* HTTP status code, default to 200.
|
|
12
|
+
*/
|
|
13
|
+
status?: number;
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Optional redirect. Will trigger a redirect of provided type.
|
|
17
|
+
*/
|
|
18
|
+
redirect?: {
|
|
19
|
+
to: string;
|
|
20
|
+
type?: "TEMPORARY" | "PERMANENT";
|
|
21
|
+
};
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Actual payload to return.
|
|
25
|
+
*/
|
|
26
|
+
data?: T;
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Error object set if error response.
|
|
30
|
+
* If set the `status` is set to 4xx or 5xx code.
|
|
31
|
+
*/
|
|
32
|
+
error?: {
|
|
33
|
+
id: string;
|
|
34
|
+
title: string;
|
|
35
|
+
detail?: string;
|
|
36
|
+
code?: string;
|
|
37
|
+
};
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
/**
|
|
40
|
+
* HTTP headers, names are lower cased
|
|
41
|
+
*/
|
|
42
|
+
headers?: {
|
|
43
|
+
[x: string]: string;
|
|
44
|
+
};
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
export type ExpressResponse = Response;
|
|
48
|
-
export type ExpressRequest = Request;
|