@nestia/fetcher 1.6.7 → 2.0.0-dev.20230830

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.
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IFetchRoute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IFetchRoute.js","sourceRoot":"","sources":["../../src/internal/IFetchRoute.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestia/fetcher",
3
- "version": "1.6.7",
3
+ "version": "2.0.0-dev.20230830",
4
4
  "description": "Fetcher library of Nestia SDK",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
package/src/AesPkcs5.ts CHANGED
@@ -26,7 +26,6 @@ export namespace AesPkcs5 {
26
26
  key,
27
27
  iv,
28
28
  );
29
-
30
29
  return cipher.update(data, "utf8", "base64") + cipher.final("base64");
31
30
  }
32
31
 
@@ -0,0 +1,115 @@
1
+ import { AesPkcs5 } from "./AesPkcs5";
2
+ import { IConnection } from "./IConnection";
3
+ import { IEncryptionPassword } from "./IEncryptionPassword";
4
+ import { Primitive } from "./Primitive";
5
+ import { FetcherBase } from "./internal/FetcherBase";
6
+ import { IFetchRoute } from "./internal/IFetchRoute";
7
+
8
+ /**
9
+ * Utility class for `fetch` functions used in `@nestia/sdk` with encryption.
10
+ *
11
+ * `EncryptedFetcher` is a utility class designed for SDK functions generated by
12
+ * [`@nestia/sdk`](https://nestia.io/docs/sdk/sdk), interacting with the remote
13
+ * HTTP API encrypted by AES-PKCS algorithm. In other words, this is a collection of
14
+ * dedicated `fetch()` functions for `@nestia/sdk` with encryption.
15
+ *
16
+ * For reference, `EncryptedFetcher` class being used only when target controller
17
+ * method is encrypting body data by `@EncryptedRoute` or `@EncryptedBody` decorators.
18
+ * If those decorators are not used, {@link PlainFetcher} class would be used instead.
19
+ *
20
+ * @author Jeongho Nam - https://github.com/samchon
21
+ */
22
+ export namespace EncryptedFetcher {
23
+ /**
24
+ * Fetch function only for `HEAD` method.
25
+ *
26
+ * @param connection Connection information for the remote HTTP server
27
+ * @param route Route information about the target API
28
+ * @return Nothing because of `HEAD` method
29
+ */
30
+ export function fetch(
31
+ connection: IConnection,
32
+ route: IFetchRoute<"HEAD">,
33
+ ): Promise<void>;
34
+
35
+ /**
36
+ * Fetch function only for `GET` method.
37
+ *
38
+ * @param connection Connection information for the remote HTTP server
39
+ * @param route Route information about the target API
40
+ * @return Response body data from the remote API
41
+ */
42
+ export function fetch<Output>(
43
+ connection: IConnection,
44
+ route: IFetchRoute<"GET">,
45
+ ): Promise<Primitive<Output>>;
46
+
47
+ /**
48
+ * Fetch function for the `POST`, `PUT`, `PATCH` and `DELETE` methods.
49
+ *
50
+ * @param connection Connection information for the remote HTTP server
51
+ * @param route Route information about the target API
52
+ * @return Response body data from the remote API
53
+ */
54
+ export function fetch<Input, Output>(
55
+ connection: IConnection,
56
+ route: IFetchRoute<"POST" | "PUT" | "PATCH" | "DELETE">,
57
+ input?: Input,
58
+ stringify?: (input: Input) => string,
59
+ ): Promise<Primitive<Output>>;
60
+
61
+ export async function fetch<Input, Output>(
62
+ connection: IConnection,
63
+ route: IFetchRoute<
64
+ "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT"
65
+ >,
66
+ input?: Input,
67
+ stringify?: (input: Input) => string,
68
+ ): Promise<Primitive<Output>> {
69
+ if (
70
+ (route.request?.encrypted === true || route.response?.encrypted) &&
71
+ connection.encryption === undefined
72
+ )
73
+ throw new Error(
74
+ "Error on EncryptedFetcher.fetch(): the encryption password has not been configured.",
75
+ );
76
+ const closure =
77
+ typeof connection.encryption === "function"
78
+ ? (direction: "encode" | "decode") =>
79
+ (
80
+ headers: Record<
81
+ string,
82
+ IConnection.HeaderValue | undefined
83
+ >,
84
+ body: string,
85
+ ) =>
86
+ (
87
+ connection.encryption as IEncryptionPassword.Closure
88
+ )({
89
+ headers,
90
+ body,
91
+ direction,
92
+ })
93
+ : () => () => connection.encryption as IEncryptionPassword;
94
+
95
+ return FetcherBase.fetch({
96
+ className: "EncryptedFetcher",
97
+ encode:
98
+ route.request?.encrypted === true
99
+ ? (input, headers) => {
100
+ const p = closure("encode")(headers, input);
101
+ return AesPkcs5.encrypt(input, p.key, p.iv);
102
+ }
103
+ : (input) => input,
104
+ decode:
105
+ route.response?.encrypted === true
106
+ ? (input, headers) => {
107
+ const p = closure("decode")(headers, input);
108
+ return JSON.parse(
109
+ AesPkcs5.decrypt(input, p.key, p.iv),
110
+ );
111
+ }
112
+ : (input) => input,
113
+ })(connection, route, input, stringify);
114
+ }
115
+ }
@@ -30,11 +30,6 @@ export interface IConnection<Headers extends object = {}> {
30
30
  headers?: Record<string, IConnection.HeaderValue> &
31
31
  IConnection.Headerify<Headers>;
32
32
 
33
- /**
34
- * Encryption password of its closure function.
35
- */
36
- encryption?: IEncryptionPassword | IEncryptionPassword.Closure;
37
-
38
33
  /**
39
34
  * Use simulation mode.
40
35
  *
@@ -56,6 +51,15 @@ export interface IConnection<Headers extends object = {}> {
56
51
  * Additional options for the `fetch` function.
57
52
  */
58
53
  options?: IConnection.IOptions;
54
+
55
+ /**
56
+ * Encryption password of its closure function.
57
+ *
58
+ * Define it only when target backend server is encrypting body data through
59
+ * `@EncryptedRoute` or `@EncryptedBody` decorators of `@nestia/core` for
60
+ * security reason.
61
+ */
62
+ encryption?: IEncryptionPassword | IEncryptionPassword.Closure;
59
63
  }
60
64
  export namespace IConnection {
61
65
  /**
@@ -1,3 +1,5 @@
1
+ import { IConnection } from "./IConnection";
2
+
1
3
  /**
2
4
  * Encryption password.
3
5
  *
@@ -31,18 +33,18 @@ export namespace IEncryptionPassword {
31
33
  /**
32
34
  * Encryption password getter.
33
35
  *
34
- * @param param Request or response headers and body content
35
- * @param encoded Be encoded or to be decoded
36
+ * @param props Properties for predication
36
37
  * @returns Encryption password
37
38
  */
38
- (param: IParameter, encoded: boolean): IEncryptionPassword;
39
+ (props: IProps): IEncryptionPassword;
39
40
  }
40
41
 
41
42
  /**
42
- * Parameter for the closure.
43
+ * Properties for the closure.
43
44
  */
44
- export interface IParameter {
45
- headers: Record<string, string>;
45
+ export interface IProps {
46
+ headers: Record<string, IConnection.HeaderValue | undefined>;
46
47
  body: string;
48
+ direction: "encode" | "decode";
47
49
  }
48
50
  }
@@ -0,0 +1,82 @@
1
+ import { IConnection } from "./IConnection";
2
+ import { Primitive } from "./Primitive";
3
+
4
+ import { IFetchRoute } from "./internal/IFetchRoute";
5
+ import { FetcherBase } from "./internal/FetcherBase";
6
+
7
+ /**
8
+ * Utility class for `fetch` functions used in `@nestia/sdk`.
9
+ *
10
+ * `PlainFetcher` is a utility class designed for SDK functions generated by
11
+ * [`@nestia/sdk`](https://nestia.io/docs/sdk/sdk), interacting with the remote
12
+ * HTTP sever API. In other words, this is a collection of dedicated `fetch()`
13
+ * functions for `@nestia/sdk`.
14
+ *
15
+ * For reference, `PlainFetcher` class does not encrypt or decrypt the body data
16
+ * at all. It just delivers plain data without any post processing. If you've
17
+ * defined a controller method through `@EncryptedRoute` or `@EncryptedBody`
18
+ * decorator, then {@liink EncryptedFetcher} class would be used instead.
19
+ *
20
+ * @author Jeongho Nam - https://github.com/samchon
21
+ */
22
+ export namespace PlainFetcher {
23
+ /**
24
+ * Fetch function only for `HEAD` method.
25
+ *
26
+ * @param connection Connection information for the remote HTTP server
27
+ * @param route Route information about the target API
28
+ * @return Nothing because of `HEAD` method
29
+ */
30
+ export function fetch(
31
+ connection: IConnection,
32
+ route: IFetchRoute<"HEAD">,
33
+ ): Promise<void>;
34
+
35
+ /**
36
+ * Fetch function only for `GET` method.
37
+ *
38
+ * @param connection Connection information for the remote HTTP server
39
+ * @param route Route information about the target API
40
+ * @return Response body data from the remote API
41
+ */
42
+ export function fetch<Output>(
43
+ connection: IConnection,
44
+ route: IFetchRoute<"GET">,
45
+ ): Promise<Primitive<Output>>;
46
+
47
+ /**
48
+ * Fetch function for the `POST`, `PUT`, `PATCH` and `DELETE` methods.
49
+ *
50
+ * @param connection Connection information for the remote HTTP server
51
+ * @param route Route information about the target API
52
+ * @return Response body data from the remote API
53
+ */
54
+ export function fetch<Input, Output>(
55
+ connection: IConnection,
56
+ route: IFetchRoute<"POST" | "PUT" | "PATCH" | "DELETE">,
57
+ input?: Input,
58
+ stringify?: (input: Input) => string,
59
+ ): Promise<Primitive<Output>>;
60
+
61
+ export async function fetch<Input, Output>(
62
+ connection: IConnection,
63
+ route: IFetchRoute<
64
+ "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT"
65
+ >,
66
+ input?: Input,
67
+ stringify?: (input: Input) => string,
68
+ ): Promise<Primitive<Output>> {
69
+ if (
70
+ route.request?.encrypted === true ||
71
+ route.response?.encrypted === true
72
+ )
73
+ throw new Error(
74
+ "Error on PlainFetcher.fetch(): PlainFetcher doesn't have encryption ability. Use EncryptedFetcher instead.",
75
+ );
76
+ return FetcherBase.fetch({
77
+ className: "PlainFetcher",
78
+ encode: (input) => input,
79
+ decode: (input) => input,
80
+ })(connection, route, input, stringify);
81
+ }
82
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,3 @@
1
1
  export * from "./IConnection";
2
- export * from "./IEncryptionPassword";
3
2
  export * from "./Primitive";
4
-
5
- export * from "./AesPkcs5";
6
- export * from "./Fetcher";
7
3
  export * from "./HttpError";
@@ -0,0 +1,156 @@
1
+ import import2 from "import2";
2
+ import { IConnection } from "../IConnection";
3
+ import { Primitive } from "../Primitive";
4
+ import { IFetchRoute } from "./IFetchRoute";
5
+ import { Singleton } from "./Singleton";
6
+ import { HttpError } from "../HttpError";
7
+
8
+ export namespace FetcherBase {
9
+ export interface IProps {
10
+ className: string;
11
+ encode: (
12
+ input: string,
13
+ headers: Record<string, IConnection.HeaderValue | undefined>,
14
+ ) => string;
15
+ decode: (
16
+ input: string,
17
+ headers: Record<string, IConnection.HeaderValue | undefined>,
18
+ ) => any;
19
+ }
20
+
21
+ export const fetch =
22
+ (props: IProps) =>
23
+ async <Input, Output>(
24
+ connection: IConnection,
25
+ route: IFetchRoute<
26
+ "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT"
27
+ >,
28
+ input?: Input,
29
+ stringify?: (input: Input) => string,
30
+ ): Promise<Primitive<Output>> => {
31
+ //----
32
+ // REQUEST MESSSAGE
33
+ //----
34
+ // METHOD & HEADERS
35
+ const headers: Record<string, IConnection.HeaderValue | undefined> =
36
+ {
37
+ ...(connection.headers ?? {}),
38
+ };
39
+ if (input !== undefined) {
40
+ if (route.request?.type === undefined)
41
+ throw new Error(
42
+ `Error on ${props.className}.fetch(): no content-type being configured.`,
43
+ );
44
+ headers["Content-Type"] = route.request.type;
45
+ }
46
+
47
+ // INIT REQUEST DATA
48
+ const init: RequestInit = {
49
+ ...(connection.options ?? {}),
50
+ method: route.method,
51
+ headers: (() => {
52
+ const output: [string, string][] = [];
53
+ for (const [key, value] of Object.entries(headers))
54
+ if (value === undefined) continue;
55
+ else if (Array.isArray(value))
56
+ for (const v of value)
57
+ output.push([key, String(v)]);
58
+ else output.push([key, String(value)]);
59
+ return output;
60
+ })(),
61
+ body:
62
+ input !== undefined
63
+ ? props.encode(
64
+ // BODY TRANSFORM
65
+ route.request?.type !== "text/plain"
66
+ ? (stringify ?? JSON.stringify)(input)
67
+ : String(input),
68
+ headers,
69
+ )
70
+ : undefined,
71
+ };
72
+
73
+ //----
74
+ // RESPONSE MESSSAGE
75
+ //----
76
+ // URL SPECIFICATION
77
+ const path: string =
78
+ connection.host[connection.host.length - 1] !== "/" &&
79
+ route.path[0] !== "/"
80
+ ? `/${route.path}`
81
+ : route.path;
82
+ const url: URL = new URL(`${connection.host}${path}`);
83
+
84
+ // DO FETCH
85
+ const response: Response = await (
86
+ await polyfill.get()
87
+ )(url.href, init);
88
+
89
+ // VALIDATE RESPONSE
90
+ if (
91
+ (route.status !== undefined &&
92
+ route.status !== null &&
93
+ response.status !== route.status) ||
94
+ ((route.status === undefined || route.status === null) &&
95
+ response.status !== 200 &&
96
+ response.status !== 201)
97
+ )
98
+ throw new HttpError(
99
+ route.method,
100
+ path,
101
+ response.status,
102
+ await response.text(),
103
+ );
104
+ else if (
105
+ route.response?.type &&
106
+ (response.headers.get("content-type") ?? "")?.indexOf(
107
+ route.response.type,
108
+ ) === -1
109
+ )
110
+ throw new Error(
111
+ `Error on ${
112
+ props.className
113
+ }.fetch(): response type mismatched - expected ${
114
+ route.response.type
115
+ }, but ${response.headers.get("content-type")}.`,
116
+ );
117
+
118
+ // RETURNS
119
+ if (route.method === "HEAD") return undefined!;
120
+ else if (route.response?.type === "application/json")
121
+ return response.json();
122
+ return props.decode(
123
+ await response.text(),
124
+ response_headers_to_object(response.headers),
125
+ ) as Primitive<Output>;
126
+ };
127
+ }
128
+
129
+ const polyfill = new Singleton(async (): Promise<typeof fetch> => {
130
+ if (
131
+ typeof global === "object" &&
132
+ typeof global.process === "object" &&
133
+ typeof global.process.versions === "object" &&
134
+ typeof global.process.versions.node !== undefined
135
+ ) {
136
+ if (global.fetch === undefined)
137
+ global.fetch = ((await import2("node-fetch")) as any).default;
138
+ return (global as any).fetch;
139
+ }
140
+ return window.fetch;
141
+ });
142
+
143
+ const response_headers_to_object = (
144
+ headers: Headers,
145
+ ): Record<string, IConnection.HeaderValue | undefined> => {
146
+ const output: Record<string, IConnection.HeaderValue> = {};
147
+ headers.forEach((value, key) => {
148
+ if (key === "set-cookie") {
149
+ output[key] ??= [];
150
+ (output[key] as string[]).push(
151
+ ...value.split(";").map((str) => str.trim()),
152
+ );
153
+ } else output[key] = value;
154
+ });
155
+ return output;
156
+ };
@@ -0,0 +1,36 @@
1
+ export interface IFetchRoute<
2
+ Method extends "HEAD" | "GET" | "POST" | "PUT" | "PATCH" | "DELETE",
3
+ > {
4
+ /**
5
+ * Method of the HTTP request.
6
+ */
7
+ method: Method;
8
+
9
+ /**
10
+ * Path of the HTTP request.
11
+ */
12
+ path: string;
13
+
14
+ /**
15
+ * Request body data info.
16
+ */
17
+ request: Method extends "DELETE" | "POST" | "PUT" | "PATCH"
18
+ ? IRoute.IBody | null
19
+ : null;
20
+
21
+ /**
22
+ * Response body data info.
23
+ */
24
+ response: Method extends "HEAD" ? null : IRoute.IBody;
25
+
26
+ /**
27
+ * When special status code being used.
28
+ */
29
+ status?: null | number;
30
+ }
31
+ export namespace IRoute {
32
+ export interface IBody {
33
+ type: "application/json" | "text/plain";
34
+ encrypted?: boolean;
35
+ }
36
+ }
package/lib/Fetcher.d.ts DELETED
@@ -1,73 +0,0 @@
1
- import { IConnection } from "./IConnection";
2
- import { Primitive } from "./Primitive";
3
- /**
4
- * Fetcher, utility class for the [**Nestia**](https://github.com/samchon/nestia) fetch.
5
- *
6
- * `Fetcher` is a utility class providing the {@link Fetcher.fetch} functions who're being
7
- * used by all of the SDK libraries, interacting with the remote HTTP servers, who are
8
- * generated by the [**Nestia**](https://github.com/samchon/nestia).
9
- *
10
- * As this `Fetcher` be used only by the [**Nestia**](https://github.com/samchon/nestia)
11
- * generated SDK libraries, you don't need to handle this class directly. It may only be
12
- * appeared in the source codes of the [**Nestia**](https://github.com/samchon/nestia)
13
- * generated SDK libraries.
14
- *
15
- * @author Jeongho Nam - https://github.com/samchon
16
- */
17
- export declare class Fetcher {
18
- static fetch(connection: IConnection, encrypted: Fetcher.IEncrypted, method: "HEAD", path: string): Promise<void>;
19
- /**
20
- * Fetch function for the `GET` methods.
21
- *
22
- * @param connection Connection information for the remote HTTP server
23
- * @param encrypted Whether the request/response body be encrypted or not
24
- * @param method Method of the HTTP request
25
- * @param path Path of the HTTP request
26
- * @return Response body data from the remote HTTP server
27
- */
28
- static fetch<Output>(connection: IConnection, encrypted: Fetcher.IEncrypted, method: "GET", path: string): Promise<Primitive<Output>>;
29
- /**
30
- * Fetch function for the `POST`, `PUT`, `PATCH` and `DELETE` methods.
31
- *
32
- * @param connection Connection information for the remote HTTP server
33
- * @param encrypted Whether the request/response body be encrypted or not
34
- * @param method Method of the HTTP request
35
- * @param path Path of the HTTP request
36
- * @param input Request body data for the HTTP request
37
- * @param stringify JSON string conversion function, default is the `JSON.stringify`
38
- * @return Response body data from the remote HTTP server
39
- */
40
- static fetch<Input, Output>(connection: IConnection, encrypted: Fetcher.IEncrypted, method: "POST" | "PUT" | "PATCH" | "DELETE", path: string, input?: Input, stringify?: (input: Input) => string): Promise<Primitive<Output>>;
41
- }
42
- export declare namespace Fetcher {
43
- /**
44
- * Whether be encrypted or not.
45
- *
46
- * `Fetcher.IEncrypted` is a type of interface who represents whether the HTTP request
47
- * and response body must be encrypted or not.
48
- *
49
- * Like the {@link Fetcher} who are being used by all of the SDK libraries that are
50
- * generated by the [Nestia](https://github.com/samchon/nestia), this `IEncrypted`
51
- * interface would be used by the [Nestia](https://github.com/samchon/nestia) generated
52
- * SDK libaries.
53
- *
54
- * As this `Fetcher` be used only by the [**Nestia**](https://github.com/samchon/nestia)
55
- * generated SDK libraries, you don't need to handle this class directly. It may only be
56
- * appeared in the source codes of the [**Nestia**](https://github.com/samchon/nestia)
57
- * generated SDK libraries.
58
- */
59
- interface IEncrypted {
60
- /**
61
- * Whether the request body be encrypted or not.
62
- */
63
- request?: boolean;
64
- /**
65
- * Whether the response body be encrypted or not.
66
- */
67
- response: boolean;
68
- /**
69
- * When special status code is allowed.
70
- */
71
- status?: number;
72
- }
73
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"Fetcher.js","sourceRoot":"","sources":["../src/Fetcher.ts"],"names":[],"mappings":"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"}