@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/lib/AesPkcs5.js.map +1 -1
- package/lib/EncryptedFetcher.d.ts +43 -0
- package/lib/EncryptedFetcher.js +97 -0
- package/lib/EncryptedFetcher.js.map +1 -0
- package/lib/IConnection.d.ts +8 -4
- package/lib/IEncryptionPassword.d.ts +7 -6
- package/lib/PlainFetcher.d.ts +44 -0
- package/lib/PlainFetcher.js +75 -0
- package/lib/PlainFetcher.js.map +1 -0
- package/lib/index.d.ts +0 -3
- package/lib/index.js +0 -3
- package/lib/index.js.map +1 -1
- package/lib/internal/FetcherBase.d.ts +11 -0
- package/lib/{Fetcher.js → internal/FetcherBase.js} +79 -105
- package/lib/internal/FetcherBase.js.map +1 -0
- package/lib/internal/IFetchRoute.d.ts +28 -0
- package/lib/internal/IFetchRoute.js +3 -0
- package/lib/internal/IFetchRoute.js.map +1 -0
- package/package.json +1 -1
- package/src/AesPkcs5.ts +0 -1
- package/src/EncryptedFetcher.ts +115 -0
- package/src/IConnection.ts +9 -5
- package/src/IEncryptionPassword.ts +8 -6
- package/src/PlainFetcher.ts +82 -0
- package/src/index.ts +0 -4
- package/src/internal/FetcherBase.ts +156 -0
- package/src/internal/IFetchRoute.ts +36 -0
- package/lib/Fetcher.d.ts +0 -73
- package/lib/Fetcher.js.map +0 -1
- package/src/Fetcher.ts +0 -262
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
|
-
}
|