@arkyn/server 3.0.1-beta.55 → 3.0.1-beta.56

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.
Files changed (36) hide show
  1. package/package.json +3 -3
  2. package/src/api/arkynLogRequest.ts +0 -118
  3. package/src/api/deleteRequest.ts +0 -22
  4. package/src/api/getRequest.ts +0 -20
  5. package/src/api/makeRequest.ts +0 -118
  6. package/src/api/patchRequest.ts +0 -22
  7. package/src/api/postRequest.ts +0 -22
  8. package/src/api/putRequest.ts +0 -22
  9. package/src/http/badResponses/badGateway.ts +0 -63
  10. package/src/http/badResponses/badRequest.ts +0 -63
  11. package/src/http/badResponses/conflict.ts +0 -63
  12. package/src/http/badResponses/forbidden.ts +0 -63
  13. package/src/http/badResponses/notFound.ts +0 -63
  14. package/src/http/badResponses/notImplemented.ts +0 -63
  15. package/src/http/badResponses/serverError.ts +0 -63
  16. package/src/http/badResponses/unauthorized.ts +0 -63
  17. package/src/http/badResponses/unprocessableEntity.ts +0 -79
  18. package/src/http/successResponses/created.ts +0 -64
  19. package/src/http/successResponses/found.ts +0 -67
  20. package/src/http/successResponses/noContent.ts +0 -42
  21. package/src/http/successResponses/success.ts +0 -64
  22. package/src/http/successResponses/updated.ts +0 -64
  23. package/src/index.ts +0 -29
  24. package/src/mapper/arkynLogRequestMapper.ts +0 -73
  25. package/src/services/apiService.ts +0 -148
  26. package/src/services/arkynLogService.ts +0 -70
  27. package/src/services/decodeErrorMessageFromRequest.ts +0 -36
  28. package/src/services/decodeRequestBody.ts +0 -43
  29. package/src/services/errorHandler.ts +0 -99
  30. package/src/services/formParse.ts +0 -86
  31. package/src/services/getCaller.ts +0 -81
  32. package/src/services/getScopedParams.ts +0 -43
  33. package/src/services/httpDebug.ts +0 -104
  34. package/src/services/measureRouteExecution.ts +0 -31
  35. package/src/services/schemaValidator.ts +0 -66
  36. package/src/types/ApiResponseDTO.ts +0 -19
@@ -1,148 +0,0 @@
1
- import { deleteRequest } from "../api/deleteRequest";
2
- import { getRequest } from "../api/getRequest";
3
- import { patchRequest } from "../api/patchRequest";
4
- import { postRequest } from "../api/postRequest";
5
- import { putRequest } from "../api/putRequest";
6
-
7
- type ApiServiceConstructorProps = {
8
- baseUrl: string;
9
- baseHeaders?: HeadersInit;
10
- baseToken?: string | null;
11
- };
12
-
13
- type ApiRequestDataWithoutBodyProps = {
14
- headers?: HeadersInit;
15
- token?: string;
16
- };
17
-
18
- type ApiRequestDataWithBodyProps = {
19
- body?: any;
20
- headers?: HeadersInit;
21
- token?: string;
22
- };
23
-
24
- /**
25
- * Class representing an API instance to handle HTTP requests with base configurations.
26
- */
27
-
28
- class ApiService {
29
- private baseUrl: string;
30
- private baseHeaders?: HeadersInit;
31
- private baseToken?: string;
32
-
33
- /**
34
- * Creates an instance of ApiService.
35
- * @param props - The configuration properties for the API instance.
36
- * @param props.baseUrl - The base URL for the API.
37
- * @param props.baseHeaders - Optional base headers to include in all requests.
38
- * @param props.baseToken - Optional base token for authorization.
39
- */
40
-
41
- constructor(props: ApiServiceConstructorProps) {
42
- this.baseUrl = props.baseUrl;
43
- this.baseHeaders = props.baseHeaders || undefined;
44
- this.baseToken = props.baseToken || undefined;
45
- }
46
-
47
- /**
48
- * Generates the full URL by appending the route to the base URL.
49
- * @param route - The route to append to the base URL.
50
- * @returns The full URL as a string.
51
- */
52
-
53
- private generateURL(route: string) {
54
- return this.baseUrl + route;
55
- }
56
-
57
- /**
58
- * Generates the headers for a request by merging base headers, provided headers, and tokens.
59
- * @param initHeaders - Initial headers to include in the request.
60
- * @param token - Optional token to override the base token.
61
- * @returns The merged headers as a HeadersInit object.
62
- */
63
-
64
- private generateHeaders(
65
- initHeaders: HeadersInit,
66
- token?: string
67
- ): HeadersInit {
68
- let headers: HeadersInit = {};
69
- if (this.baseToken) headers = { Authorization: `Bearer ${this.baseToken}` };
70
- if (this.baseHeaders) headers = { ...headers, ...this.baseHeaders };
71
-
72
- if (initHeaders) headers = { ...headers, ...initHeaders };
73
- if (token) headers = { ...headers, Authorization: `Bearer ${token}` };
74
-
75
- return headers;
76
- }
77
-
78
- /**
79
- * Sends a get request to the specified route.
80
- * @param route - The API route to send the get request to.
81
- * @param data - The request data, including optional headers and token.
82
- * @returns The API response data.
83
- */
84
-
85
- async get(route: string, data?: ApiRequestDataWithoutBodyProps) {
86
- const url = this.generateURL(route);
87
- const headers = this.generateHeaders(data?.headers || {}, data?.token);
88
- return await getRequest(url, headers);
89
- }
90
-
91
- /**
92
- * Sends a post request to the specified route.
93
- * @param route - The API route to send the post request to.
94
- * @param data - The request data, including body, optional headers, and token.
95
- * @returns The API response data.
96
- */
97
-
98
- async post(route: string, data?: ApiRequestDataWithBodyProps) {
99
- const url = this.generateURL(route);
100
- const headers = this.generateHeaders(data?.headers || {}, data?.token);
101
- const body = data?.body;
102
- return await postRequest(url, headers, body);
103
- }
104
-
105
- /**
106
- * Sends a put request to the specified route.
107
- * @param route - The API route to send the put request to.
108
- * @param data - The request data, including body, optional headers, and token.
109
- * @returns The API response data.
110
- */
111
-
112
- async put(route: string, data?: ApiRequestDataWithBodyProps) {
113
- const url = this.generateURL(route);
114
- const headers = this.generateHeaders(data?.headers || {}, data?.token);
115
- const body = data?.body;
116
- return await putRequest(url, headers, body);
117
- }
118
-
119
- /**
120
- * Sends a patch request to the specified route.
121
- * @param route - The API route to send the patch request to.
122
- * @param data - The request data, including body, optional headers, and token.
123
- * @returns The API response data.
124
- */
125
-
126
- async patch(route: string, data?: ApiRequestDataWithBodyProps) {
127
- const url = this.generateURL(route);
128
- const headers = this.generateHeaders(data?.headers || {}, data?.token);
129
- const body = data?.body;
130
- return await patchRequest(url, headers, body);
131
- }
132
-
133
- /**
134
- * Sends a delete request to the specified route.
135
- * @param route - The API route to send the delete request to.
136
- * @param data - The request data, including body, optional headers, and token.
137
- * @returns The API response data.
138
- */
139
-
140
- async delete(route: string, data?: ApiRequestDataWithBodyProps) {
141
- const url = this.generateURL(route);
142
- const headers = this.generateHeaders(data?.headers || {}, data?.token);
143
- const body = data?.body;
144
- return await deleteRequest(url, headers, body);
145
- }
146
- }
147
-
148
- export { ApiService };
@@ -1,70 +0,0 @@
1
- type ArkynConfigProps = {
2
- arkynTrafficSourceId: string;
3
- arkynUserToken: string;
4
- arkynApiUrl: string;
5
- };
6
-
7
- type SetArkynConfigProps = {
8
- arkynTrafficSourceId: string;
9
- arkynUserToken: string;
10
- arkynLogBaseApiUrl?: string;
11
- };
12
-
13
- /**
14
- * The `ArkynLogService` class manages the configuration for the arkyn flow.
15
- * It allows you to set and retrieve the arkyn configuration, including the traffic source ID,
16
- * user token, and API URL.
17
- */
18
-
19
- class ArkynLogService {
20
- private static arkynConfig?: ArkynConfigProps;
21
-
22
- /**
23
- * Sets the configuration for the arkyn. This method initializes the arkyn configuration
24
- * with the provided `arkynConfig` values. If the configuration has already been set,
25
- * the method will return early without making any changes.
26
- *
27
- * @param arkynConfig - An object containing the arkyn configuration properties.
28
- * @param arkynConfig.arkynTrafficSourceId - The key used to identify the arkyn.
29
- * @param arkynConfig.arkynUserToken - The user token for authenticating with the arkyn.
30
- * @param arkynConfig.arkynLogBaseApiUrl - (Optional) The API URL for the arkyn. If not provided,
31
- * a default URL will be used.
32
- */
33
-
34
- static setArkynConfig(arkynConfig: SetArkynConfigProps) {
35
- if (!!this.arkynConfig) return;
36
-
37
- let defaultArkynURL = `https://logs-arkyn-flow-logs.vw6wo7.easypanel.host`;
38
- let arkynLogBaseApiUrl = arkynConfig.arkynLogBaseApiUrl || defaultArkynURL;
39
-
40
- arkynLogBaseApiUrl =
41
- arkynLogBaseApiUrl + "/http-traffic-records/:trafficSourceId";
42
-
43
- this.arkynConfig = {
44
- arkynTrafficSourceId: arkynConfig.arkynTrafficSourceId,
45
- arkynUserToken: arkynConfig.arkynUserToken,
46
- arkynApiUrl: arkynLogBaseApiUrl,
47
- };
48
- }
49
-
50
- /**
51
- * Retrieves the current arkyn configuration for the ArkynLogService.
52
- *
53
- * @returns {ArkynConfigProps | undefined} The current arkyn configuration if set,
54
- * or `undefined` if no configuration has been initialized.
55
- */
56
- static getArkynConfig(): ArkynConfigProps | undefined {
57
- return this.arkynConfig;
58
- }
59
-
60
- /**
61
- * Resets the arkyn configuration to `undefined`.
62
- * This method can be used to clear the current configuration.
63
- */
64
-
65
- static resetArkynConfig() {
66
- this.arkynConfig = undefined;
67
- }
68
- }
69
-
70
- export { ArkynLogService };
@@ -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,81 +0,0 @@
1
- import path from "path";
2
- import { HttpDebugService } from "./httpDebug";
3
-
4
- /**
5
- * Retrieves information about the caller of the current function.
6
- *
7
- * This function analyzes the stack trace to determine the file path and function name
8
- * of the caller. It excludes stack trace entries related to the `@arkyn/server` package
9
- * and attempts to resolve the file path relative to the project root directory.
10
- *
11
- * @returns An object containing:
12
- * - `functionName`: The name of the function that called the current function, or "Unknown function" if it cannot be determined.
13
- * - `callerInfo`: The file path of the caller relative to the project root, or "Unknown caller" if it cannot be determined.
14
- */
15
-
16
- function getCaller() {
17
- const projectRoot = process.cwd();
18
-
19
- const err = new Error();
20
- const stack = err.stack || "";
21
- const stackLines = stack.split("\n").map((line) => line.trim());
22
-
23
- const ignoreFile = HttpDebugService.ignoreFile;
24
-
25
- let callerIndex = 2;
26
-
27
- while (
28
- callerIndex < stackLines.length &&
29
- (stackLines[callerIndex].includes("node:internal") ||
30
- stackLines[callerIndex].includes("/node_modules/"))
31
- ) {
32
- callerIndex++;
33
- }
34
-
35
- if (ignoreFile) {
36
- while (
37
- callerIndex < stackLines.length &&
38
- stackLines[callerIndex].includes(ignoreFile)
39
- ) {
40
- callerIndex++;
41
- }
42
- }
43
-
44
- const callerLine = stackLines[callerIndex] || "";
45
-
46
- let functionName = "Unknown function";
47
- let callerInfo = "Unknown caller";
48
-
49
- const namedFunctionMatch = callerLine.match(/at\s+([^(\s]+)\s+\(([^)]+)\)/);
50
- if (namedFunctionMatch) {
51
- functionName = namedFunctionMatch[1];
52
- callerInfo = namedFunctionMatch[2];
53
- } else {
54
- const anonymousFunctionMatch = callerLine.match(/at\s+(.+)/);
55
- if (anonymousFunctionMatch) {
56
- callerInfo = anonymousFunctionMatch[1];
57
-
58
- const objectMethodMatch = callerInfo.match(/at\s+([^(\s]+)\s+/);
59
- if (objectMethodMatch && objectMethodMatch[1] !== "new") {
60
- functionName = objectMethodMatch[1];
61
- }
62
- }
63
- }
64
-
65
- if (callerInfo.includes("(")) {
66
- callerInfo = callerInfo.substring(
67
- callerInfo.indexOf("(") + 1,
68
- callerInfo.lastIndexOf(")")
69
- );
70
- }
71
-
72
- callerInfo = callerInfo.split(":").slice(0, -2).join(":");
73
-
74
- try {
75
- callerInfo = path.relative(projectRoot, callerInfo);
76
- } catch (e) {}
77
-
78
- return { functionName, callerInfo };
79
- }
80
-
81
- 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 };