milkio 0.1.2 → 0.2.0

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.
@@ -1,194 +1,194 @@
1
1
  /* eslint-disable no-console */
2
- import { loggerPushTags, loggerSubmit, useLogger, runtime, MiddlewareEvent } from ".."
3
- import type { ExecuteId, MilkioApp, Mixin } from ".."
4
- import { hanldeCatchError } from "../utils/handle-catch-error"
5
- import { routerHandler } from "../../../src/router"
6
- import schema from "../../../generated/api-schema"
7
- import { failCode } from "../../../src/fail-code"
8
- import { TSON } from "@southern-aurora/tson"
9
- import { createUlid } from "../utils/create-ulid"
10
- import { configMilkio } from "../../../src/config/milkio"
11
- import { headerToPlainObject } from "../utils/header-to-plain-object"
2
+ import { loggerPushTags, loggerSubmit, useLogger, runtime, MiddlewareEvent } from "..";
3
+ import type { ExecuteId, MilkioApp, Mixin } from "..";
4
+ import { hanldeCatchError } from "../utils/handle-catch-error";
5
+ import { routerHandler } from "../../../src/router";
6
+ import schema from "../../../generated/api-schema";
7
+ import { failCode } from "../../../src/fail-code";
8
+ import { TSON } from "@southern-aurora/tson";
9
+ import { createUlid } from "../utils/create-ulid";
10
+ import { configMilkio } from "../../../src/config/milkio";
11
+ import { headerToPlainObject } from "../utils/header-to-plain-object";
12
12
 
13
13
  export type ExecuteHttpServerOptions = {
14
- /**
15
- * The execution ID generator
16
- * If you have enabled this option, the executeId will be generated each time by calling this method. Otherwise, it will be generated using the built-in method.
17
- *
18
- * @param request
19
- * @returns
20
- */
21
- executeIdGenerator?: (request: Request) => string | Promise<string>;
14
+ /**
15
+ * The execution ID generator
16
+ * If you have enabled this option, the executeId will be generated each time by calling this method. Otherwise, it will be generated using the built-in method.
17
+ *
18
+ * @param request
19
+ * @returns
20
+ */
21
+ executeIdGenerator?: (request: Request) => string | Promise<string>;
22
22
  };
23
23
 
24
24
  export function defineHttpHandler(app: MilkioApp, options: ExecuteHttpServerOptions = {}) {
25
- const fetch = async (request: MilkioHTTPRequest) => {
26
- const fullurl = new URL(request.request.url, `http://${request.request.headers.get("host") ?? "localhost"}`)
27
- const executeId = (options?.executeIdGenerator ? await options.executeIdGenerator(request.request) : createUlid()) as ExecuteId
28
- runtime.execute.executeIds.add(executeId)
29
- const logger = useLogger(executeId)
30
- const ip = (request.request.headers.get("x-forwarded-for") as string | undefined)?.split(",")[0] ?? "0.0.0.0"
31
- const headers = request.request.headers
32
-
33
- loggerPushTags(executeId, {
34
- from: "http-server",
35
- fullUrl: fullurl.pathname,
36
- ip,
37
- method: request.request.method,
38
- // @ts-ignore
39
- requestHeaders: headerToPlainObject(request.request.headers),
40
- timein: new Date().getTime()
41
- })
42
-
43
- const response: MilkioHTTPResponse = {
44
- body: "",
45
- status: 200,
46
- headers: {
47
- "Content-Type": "application/json",
48
- "Access-Control-Allow-Methods": configMilkio.corsAllowMethods ?? "*",
49
- "Access-Control-Allow-Headers": configMilkio.corsAllowHeaders ?? "*",
50
- "Access-Control-Allow-Origin": configMilkio.corsAllowOrigin ?? "*"
51
- }
52
- }
53
-
54
- try {
55
- // Process OPTIONS pre inspection requests
56
- if (request.request.method === "OPTIONS") {
57
- await loggerSubmit(executeId)
58
- runtime.execute.executeIds.delete(executeId)
59
-
60
- return new Response("", {
61
- headers: {
62
- "Access-Control-Allow-Methods": configMilkio.corsAllowMethods ?? "*",
63
- "Access-Control-Allow-Headers": configMilkio.corsAllowHeaders ?? "*",
64
- "Access-Control-Allow-Origin": configMilkio.corsAllowOrigin ?? "*"
65
- }
66
- })
67
- }
68
-
69
- let path = fullurl.pathname.substring(1).split("/")
70
-
71
- // Compatible with API gateway's ability to differentiate versions by path
72
- // see: /src/config/ConfigProgram.ts in "ignorePathLevel"
73
- if (configMilkio.ignorePathLevel !== 0) path = path.slice(configMilkio.ignorePathLevel)
74
-
75
- let pathstr = path.join("/") as keyof (typeof schema)["apiMethodsSchema"]
76
-
77
- // Special processing: do not run middleware when encountering 404 and return quickly
78
- if (!(pathstr in schema.apiMethodsSchema) || pathstr.startsWith('$/')) {
79
- // @ts-ignore
80
- const redirectPath = await routerHandler(pathstr, fullurl)
81
- if (!redirectPath) {
82
- const rawbody = await request.request.text()
83
- loggerPushTags(executeId, {
84
- body: rawbody || "no body"
85
- })
86
- if (!response.body) response.body = `{"executeId":"${executeId}","success":false,"fail":{"code":"NOT_FOUND","message":${JSON.stringify(failCode.NOT_FOUND())}}}`
87
-
88
- loggerPushTags(executeId, {
89
- status: response.status,
90
- responseHeaders: response.headers,
91
- timeout: new Date().getTime()
92
- })
93
-
94
- await loggerSubmit(executeId)
95
- runtime.execute.executeIds.delete(executeId)
96
-
97
- return new Response(response.body, response)
98
- }
99
- pathstr = redirectPath as typeof pathstr
100
- }
101
-
102
- loggerPushTags(executeId, {
103
- path: pathstr
104
- })
105
-
106
- const detail = {
107
- path: pathstr,
108
- ip,
109
- executeId,
110
- fullurl,
111
- request: request.request,
112
- response
113
- }
114
-
115
- // execute api
116
- // after request middleware
117
- await MiddlewareEvent.handle("afterHTTPRequest", [headers, detail])
118
-
119
- const rawbody = await request.request.text()
120
- loggerPushTags(executeId, {
121
- body: rawbody || "no body"
122
- })
123
-
124
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
- let params: any
126
- if (rawbody === "") {
127
- params = undefined
128
- } else {
129
- try {
130
- params = JSON.parse(rawbody)
131
- } catch (error) {
132
- const logger = useLogger(executeId)
133
- logger.log("TIP: body is not json, the content is not empty, but the content is not in a valid JSON format. The original content value can be retrieved via request.request.text()")
134
- params = undefined
135
- }
136
- }
137
-
138
- loggerPushTags(executeId, {
139
- params
140
- })
141
-
142
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
143
- // @ts-ignore
144
- const result = await app._executeCoreToJson(pathstr, params, headers, {
145
- executeId,
146
- logger,
147
- detail
148
- })
149
-
150
- // @ts-ignore
151
- // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression, @typescript-eslint/no-explicit-any
152
- if (!response.body) response.body = result
153
-
154
- // before response middleware
155
- const middlewareResponse = {
156
- value: response.body
157
- }
158
- await MiddlewareEvent.handle("beforeHTTPResponse", [middlewareResponse, detail])
159
-
160
- if (!response.body) response.body = middlewareResponse.value
161
- } catch (error) {
162
- const result = hanldeCatchError(error, executeId)
163
- if (!response.body) response.body = TSON.stringify(result)
164
- }
165
-
166
- loggerPushTags(executeId, {
167
- status: response.status,
168
- responseHeaders: response.headers,
169
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
170
- body: response.body?.toString() ?? "",
171
- timeout: new Date().getTime()
172
- })
173
-
174
- await loggerSubmit(executeId)
175
- runtime.execute.executeIds.delete(executeId)
176
-
177
- return new Response(response.body, response)
178
- }
179
-
180
- return fetch
25
+ const fetch = async (request: MilkioHTTPRequest) => {
26
+ const fullurl = new URL(request.request.url, `http://${request.request.headers.get("host") ?? "localhost"}`);
27
+ const executeId = (options?.executeIdGenerator ? await options.executeIdGenerator(request.request) : createUlid()) as ExecuteId;
28
+ runtime.execute.executeIds.add(executeId);
29
+ const logger = useLogger(executeId);
30
+ const ip = (request.request.headers.get("x-forwarded-for") as string | undefined)?.split(",")[0] ?? "0.0.0.0";
31
+ const headers = request.request.headers;
32
+
33
+ loggerPushTags(executeId, {
34
+ from: "http-server",
35
+ fullUrl: fullurl.pathname,
36
+ ip,
37
+ method: request.request.method,
38
+ // @ts-ignore
39
+ requestHeaders: headerToPlainObject(request.request.headers),
40
+ timein: new Date().getTime(),
41
+ });
42
+
43
+ const response: MilkioHTTPResponse = {
44
+ body: "",
45
+ status: 200,
46
+ headers: {
47
+ "Content-Type": "application/json",
48
+ "Access-Control-Allow-Methods": configMilkio.corsAllowMethods ?? "*",
49
+ "Access-Control-Allow-Headers": configMilkio.corsAllowHeaders ?? "*",
50
+ "Access-Control-Allow-Origin": configMilkio.corsAllowOrigin ?? "*",
51
+ },
52
+ };
53
+
54
+ try {
55
+ // Process OPTIONS pre inspection requests
56
+ if (request.request.method === "OPTIONS") {
57
+ await loggerSubmit(executeId);
58
+ runtime.execute.executeIds.delete(executeId);
59
+
60
+ return new Response("", {
61
+ headers: {
62
+ "Access-Control-Allow-Methods": configMilkio.corsAllowMethods ?? "*",
63
+ "Access-Control-Allow-Headers": configMilkio.corsAllowHeaders ?? "*",
64
+ "Access-Control-Allow-Origin": configMilkio.corsAllowOrigin ?? "*",
65
+ },
66
+ });
67
+ }
68
+
69
+ let path = fullurl.pathname.substring(1).split("/");
70
+
71
+ // Compatible with API gateway's ability to differentiate versions by path
72
+ // see: /src/config/ConfigProgram.ts in "ignorePathLevel"
73
+ if (configMilkio.ignorePathLevel !== 0) path = path.slice(configMilkio.ignorePathLevel);
74
+
75
+ let pathstr = path.join("/") as keyof (typeof schema)["apiMethodsSchema"];
76
+
77
+ // Special processing: do not run middleware when encountering 404 and return quickly
78
+ if (!(pathstr in schema.apiMethodsSchema) || pathstr.startsWith("$/")) {
79
+ // @ts-ignore
80
+ const redirectPath = await routerHandler(pathstr, fullurl);
81
+ if (!redirectPath) {
82
+ const rawbody = await request.request.text();
83
+ loggerPushTags(executeId, {
84
+ body: rawbody || "no body",
85
+ });
86
+ if (!response.body) response.body = `{"executeId":"${executeId}","success":false,"fail":{"code":"NOT_FOUND","message":${JSON.stringify(failCode.NOT_FOUND())}}}`;
87
+
88
+ loggerPushTags(executeId, {
89
+ status: response.status,
90
+ responseHeaders: response.headers,
91
+ timeout: new Date().getTime(),
92
+ });
93
+
94
+ await loggerSubmit(executeId);
95
+ runtime.execute.executeIds.delete(executeId);
96
+
97
+ return new Response(response.body, response);
98
+ }
99
+ pathstr = redirectPath as typeof pathstr;
100
+ }
101
+
102
+ loggerPushTags(executeId, {
103
+ path: pathstr,
104
+ });
105
+
106
+ const detail = {
107
+ path: pathstr,
108
+ ip,
109
+ executeId,
110
+ fullurl,
111
+ request: request.request,
112
+ response,
113
+ };
114
+
115
+ // execute api
116
+ // after request middleware
117
+ await MiddlewareEvent.handle("afterHTTPRequest", [headers, detail]);
118
+
119
+ const rawbody = await request.request.text();
120
+ loggerPushTags(executeId, {
121
+ body: rawbody || "no body",
122
+ });
123
+
124
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ let params: any;
126
+ if (rawbody === "") {
127
+ params = undefined;
128
+ } else {
129
+ try {
130
+ params = JSON.parse(rawbody);
131
+ } catch (error) {
132
+ const logger = useLogger(executeId);
133
+ logger.log("TIP: body is not json, the content is not empty, but the content is not in a valid JSON format. The original content value can be retrieved via request.request.text()");
134
+ params = undefined;
135
+ }
136
+ }
137
+
138
+ loggerPushTags(executeId, {
139
+ params,
140
+ });
141
+
142
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
143
+ // @ts-ignore
144
+ const result = await app._executeCoreToJson(pathstr, params, headers, {
145
+ executeId,
146
+ logger,
147
+ detail,
148
+ });
149
+
150
+ // @ts-ignore
151
+ // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression, @typescript-eslint/no-explicit-any
152
+ if (!response.body) response.body = result;
153
+
154
+ // before response middleware
155
+ const middlewareResponse = {
156
+ value: response.body,
157
+ };
158
+ await MiddlewareEvent.handle("beforeHTTPResponse", [middlewareResponse, detail]);
159
+
160
+ if (!response.body) response.body = middlewareResponse.value;
161
+ } catch (error) {
162
+ const result = hanldeCatchError(error, executeId);
163
+ if (!response.body) response.body = TSON.stringify(result);
164
+ }
165
+
166
+ loggerPushTags(executeId, {
167
+ status: response.status,
168
+ responseHeaders: response.headers,
169
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
170
+ body: response.body?.toString() ?? "",
171
+ timeout: new Date().getTime(),
172
+ });
173
+
174
+ await loggerSubmit(executeId);
175
+ runtime.execute.executeIds.delete(executeId);
176
+
177
+ return new Response(response.body, response);
178
+ };
179
+
180
+ return fetch;
181
181
  }
182
182
 
183
183
  export type MilkioHTTPRequest = {
184
- request: Request;
184
+ request: Request;
185
185
  };
186
186
 
187
187
  export type MilkioHTTPResponse = Mixin<
188
- ResponseInit,
189
- {
190
- body: string | BodyInit;
191
- status: number;
192
- headers: Record<string, string>;
193
- }
188
+ ResponseInit,
189
+ {
190
+ body: string | BodyInit;
191
+ status: number;
192
+ headers: Record<string, string>;
193
+ }
194
194
  >;
@@ -1,9 +1,9 @@
1
- import { type MiddlewareOptions } from ".."
1
+ import type { MiddlewareOptions } from "..";
2
2
 
3
3
  export function defineMiddleware(options: MiddlewareOptions): () => MiddlewareOptions {
4
- return () => ({
5
- ...options,
6
- // @ts-ignore
7
- isMiddleware: true
8
- })
4
+ return () => ({
5
+ ...options,
6
+ // @ts-ignore
7
+ isMiddleware: true,
8
+ });
9
9
  }
@@ -1,13 +1,13 @@
1
1
  export const defineUse = <CreatorFn extends () => Promise<unknown> | unknown>(creatorFn: CreatorFn): (() => Promise<Awaited<ReturnType<CreatorFn>>>) => {
2
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
- let use: any | undefined
2
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
+ let use: any | undefined;
4
4
 
5
- const getUse = async () => {
6
- if (use === undefined) {
7
- use = await creatorFn()
8
- }
9
- return use
10
- }
5
+ const getUse = async () => {
6
+ if (use === undefined) {
7
+ use = await creatorFn();
8
+ }
9
+ return use;
10
+ };
11
11
 
12
- return getUse
13
- }
12
+ return getUse;
13
+ };
package/index.ts CHANGED
@@ -1,36 +1,36 @@
1
1
  // types
2
- export * from "./types"
2
+ export * from "./types";
3
3
 
4
4
  // utils
5
- export * from "./utils/tson"
6
- export * from "./utils/create-ulid"
7
- export * from "./utils/env-to-string"
8
- export * from "./utils/env-to-number"
9
- export * from "./utils/env-to-boolean"
5
+ export * from "./utils/tson";
6
+ export * from "./utils/create-ulid";
7
+ export * from "./utils/env-to-string";
8
+ export * from "./utils/env-to-number";
9
+ export * from "./utils/env-to-boolean";
10
10
  // export * from "./utils/create-template"
11
- export * from "./utils/header-to-plain-object"
11
+ export * from "./utils/header-to-plain-object";
12
12
 
13
13
  // defines
14
- export * from "./defines/define-use"
15
- export * from "./defines/define-api"
16
- export * from "./defines/define-api-test"
17
- export * from "./defines/define-middleware"
14
+ export * from "./defines/define-use";
15
+ export * from "./defines/define-api";
16
+ export * from "./defines/define-api-test";
17
+ export * from "./defines/define-middleware";
18
18
 
19
19
  // kernel
20
- export * from "./kernel/runtime"
21
- export * from "./kernel/logger"
22
- export * from "./kernel/fail"
23
- export * from "./kernel/meta"
24
- export * from "./kernel/context"
25
- export * from "./kernel/validate"
26
- export * from "./kernel/middleware"
20
+ export * from "./kernel/runtime";
21
+ export * from "./kernel/logger";
22
+ export * from "./kernel/fail";
23
+ export * from "./kernel/meta";
24
+ export * from "./kernel/context";
25
+ export * from "./kernel/validate";
26
+ export * from "./kernel/middleware";
27
27
 
28
28
  // handler
29
- export * from "./defines/define-http-handler"
30
- export * from "./defines/define-command-handler"
29
+ export * from "./defines/define-http-handler";
30
+ export * from "./defines/define-command-handler";
31
31
 
32
32
  // api test
33
- export * from "./api-test/index"
33
+ export * from "./api-test/index";
34
34
 
35
35
  // milkio
36
- export * from "./kernel/milkio"
36
+ export * from "./kernel/milkio";
package/kernel/context.ts CHANGED
@@ -1,23 +1,23 @@
1
- import type { ExecuteId, Logger, MilkioHTTPResponse } from ".."
1
+ import type { ExecuteId, Logger, MilkioHTTPResponse } from "..";
2
2
 
3
3
  export type MilkioContext = {
4
- path: string;
5
- executeId: ExecuteId;
6
- headers: Headers;
7
- logger: Logger;
8
- /**
9
- * Additional information about the request
10
- * These are usually only fully implemented when called by an HTTP server
11
- * During testing or when calling between microservices, some or all of the values may be undefined
12
- */
13
- detail: Partial<FrameworkHTTPDetail>;
4
+ path: string;
5
+ executeId: ExecuteId;
6
+ headers: Headers;
7
+ logger: Logger;
8
+ /**
9
+ * Additional information about the request
10
+ * These are usually only fully implemented when called by an HTTP server
11
+ * During testing or when calling between microservices, some or all of the values may be undefined
12
+ */
13
+ detail: Partial<FrameworkHTTPDetail>;
14
14
  };
15
15
 
16
16
  export type FrameworkHTTPDetail = {
17
- path: string;
18
- executeId: ExecuteId;
19
- fullurl: URL;
20
- ip: string;
21
- request: Request;
22
- response: MilkioHTTPResponse;
17
+ path: string;
18
+ executeId: ExecuteId;
19
+ fullurl: URL;
20
+ ip: string;
21
+ request: Request;
22
+ response: MilkioHTTPResponse;
23
23
  };
package/kernel/fail.ts CHANGED
@@ -1,19 +1,19 @@
1
- import { failCode } from "../../../src/fail-code"
1
+ import { failCode } from "../../../src/fail-code";
2
2
 
3
3
  export function reject<Code extends keyof typeof failCode, FailData extends (typeof failCode)[Code]>(code: Code, data: Parameters<FailData>[0]) {
4
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5
- const message = failCode[code]?.(data as any) ?? ""
6
- const error = {
7
- name: "MilkioReject",
8
- code,
9
- message,
10
- data,
11
- stack: ""
12
- }
13
- Error.captureStackTrace(error)
14
- error.stack = error.stack.replace(/\n.*\n/, "\n")
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5
+ const message = failCode[code]?.(data as any) ?? "";
6
+ const error = {
7
+ name: "MilkioReject",
8
+ code,
9
+ message,
10
+ data,
11
+ stack: "",
12
+ };
13
+ Error.captureStackTrace(error);
14
+ error.stack = error.stack.replace(/\n.*\n/, "\n");
15
15
 
16
- return error
16
+ return error;
17
17
  }
18
18
 
19
19
  export type MilkioReject = ReturnType<typeof reject>;