@arkyn/server 3.0.1-beta.21 → 3.0.1-beta.22
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/package.json +1 -1
- package/src/api/arkynLogRequest.ts +0 -118
- package/src/api/deleteRequest.ts +0 -22
- package/src/api/getRequest.ts +0 -20
- package/src/api/makeRequest.ts +0 -118
- package/src/api/patchRequest.ts +0 -22
- package/src/api/postRequest.ts +0 -22
- package/src/api/putRequest.ts +0 -22
- package/src/config/apiInstance.ts +0 -148
- package/src/config/arkynLogInstance.ts +0 -70
- package/src/http/badResponses/badGateway.ts +0 -63
- package/src/http/badResponses/badRequest.ts +0 -63
- package/src/http/badResponses/conflict.ts +0 -63
- package/src/http/badResponses/forbidden.ts +0 -63
- package/src/http/badResponses/notFound.ts +0 -63
- package/src/http/badResponses/notImplemented.ts +0 -63
- package/src/http/badResponses/serverError.ts +0 -63
- package/src/http/badResponses/unauthorized.ts +0 -63
- package/src/http/badResponses/unprocessableEntity.ts +0 -79
- package/src/http/successResponses/created.ts +0 -64
- package/src/http/successResponses/found.ts +0 -67
- package/src/http/successResponses/noContent.ts +0 -42
- package/src/http/successResponses/success.ts +0 -64
- package/src/http/successResponses/updated.ts +0 -64
- package/src/index.ts +0 -31
- package/src/mapper/arkynLogRequestMapper.ts +0 -73
- package/src/services/decodeErrorMessageFromRequest.ts +0 -36
- package/src/services/decodeRequestBody.ts +0 -43
- package/src/services/errorHandler.ts +0 -99
- package/src/services/formParse.ts +0 -86
- package/src/services/getCaller.ts +0 -82
- package/src/services/getScopedParams.ts +0 -43
- package/src/services/httpDebug.ts +0 -61
- package/src/services/measureRouteExecution.ts +0 -31
- package/src/services/schemaValidator.ts +0 -66
- package/src/types/ApiResponseDTO.ts +0 -19
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -5
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Represents a successful HTTP response with a status code of 200 (OK).
|
|
3
|
-
* This class is used to standardize the structure of a "Success" response,
|
|
4
|
-
* including the response body, headers, status, and status text.
|
|
5
|
-
*
|
|
6
|
-
* @template T - The type of the response body.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
class Success<T> {
|
|
10
|
-
body: T;
|
|
11
|
-
headers: ResponseInit["headers"];
|
|
12
|
-
status: number;
|
|
13
|
-
statusText: string;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Creates an instance of the `Success` class.
|
|
17
|
-
*
|
|
18
|
-
* @param body - The response body to be included in the HTTP response.
|
|
19
|
-
* @param init - Optional initialization object for customizing headers, status, and status text.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
constructor(body: T, init?: ResponseInit) {
|
|
23
|
-
this.body = body;
|
|
24
|
-
this.headers = init?.headers || {};
|
|
25
|
-
this.status = init?.status || 200;
|
|
26
|
-
this.statusText = init?.statusText ?? "OK";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Converts the `Success` instance into a `Response` object with a JSON body.
|
|
31
|
-
* This method ensures the response has the appropriate headers, status, and status text.
|
|
32
|
-
*
|
|
33
|
-
* @returns A `Response` object with the serialized JSON body and response metadata.
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
toResponse(): Response {
|
|
37
|
-
const responseInit: ResponseInit = {
|
|
38
|
-
headers: { "Content-Type": "application/json", ...this.headers },
|
|
39
|
-
status: this.status,
|
|
40
|
-
statusText: this.statusText,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
return new Response(JSON.stringify(this.body), responseInit);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Converts the `Success` instance into a `Response` object using the `Response.json` method.
|
|
48
|
-
* This method is an alternative to `toResponse` for generating JSON responses.
|
|
49
|
-
*
|
|
50
|
-
* @returns A `Response` object with the JSON body and response metadata.
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
toJson(): Response {
|
|
54
|
-
const responseInit: ResponseInit = {
|
|
55
|
-
headers: this.headers,
|
|
56
|
-
status: this.status,
|
|
57
|
-
statusText: this.statusText,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
return Response.json(this.body, responseInit);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { Success };
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Represents a successful HTTP response with a status code of 200 (OK) or other custom status codes.
|
|
3
|
-
* This class is used to standardize the structure of an "Updated" response,
|
|
4
|
-
* including the response body, headers, status, and status text.
|
|
5
|
-
*
|
|
6
|
-
* @template T - The type of the response body.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
class Updated<T> {
|
|
10
|
-
body: T;
|
|
11
|
-
headers: ResponseInit["headers"];
|
|
12
|
-
status: number;
|
|
13
|
-
statusText: string;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Creates an instance of the `Updated` class.
|
|
17
|
-
*
|
|
18
|
-
* @param body - The response body to be included in the HTTP response.
|
|
19
|
-
* @param init - Optional initialization object for customizing headers, status, and status text.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
constructor(body: T, init?: ResponseInit) {
|
|
23
|
-
this.body = body;
|
|
24
|
-
this.headers = init?.headers || {};
|
|
25
|
-
this.status = init?.status || 200;
|
|
26
|
-
this.statusText = init?.statusText || "Resource updated successfully";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Converts the `Updated` instance into a `Response` object with a JSON body.
|
|
31
|
-
* This method ensures the response has the appropriate headers, status, and status text.
|
|
32
|
-
*
|
|
33
|
-
* @returns A `Response` object with the serialized JSON body and response metadata.
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
toResponse(): Response {
|
|
37
|
-
const responseInit: ResponseInit = {
|
|
38
|
-
headers: { "Content-Type": "application/json", ...this.headers },
|
|
39
|
-
status: this.status,
|
|
40
|
-
statusText: this.statusText,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
return new Response(JSON.stringify(this.body), responseInit);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Converts the `Updated` instance into a `Response` object using the `Response.json` method.
|
|
48
|
-
* This method is an alternative to `toResponse` for generating JSON responses.
|
|
49
|
-
*
|
|
50
|
-
* @returns A `Response` object with the JSON body and response metadata.
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
toJson(): Response {
|
|
54
|
-
const responseInit: ResponseInit = {
|
|
55
|
-
headers: this.headers,
|
|
56
|
-
status: this.status,
|
|
57
|
-
statusText: this.statusText,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
return Response.json(this.body, responseInit);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { Updated };
|
package/src/index.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// config
|
|
2
|
-
export { ApiInstance } from "./config/apiInstance";
|
|
3
|
-
export { ArkynLogInstance } from "./config/arkynLogInstance";
|
|
4
|
-
|
|
5
|
-
// http bad responses
|
|
6
|
-
export { BadGateway } from "./http/badResponses/badGateway";
|
|
7
|
-
export { BadRequest } from "./http/badResponses/badRequest";
|
|
8
|
-
export { Conflict } from "./http/badResponses/conflict";
|
|
9
|
-
export { Forbidden } from "./http/badResponses/forbidden";
|
|
10
|
-
export { NotFound } from "./http/badResponses/notFound";
|
|
11
|
-
export { NotImplemented } from "./http/badResponses/notImplemented";
|
|
12
|
-
export { ServerError } from "./http/badResponses/serverError";
|
|
13
|
-
export { Unauthorized } from "./http/badResponses/unauthorized";
|
|
14
|
-
export { UnprocessableEntity } from "./http/badResponses/unprocessableEntity";
|
|
15
|
-
|
|
16
|
-
// http success responses
|
|
17
|
-
export { Created } from "./http/successResponses/created";
|
|
18
|
-
export { Found } from "./http/successResponses/found";
|
|
19
|
-
export { NoContent } from "./http/successResponses/noContent";
|
|
20
|
-
export { Success } from "./http/successResponses/success";
|
|
21
|
-
export { Updated } from "./http/successResponses/updated";
|
|
22
|
-
|
|
23
|
-
// services
|
|
24
|
-
export { decodeErrorMessageFromRequest } from "./services/decodeErrorMessageFromRequest";
|
|
25
|
-
export { decodeRequestBody } from "./services/decodeRequestBody";
|
|
26
|
-
export { errorHandler } from "./services/errorHandler";
|
|
27
|
-
export { formParse } from "./services/formParse";
|
|
28
|
-
export { getCaller } from "./services/getCaller";
|
|
29
|
-
export { getScopedParams } from "./services/getScopedParams";
|
|
30
|
-
export { httpDebug } from "./services/httpDebug";
|
|
31
|
-
export { SchemaValidator } from "./services/schemaValidator";
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
type InputProps = {
|
|
2
|
-
status: number;
|
|
3
|
-
url: string;
|
|
4
|
-
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
5
|
-
requestHeaders: HeadersInit;
|
|
6
|
-
responseHeaders: HeadersInit;
|
|
7
|
-
requestBody: any;
|
|
8
|
-
elapsedTime: number;
|
|
9
|
-
responseBody: any;
|
|
10
|
-
queryParams: URLSearchParams;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
type OutputProps = {
|
|
14
|
-
rawUrl: string;
|
|
15
|
-
status: number;
|
|
16
|
-
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
17
|
-
token: string | null;
|
|
18
|
-
elapsedTime: number;
|
|
19
|
-
requestHeaders: Record<string, string>;
|
|
20
|
-
requestBody: Record<string, string>;
|
|
21
|
-
queryParams: Record<string, string>;
|
|
22
|
-
responseHeaders: Record<string, string>;
|
|
23
|
-
responseBody: any;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
class ArkynLogRequestMapper {
|
|
27
|
-
private static mapHeaders(headers: HeadersInit): Record<string, string> {
|
|
28
|
-
if (headers instanceof Headers) {
|
|
29
|
-
return Object.fromEntries(headers.entries());
|
|
30
|
-
} else if (typeof headers === "object") {
|
|
31
|
-
return Object.entries(headers).reduce((acc, [key, value]) => {
|
|
32
|
-
if (typeof value === "string") {
|
|
33
|
-
acc[key] = value;
|
|
34
|
-
} else if (Array.isArray(value)) {
|
|
35
|
-
acc[key] = value.join(", ");
|
|
36
|
-
} else {
|
|
37
|
-
acc[key] = JSON.stringify(value);
|
|
38
|
-
}
|
|
39
|
-
return acc;
|
|
40
|
-
}, {} as Record<string, string>);
|
|
41
|
-
}
|
|
42
|
-
return {};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private static mapQueryParams(
|
|
46
|
-
queryParams: URLSearchParams
|
|
47
|
-
): Record<string, string> {
|
|
48
|
-
const params: Record<string, string> = {};
|
|
49
|
-
|
|
50
|
-
queryParams.forEach((value, key) => {
|
|
51
|
-
params[key] = value;
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return params;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
static handle(props: InputProps): OutputProps {
|
|
58
|
-
return {
|
|
59
|
-
rawUrl: props.url,
|
|
60
|
-
status: props.status,
|
|
61
|
-
method: props.method,
|
|
62
|
-
token: null,
|
|
63
|
-
elapsedTime: props.elapsedTime,
|
|
64
|
-
requestHeaders: this.mapHeaders(props.requestHeaders),
|
|
65
|
-
requestBody: props.requestBody || null,
|
|
66
|
-
queryParams: this.mapQueryParams(props.queryParams),
|
|
67
|
-
responseHeaders: this.mapHeaders(props.responseHeaders),
|
|
68
|
-
responseBody: props.responseBody || null,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export { ArkynLogRequestMapper };
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Decodes an error message from a given request data object or response object.
|
|
3
|
-
*
|
|
4
|
-
* This function attempts to extract a meaningful error message from the provided
|
|
5
|
-
* `data` or `response` objects by checking various properties in a specific order.
|
|
6
|
-
* If no valid error message is found, it returns a default message: "Missing error message".
|
|
7
|
-
*
|
|
8
|
-
* @param data - The data object that may contain error information. It can have properties
|
|
9
|
-
* such as `message`, `error`, or `error.message` that are checked for a string value.
|
|
10
|
-
* @param response - The response object that may contain a `statusText` property
|
|
11
|
-
* representing the HTTP status text.
|
|
12
|
-
* @returns A string representing the decoded error message, or a default message
|
|
13
|
-
* if no error message is found.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
function decodeErrorMessageFromRequest(data: any, response: Response): string {
|
|
17
|
-
if (data?.message && typeof data?.message === "string") {
|
|
18
|
-
return data?.message;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (data?.error && typeof data?.error === "string") {
|
|
22
|
-
return data?.error;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (data?.error?.message && typeof data?.error?.message === "string") {
|
|
26
|
-
return data?.error?.message;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (response?.statusText && typeof response?.statusText === "string") {
|
|
30
|
-
return response?.statusText;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return "Missing error message";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { decodeErrorMessageFromRequest };
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { BadRequest } from "../http/badResponses/badRequest";
|
|
2
|
-
|
|
3
|
-
type DecodeRequestBodyFunction = (request: Request) => Promise<any>;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Decodes the body of an incoming request into a JavaScript object.
|
|
7
|
-
*
|
|
8
|
-
* This function attempts to parse the request body in the following order:
|
|
9
|
-
* 1. Tries to parse the body as JSON.
|
|
10
|
-
* 2. If JSON parsing fails, attempts to parse the body as URL-encoded form data.
|
|
11
|
-
* 3. If both parsing attempts fail, logs the errors and returns an empty object.
|
|
12
|
-
*
|
|
13
|
-
* @param req - The incoming request object containing the body to decode.
|
|
14
|
-
* @returns A promise that resolves to the decoded data as a JavaScript object.
|
|
15
|
-
*
|
|
16
|
-
* @throws Logs errors to the console if the request body cannot be read or parsed.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const decodeRequestBody: DecodeRequestBodyFunction = async (req) => {
|
|
20
|
-
let data: any;
|
|
21
|
-
|
|
22
|
-
const arrayBuffer = await req.arrayBuffer();
|
|
23
|
-
const text = new TextDecoder().decode(arrayBuffer);
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
data = JSON.parse(text);
|
|
27
|
-
} catch (jsonError) {
|
|
28
|
-
try {
|
|
29
|
-
if (text.includes("=")) {
|
|
30
|
-
const formData = new URLSearchParams(text);
|
|
31
|
-
data = Object.fromEntries(formData.entries());
|
|
32
|
-
} else {
|
|
33
|
-
throw new BadRequest("Invalid URLSearchParams format");
|
|
34
|
-
}
|
|
35
|
-
} catch (formDataError) {
|
|
36
|
-
throw new BadRequest("Failed to extract data from request");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return data;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export { decodeRequestBody };
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { BadGateway } from "../http/badResponses/badGateway";
|
|
2
|
-
import { BadRequest } from "../http/badResponses/badRequest";
|
|
3
|
-
import { Conflict } from "../http/badResponses/conflict";
|
|
4
|
-
import { Forbidden } from "../http/badResponses/forbidden";
|
|
5
|
-
import { NotFound } from "../http/badResponses/notFound";
|
|
6
|
-
import { NotImplemented } from "../http/badResponses/notImplemented";
|
|
7
|
-
import { ServerError } from "../http/badResponses/serverError";
|
|
8
|
-
import { Unauthorized } from "../http/badResponses/unauthorized";
|
|
9
|
-
import { UnprocessableEntity } from "../http/badResponses/unprocessableEntity";
|
|
10
|
-
|
|
11
|
-
import { Created } from "../http/successResponses/created";
|
|
12
|
-
import { Found } from "../http/successResponses/found";
|
|
13
|
-
import { NoContent } from "../http/successResponses/noContent";
|
|
14
|
-
import { Success } from "../http/successResponses/success";
|
|
15
|
-
import { Updated } from "../http/successResponses/updated";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Handles errors and converts them into appropriate HTTP responses.
|
|
19
|
-
*
|
|
20
|
-
* This function takes an error object and determines its type to return
|
|
21
|
-
* the corresponding HTTP response. It supports both success and error
|
|
22
|
-
* response types, converting them into a standardized format using the
|
|
23
|
-
* `toResponse` method when applicable.
|
|
24
|
-
*
|
|
25
|
-
* @param error - The error object to handle. It can be an instance of various
|
|
26
|
-
* HTTP response classes or a generic error.
|
|
27
|
-
*
|
|
28
|
-
* @returns The corresponding HTTP response object if the error matches a known
|
|
29
|
-
* type, or `undefined` if no match is found.
|
|
30
|
-
*
|
|
31
|
-
* ### Supported Success Responses:
|
|
32
|
-
* - `Found`
|
|
33
|
-
* - `Created`
|
|
34
|
-
* - `Updated`
|
|
35
|
-
* - `Success`
|
|
36
|
-
* - `NoContent`
|
|
37
|
-
*
|
|
38
|
-
* ### Supported Error Responses:
|
|
39
|
-
* - `BadGateway`
|
|
40
|
-
* - `BadRequest`
|
|
41
|
-
* - `Conflict`
|
|
42
|
-
* - `Forbidden`
|
|
43
|
-
* - `NotFound`
|
|
44
|
-
* - `NotImplemented`
|
|
45
|
-
* - `ServerError`
|
|
46
|
-
* - `Unauthorized`
|
|
47
|
-
* - `UnprocessableEntity`
|
|
48
|
-
*
|
|
49
|
-
* ### Example Usage:
|
|
50
|
-
* ```typescript
|
|
51
|
-
* try {
|
|
52
|
-
* // Some operation that might throw an error
|
|
53
|
-
* } catch (error) {
|
|
54
|
-
* return errorHandler(error);
|
|
55
|
-
* }
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
|
|
59
|
-
function errorHandler(error: any): Response {
|
|
60
|
-
switch (true) {
|
|
61
|
-
case error instanceof Response:
|
|
62
|
-
return error;
|
|
63
|
-
case error instanceof Found:
|
|
64
|
-
return error.toResponse();
|
|
65
|
-
case error instanceof Created:
|
|
66
|
-
return error.toResponse();
|
|
67
|
-
case error instanceof Updated:
|
|
68
|
-
return error.toResponse();
|
|
69
|
-
case error instanceof Success:
|
|
70
|
-
return error.toResponse();
|
|
71
|
-
case error instanceof NoContent:
|
|
72
|
-
return error.toResponse();
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
switch (true) {
|
|
76
|
-
case error instanceof BadGateway:
|
|
77
|
-
return error.toResponse();
|
|
78
|
-
case error instanceof BadRequest:
|
|
79
|
-
return error.toResponse();
|
|
80
|
-
case error instanceof Conflict:
|
|
81
|
-
return error.toResponse();
|
|
82
|
-
case error instanceof Forbidden:
|
|
83
|
-
return error.toResponse();
|
|
84
|
-
case error instanceof NotFound:
|
|
85
|
-
return error.toResponse();
|
|
86
|
-
case error instanceof NotImplemented:
|
|
87
|
-
return error.toResponse();
|
|
88
|
-
case error instanceof ServerError:
|
|
89
|
-
return error.toResponse();
|
|
90
|
-
case error instanceof Unauthorized:
|
|
91
|
-
return error.toResponse();
|
|
92
|
-
case error instanceof UnprocessableEntity:
|
|
93
|
-
return error.toResponse();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return new ServerError("Server error", error).toResponse();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export { errorHandler };
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { ZodType } from "zod";
|
|
2
|
-
|
|
3
|
-
type SuccessResponse<T extends FormParseProps> = {
|
|
4
|
-
success: true;
|
|
5
|
-
data: T[1] extends ZodType<infer U> ? U : never;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
type ErrorResponse = {
|
|
9
|
-
success: false;
|
|
10
|
-
fields: { [x: string]: string };
|
|
11
|
-
fieldErrors: { [x: string]: string };
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
type FormParseProps = [formData: { [k: string]: any }, schema: ZodType];
|
|
15
|
-
|
|
16
|
-
type FormParseReturnType<T extends FormParseProps> =
|
|
17
|
-
| SuccessResponse<T>
|
|
18
|
-
| ErrorResponse;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Parses form data using a Zod schema and returns the result.
|
|
22
|
-
*
|
|
23
|
-
* @template T - A type that extends `FormParseProps`.
|
|
24
|
-
*
|
|
25
|
-
* @param {T} param0 - An array containing the form data and the Zod schema.
|
|
26
|
-
* @param {T[0]} param0[0] - The form data to be validated.
|
|
27
|
-
* @param {T[1]} param0[1] - The Zod schema used for validation.
|
|
28
|
-
*
|
|
29
|
-
* @returns {FormParseReturnType<T>} An object containing the validation result.
|
|
30
|
-
* - If validation fails, it includes:
|
|
31
|
-
* - `success`: A boolean indicating the validation status (false).
|
|
32
|
-
* - `fieldErrors`: An object mapping field names to their respective error messages.
|
|
33
|
-
* - `fields`: The original form data.
|
|
34
|
-
* - If validation succeeds, it includes:
|
|
35
|
-
* - `success`: A boolean indicating the validation status (true).
|
|
36
|
-
* - `data`: The parsed and validated data.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```typescript
|
|
40
|
-
* import { z } from "zod";
|
|
41
|
-
*
|
|
42
|
-
* const schema = z.object({
|
|
43
|
-
* name: z.string().min(1, "Name is required"),
|
|
44
|
-
* age: z.number().min(18, "Must be at least 18"),
|
|
45
|
-
* });
|
|
46
|
-
*
|
|
47
|
-
* const formData = { name: "", age: 17 };
|
|
48
|
-
*
|
|
49
|
-
* const result = formParse([formData, schema]);
|
|
50
|
-
*
|
|
51
|
-
* if (!result.success) {
|
|
52
|
-
* console.log(result.fieldErrors); // { name: "Name is required", age: "Must be at least 18" }
|
|
53
|
-
* } else {
|
|
54
|
-
* console.log(result.data); // Parsed data
|
|
55
|
-
* }
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
|
|
59
|
-
function formParse<T extends FormParseProps>([
|
|
60
|
-
formData,
|
|
61
|
-
schema,
|
|
62
|
-
]: T): FormParseReturnType<T> {
|
|
63
|
-
const zodResponse = schema.safeParse(formData);
|
|
64
|
-
|
|
65
|
-
if (zodResponse.success === false) {
|
|
66
|
-
const errorsObject = Object.fromEntries(
|
|
67
|
-
zodResponse.error.issues.map((item) => {
|
|
68
|
-
console.log(item);
|
|
69
|
-
return [item.path.join("."), item.message];
|
|
70
|
-
})
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
success: zodResponse.success,
|
|
75
|
-
fieldErrors: errorsObject,
|
|
76
|
-
fields: formData,
|
|
77
|
-
};
|
|
78
|
-
} else {
|
|
79
|
-
return {
|
|
80
|
-
success: zodResponse.success,
|
|
81
|
-
data: zodResponse.data as T[1] extends ZodType<infer U> ? U : never,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export { formParse };
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Retrieves information about the caller of the current function.
|
|
5
|
-
*
|
|
6
|
-
* This function analyzes the stack trace to determine the file path and function name
|
|
7
|
-
* of the caller. It excludes stack trace entries related to the `@arkyn/server` package
|
|
8
|
-
* and attempts to resolve the file path relative to the project root directory.
|
|
9
|
-
*
|
|
10
|
-
* @returns An object containing:
|
|
11
|
-
* - `functionName`: The name of the function that called the current function, or "Unknown function" if it cannot be determined.
|
|
12
|
-
* - `callerInfo`: The file path of the caller relative to the project root, or "Unknown caller" if it cannot be determined.
|
|
13
|
-
*/
|
|
14
|
-
function getCaller() {
|
|
15
|
-
const projectRoot = process.cwd();
|
|
16
|
-
|
|
17
|
-
const err = new Error();
|
|
18
|
-
const stack = err.stack || "";
|
|
19
|
-
const stackLines = stack.split("\n").map((line) => line.trim());
|
|
20
|
-
|
|
21
|
-
// The first line is the error message
|
|
22
|
-
// The second line is this function (getCaller)
|
|
23
|
-
// The third line should be the direct caller
|
|
24
|
-
// We start from 2 because indexes are zero-based
|
|
25
|
-
let callerIndex = 2;
|
|
26
|
-
|
|
27
|
-
// Ignore internal or infrastructure lines if necessary
|
|
28
|
-
while (
|
|
29
|
-
callerIndex < stackLines.length &&
|
|
30
|
-
(stackLines[callerIndex].includes("node:internal") ||
|
|
31
|
-
stackLines[callerIndex].includes("/node_modules/"))
|
|
32
|
-
) {
|
|
33
|
-
callerIndex++;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const callerLine = stackLines[callerIndex] || "";
|
|
37
|
-
|
|
38
|
-
let functionName = "Unknown function";
|
|
39
|
-
let callerInfo = "Unknown caller";
|
|
40
|
-
|
|
41
|
-
// Default for named functions: "at functionName (file:line:column)"
|
|
42
|
-
const namedFunctionMatch = callerLine.match(/at\s+([^(\s]+)\s+\(([^)]+)\)/);
|
|
43
|
-
if (namedFunctionMatch) {
|
|
44
|
-
functionName = namedFunctionMatch[1];
|
|
45
|
-
callerInfo = namedFunctionMatch[2];
|
|
46
|
-
}
|
|
47
|
-
// Default for anonymous functions or methods: "at file:line:column"
|
|
48
|
-
else {
|
|
49
|
-
const anonymousFunctionMatch = callerLine.match(/at\s+(.+)/);
|
|
50
|
-
if (anonymousFunctionMatch) {
|
|
51
|
-
callerInfo = anonymousFunctionMatch[1];
|
|
52
|
-
|
|
53
|
-
// Tenta extrair nome da função de padrões como Object.method ou Class.method
|
|
54
|
-
const objectMethodMatch = callerInfo.match(/at\s+([^(\s]+)\s+/);
|
|
55
|
-
if (objectMethodMatch && objectMethodMatch[1] !== "new") {
|
|
56
|
-
functionName = objectMethodMatch[1];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Handles file paths
|
|
62
|
-
if (callerInfo.includes("(")) {
|
|
63
|
-
callerInfo = callerInfo.substring(
|
|
64
|
-
callerInfo.indexOf("(") + 1,
|
|
65
|
-
callerInfo.lastIndexOf(")")
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Remove the line:column part of the file path
|
|
70
|
-
callerInfo = callerInfo.split(":").slice(0, -2).join(":");
|
|
71
|
-
|
|
72
|
-
// Make the path relative to the project
|
|
73
|
-
try {
|
|
74
|
-
callerInfo = path.relative(projectRoot, callerInfo);
|
|
75
|
-
} catch (e) {
|
|
76
|
-
// If it fails to relativize, use the original path
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return { functionName, callerInfo };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export { getCaller };
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
type GetScopedParamsFunction = (
|
|
2
|
-
request: Request,
|
|
3
|
-
scope?: string
|
|
4
|
-
) => URLSearchParams;
|
|
5
|
-
/**
|
|
6
|
-
* Extracts and returns scoped query parameters from a request URL.
|
|
7
|
-
*
|
|
8
|
-
* @param request - The incoming request object containing the URL.
|
|
9
|
-
* @param scope - An optional string representing the scope prefix for filtering query parameters.
|
|
10
|
-
* If no scope is provided, all query parameters are returned.
|
|
11
|
-
*
|
|
12
|
-
* @returns A `URLSearchParams` object containing the scoped query parameters.
|
|
13
|
-
* If a scope is provided, only parameters with keys starting with the scope
|
|
14
|
-
* (e.g., `scope:key`) are included, and the scope prefix is removed from the keys.
|
|
15
|
-
* If no scope is provided, all query parameters are returned as-is.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // Example 1: No scope provided
|
|
19
|
-
* const request = { url: "https://example.com?key1=value1&key2=value2" };
|
|
20
|
-
* const params = getScopedParams(request);
|
|
21
|
-
* console.log(params.toString()); // Output: "key1=value1&key2=value2"
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* // Example 2: Scope provided
|
|
25
|
-
* const request = { url: "https://example.com?scope:key1=value1&scope:key2=value2&key3=value3" };
|
|
26
|
-
* const params = getScopedParams(request, "scope");
|
|
27
|
-
* console.log(params.toString()); // Output: "key1=value1&key2=value2"
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
const getScopedParams: GetScopedParamsFunction = (request, scope = "") => {
|
|
31
|
-
const url = new URL(request.url);
|
|
32
|
-
if (scope === "") return url.searchParams;
|
|
33
|
-
|
|
34
|
-
const scopedSearchParams: [string, string][] = Array.from(
|
|
35
|
-
url.searchParams.entries()
|
|
36
|
-
)
|
|
37
|
-
.filter(([key]) => key.startsWith(`${scope}:`))
|
|
38
|
-
.map(([key, value]) => [key.replace(`${scope}:`, ""), value]);
|
|
39
|
-
|
|
40
|
-
return new URLSearchParams(scopedSearchParams);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export { getScopedParams };
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { getCaller } from "../services/getCaller";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Logs debug information to the console when in development mode or when the
|
|
5
|
-
* `SHOW_ERRORS_IN_CONSOLE` environment variable is set to "true".
|
|
6
|
-
*
|
|
7
|
-
* This function provides detailed information about the caller function,
|
|
8
|
-
* its location, and the provided body and cause, if any.
|
|
9
|
-
*
|
|
10
|
-
* @param name - A string representing the name or context of the debug log.
|
|
11
|
-
* @param body - The main content or data to be logged.
|
|
12
|
-
* @param cause - (Optional) Additional information or error cause to be logged.
|
|
13
|
-
*
|
|
14
|
-
* @remarks
|
|
15
|
-
* The debug logs are only displayed when the application is running in
|
|
16
|
-
* development mode (`NODE_ENV === "development"`) or when the
|
|
17
|
-
* `SHOW_ERRORS_IN_CONSOLE` environment variable is explicitly set to "true".
|
|
18
|
-
*
|
|
19
|
-
* The logs include:
|
|
20
|
-
* - The name of the debug context.
|
|
21
|
-
* - The caller function name and its location.
|
|
22
|
-
* - The provided body content.
|
|
23
|
-
* - The optional cause, if provided.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* httpDebug("FetchUserData", { userId: 123 });
|
|
28
|
-
* ```
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```typescript
|
|
32
|
-
* httpDebug("FetchUserDataError", { userId: 123 }, new Error("User not found"));
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
function httpDebug(name: string, body: any, cause?: any) {
|
|
37
|
-
const isDebugMode =
|
|
38
|
-
process.env.NODE_ENV === "development" ||
|
|
39
|
-
process.env?.SHOW_ERRORS_IN_CONSOLE === "true";
|
|
40
|
-
|
|
41
|
-
if (isDebugMode) {
|
|
42
|
-
const reset = "\x1b[0m";
|
|
43
|
-
const cyan = "\x1b[36m";
|
|
44
|
-
|
|
45
|
-
const debugName = `${cyan}[ARKYN-DEBUG]${reset}`;
|
|
46
|
-
const { callerInfo, functionName } = getCaller();
|
|
47
|
-
|
|
48
|
-
let consoleData = `${debugName} ${name} initialized\n`;
|
|
49
|
-
consoleData += `${debugName} Caller Function: ${functionName}\n`;
|
|
50
|
-
consoleData += `${debugName} Caller Location: ${callerInfo}\n`;
|
|
51
|
-
consoleData += `${debugName} Body: ${JSON.stringify(body, null, 2)}\n`;
|
|
52
|
-
|
|
53
|
-
if (cause) {
|
|
54
|
-
consoleData += `${debugName} Cause: ${JSON.stringify(cause, null, 2)}\n`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log(consoleData);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export { httpDebug };
|