@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.
package/src/Fetcher.ts DELETED
@@ -1,262 +0,0 @@
1
- import import2 from "import2";
2
-
3
- import { IConnection } from "./IConnection";
4
- import { IEncryptionPassword } from "./IEncryptionPassword";
5
- import { Primitive } from "./Primitive";
6
-
7
- import { AesPkcs5 } from "./AesPkcs5";
8
- import { HttpError } from "./HttpError";
9
- import { Singleton } from "./internal/Singleton";
10
-
11
- /**
12
- * Fetcher, utility class for the [**Nestia**](https://github.com/samchon/nestia) fetch.
13
- *
14
- * `Fetcher` is a utility class providing the {@link Fetcher.fetch} functions who're being
15
- * used by all of the SDK libraries, interacting with the remote HTTP servers, who are
16
- * generated by the [**Nestia**](https://github.com/samchon/nestia).
17
- *
18
- * As this `Fetcher` be used only by the [**Nestia**](https://github.com/samchon/nestia)
19
- * generated SDK libraries, you don't need to handle this class directly. It may only be
20
- * appeared in the source codes of the [**Nestia**](https://github.com/samchon/nestia)
21
- * generated SDK libraries.
22
- *
23
- * @author Jeongho Nam - https://github.com/samchon
24
- */
25
- export class Fetcher {
26
- public static fetch(
27
- connection: IConnection,
28
- encrypted: Fetcher.IEncrypted,
29
- method: "HEAD",
30
- path: string,
31
- ): Promise<void>;
32
-
33
- /**
34
- * Fetch function for the `GET` methods.
35
- *
36
- * @param connection Connection information for the remote HTTP server
37
- * @param encrypted Whether the request/response body be encrypted or not
38
- * @param method Method of the HTTP request
39
- * @param path Path of the HTTP request
40
- * @return Response body data from the remote HTTP server
41
- */
42
- public static fetch<Output>(
43
- connection: IConnection,
44
- encrypted: Fetcher.IEncrypted,
45
- method: "GET",
46
- path: string,
47
- ): Promise<Primitive<Output>>;
48
-
49
- /**
50
- * Fetch function for the `POST`, `PUT`, `PATCH` and `DELETE` methods.
51
- *
52
- * @param connection Connection information for the remote HTTP server
53
- * @param encrypted Whether the request/response body be encrypted or not
54
- * @param method Method of the HTTP request
55
- * @param path Path of the HTTP request
56
- * @param input Request body data for the HTTP request
57
- * @param stringify JSON string conversion function, default is the `JSON.stringify`
58
- * @return Response body data from the remote HTTP server
59
- */
60
- public static fetch<Input, Output>(
61
- connection: IConnection,
62
- encrypted: Fetcher.IEncrypted,
63
- method: "POST" | "PUT" | "PATCH" | "DELETE",
64
- path: string,
65
- input?: Input,
66
- stringify?: (input: Input) => string,
67
- ): Promise<Primitive<Output>>;
68
-
69
- public static async fetch<Output>(
70
- connection: IConnection,
71
- encrypted: Fetcher.IEncrypted,
72
- method: "GET" | "DELETE" | "POST" | "PUT" | "PATCH" | "HEAD",
73
- path: string,
74
- input?: object,
75
- stringify?: (input: object) => string,
76
- ): Promise<Primitive<Output>> {
77
- if (encrypted.request === true || encrypted.response === true)
78
- if (connection.encryption === undefined)
79
- throw new Error(
80
- "Error on nestia.Fetcher.encrypt(): the encryption password has not been configured.",
81
- );
82
-
83
- //----
84
- // REQUEST MESSSAGE
85
- //----
86
- // METHOD & HEADERS
87
- const headers: Record<string, IConnection.HeaderValue | undefined> = {
88
- ...(connection.headers ?? {}),
89
- };
90
- if (input !== undefined)
91
- headers["Content-Type"] ??=
92
- encrypted.request === true || typeof input === "string"
93
- ? "text/plain"
94
- : "application/json";
95
-
96
- const init: RequestInit = {
97
- ...(connection.options ?? {}),
98
- method,
99
- headers: (() => {
100
- const output: [string, string][] = [];
101
- for (const [key, value] of Object.entries(headers))
102
- if (value === undefined) continue;
103
- else if (Array.isArray(value))
104
- for (const v of value) output.push([key, String(v)]);
105
- else output.push([key, String(value)]);
106
- return output;
107
- })(),
108
- };
109
-
110
- // REQUEST BODY (WITH ENCRYPTION)
111
- if (input !== undefined)
112
- init.body = (() => {
113
- const json: string =
114
- encrypted.request === true ||
115
- headers["Content-Type"] !== "text/plain"
116
- ? (stringify ?? JSON.stringify)(input)
117
- : String(input);
118
- if (encrypted.request !== true) return json;
119
-
120
- const password:
121
- | IEncryptionPassword
122
- | IEncryptionPassword.Closure =
123
- connection.encryption instanceof Function
124
- ? connection.encryption!(
125
- {
126
- headers: init.headers as Record<
127
- string,
128
- string
129
- >,
130
- body: json,
131
- },
132
- true,
133
- )
134
- : connection.encryption!;
135
- return AesPkcs5.encrypt(json, password.key, password.iv);
136
- })();
137
-
138
- //----
139
- // RESPONSE MESSAGE
140
- //----
141
- // URL SPECIFICATION
142
- if (
143
- connection.host[connection.host.length - 1] !== "/" &&
144
- path[0] !== "/"
145
- )
146
- path = "/" + path;
147
-
148
- const url: URL = new URL(`${connection.host}${path}`);
149
-
150
- // DO FETCH
151
- const response: Response = await (await polyfill.get())(url.href, init);
152
- const text: string = (await response.text()) ?? "";
153
-
154
- // CHECK THE STATUS CODE
155
- if (
156
- (encrypted.status !== undefined &&
157
- response.status !== encrypted.status) ||
158
- (encrypted.status === undefined &&
159
- response.status !== 200 &&
160
- response.status !== 201)
161
- )
162
- throw new HttpError(method, path, response.status, text);
163
-
164
- //----
165
- // OUTPUT
166
- //----
167
- // HEAD METHOD CANNOT HAVE ANYTHING
168
- if (method === "HEAD") return undefined!;
169
-
170
- // DECRYPT RESPONSE BODY
171
- const content: string = !encrypted.response || text.length === 0
172
- ? text
173
- : (() => {
174
- const password:
175
- | IEncryptionPassword
176
- | IEncryptionPassword.Closure =
177
- connection.encryption instanceof Function
178
- ? connection.encryption!(
179
- {
180
- headers: headers_to_object(
181
- response.headers,
182
- ),
183
- body: text,
184
- },
185
- false,
186
- )
187
- : connection.encryption!;
188
- return AesPkcs5.decrypt(text, password.key, password.iv);
189
- })();
190
- let ret: { __set_headers__: Record<string, any> } & Primitive<Output> =
191
- content as any;
192
-
193
- try {
194
- // PARSE RESPONSE BODY
195
- if (
196
- encrypted.response ||
197
- (response.headers.get("Content-Type") ?? "").indexOf(
198
- "application/json",
199
- ) !== -1
200
- )
201
- ret = content.length ? JSON.parse(content) : undefined!;
202
- } catch {}
203
-
204
- // RETURNS
205
- return ret;
206
- }
207
- }
208
-
209
- export namespace Fetcher {
210
- /**
211
- * Whether be encrypted or not.
212
- *
213
- * `Fetcher.IEncrypted` is a type of interface who represents whether the HTTP request
214
- * and response body must be encrypted or not.
215
- *
216
- * Like the {@link Fetcher} who are being used by all of the SDK libraries that are
217
- * generated by the [Nestia](https://github.com/samchon/nestia), this `IEncrypted`
218
- * interface would be used by the [Nestia](https://github.com/samchon/nestia) generated
219
- * SDK libaries.
220
- *
221
- * As this `Fetcher` be used only by the [**Nestia**](https://github.com/samchon/nestia)
222
- * generated SDK libraries, you don't need to handle this class directly. It may only be
223
- * appeared in the source codes of the [**Nestia**](https://github.com/samchon/nestia)
224
- * generated SDK libraries.
225
- */
226
- export interface IEncrypted {
227
- /**
228
- * Whether the request body be encrypted or not.
229
- */
230
- request?: boolean;
231
-
232
- /**
233
- * Whether the response body be encrypted or not.
234
- */
235
- response: boolean;
236
-
237
- /**
238
- * When special status code is allowed.
239
- */
240
- status?: number;
241
- }
242
- }
243
-
244
- const polyfill = new Singleton(async (): Promise<typeof fetch> => {
245
- if (
246
- typeof global === "object" &&
247
- typeof global.process === "object" &&
248
- typeof global.process.versions === "object" &&
249
- typeof global.process.versions.node !== undefined
250
- ) {
251
- if (global.fetch === undefined)
252
- global.fetch = ((await import2("node-fetch")) as any).default;
253
- return (global as any).fetch;
254
- }
255
- return window.fetch;
256
- });
257
-
258
- function headers_to_object(headers: Headers): Record<string, string> {
259
- const output: Record<string, string> = {};
260
- headers.forEach((value, key) => (output[key] = value));
261
- return output;
262
- }