@nestia/fetcher 2.0.0-dev.20230906 → 2.0.0-dev.20230908
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/EncryptedFetcher.d.ts +3 -0
- package/lib/EncryptedFetcher.js +39 -0
- package/lib/EncryptedFetcher.js.map +1 -1
- package/lib/HttpError.d.ts +3 -1
- package/lib/HttpError.js +3 -1
- package/lib/HttpError.js.map +1 -1
- package/lib/IPropagation.d.ts +42 -0
- package/lib/IPropagation.js +3 -0
- package/lib/IPropagation.js.map +1 -0
- package/lib/PlainFetcher.d.ts +3 -0
- package/lib/PlainFetcher.js +16 -0
- package/lib/PlainFetcher.js.map +1 -1
- package/lib/Primitive.d.ts +15 -13
- package/lib/Resolved.d.ts +46 -0
- package/lib/Resolved.js +3 -0
- package/lib/Resolved.js.map +1 -0
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/internal/FetcherBase.d.ts +2 -0
- package/lib/internal/FetcherBase.js +153 -99
- package/lib/internal/FetcherBase.js.map +1 -1
- package/package.json +1 -1
- package/src/EncryptedFetcher.ts +74 -0
- package/src/HttpError.ts +3 -0
- package/src/IPropagation.ts +73 -0
- package/src/PlainFetcher.ts +38 -0
- package/src/Primitive.ts +20 -16
- package/src/Resolved.ts +116 -0
- package/src/index.ts +3 -1
- package/src/internal/FetcherBase.ts +87 -39
package/src/Resolved.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolved type erased every methods.
|
|
3
|
+
*
|
|
4
|
+
* `Resolved` is a type of TMP (Type Meta Programming) type which converts
|
|
5
|
+
* its argument as a resolved type that erased every method properties.
|
|
6
|
+
*
|
|
7
|
+
* If the target argument is a built-in class which returns its origin primitive type
|
|
8
|
+
* through the `valueOf()` method like the `String` or `Number`, its return type would
|
|
9
|
+
* be the `string` or `number`. Otherwise, the built-in class does not have the
|
|
10
|
+
* `valueOf()` method, the return type would be same with the target argument.
|
|
11
|
+
*
|
|
12
|
+
* Otherwise, the target argument is a type of custom class, all of its custom methods
|
|
13
|
+
* would be erased and its prototype would be changed to the primitive `object`.
|
|
14
|
+
* Therefore, return type of the TMP type finally be the resolved object.
|
|
15
|
+
*
|
|
16
|
+
* Before | After
|
|
17
|
+
* ------------------------|----------------------------------------
|
|
18
|
+
* `Boolean` | `boolean`
|
|
19
|
+
* `Number` | `number`
|
|
20
|
+
* `BigInt` | `bigint`
|
|
21
|
+
* `String` | `string`
|
|
22
|
+
* `Class` | `interface`
|
|
23
|
+
* Native Class or Others | No change
|
|
24
|
+
*
|
|
25
|
+
* @template Instance Target argument type.
|
|
26
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
27
|
+
* @author Kyungsu Kang - https://github.com/kakasoo
|
|
28
|
+
*/
|
|
29
|
+
export type Resolved<T> = Equal<T, ResolvedMain<T>> extends true
|
|
30
|
+
? T
|
|
31
|
+
: ResolvedMain<T>;
|
|
32
|
+
|
|
33
|
+
type Equal<X, Y> = X extends Y ? (Y extends X ? true : false) : false;
|
|
34
|
+
|
|
35
|
+
type ResolvedMain<Instance> = Instance extends [never]
|
|
36
|
+
? never // (special trick for jsonable | null) type
|
|
37
|
+
: ValueOf<Instance> extends boolean | number | bigint | string
|
|
38
|
+
? ValueOf<Instance>
|
|
39
|
+
: Instance extends Function
|
|
40
|
+
? never
|
|
41
|
+
: Instance extends object
|
|
42
|
+
? ResolvedObject<Instance>
|
|
43
|
+
: ValueOf<Instance>;
|
|
44
|
+
|
|
45
|
+
type ResolvedObject<Instance extends object> = Instance extends Array<infer T>
|
|
46
|
+
? IsTuple<Instance> extends true
|
|
47
|
+
? ResolvedTuple<Instance>
|
|
48
|
+
: ResolvedMain<T>[]
|
|
49
|
+
: Instance extends Set<infer U>
|
|
50
|
+
? Set<ResolvedMain<U>>
|
|
51
|
+
: Instance extends Map<infer K, infer V>
|
|
52
|
+
? Map<ResolvedMain<K>, ResolvedMain<V>>
|
|
53
|
+
: Instance extends WeakSet<any> | WeakMap<any, any>
|
|
54
|
+
? never
|
|
55
|
+
: Instance extends
|
|
56
|
+
| Date
|
|
57
|
+
| Uint8Array
|
|
58
|
+
| Uint8ClampedArray
|
|
59
|
+
| Uint16Array
|
|
60
|
+
| Uint32Array
|
|
61
|
+
| BigUint64Array
|
|
62
|
+
| Int8Array
|
|
63
|
+
| Int16Array
|
|
64
|
+
| Int32Array
|
|
65
|
+
| BigInt64Array
|
|
66
|
+
| Float32Array
|
|
67
|
+
| Float64Array
|
|
68
|
+
| ArrayBuffer
|
|
69
|
+
| SharedArrayBuffer
|
|
70
|
+
| DataView
|
|
71
|
+
? Instance
|
|
72
|
+
: {
|
|
73
|
+
[P in keyof Instance]: ResolvedMain<Instance[P]>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
type ResolvedTuple<T extends readonly any[]> = T extends []
|
|
77
|
+
? []
|
|
78
|
+
: T extends [infer F]
|
|
79
|
+
? [ResolvedMain<F>]
|
|
80
|
+
: T extends [infer F, ...infer Rest extends readonly any[]]
|
|
81
|
+
? [ResolvedMain<F>, ...ResolvedTuple<Rest>]
|
|
82
|
+
: T extends [(infer F)?]
|
|
83
|
+
? [ResolvedMain<F>?]
|
|
84
|
+
: T extends [(infer F)?, ...infer Rest extends readonly any[]]
|
|
85
|
+
? [ResolvedMain<F>?, ...ResolvedTuple<Rest>]
|
|
86
|
+
: [];
|
|
87
|
+
|
|
88
|
+
type ValueOf<Instance> = IsValueOf<Instance, Boolean> extends true
|
|
89
|
+
? boolean
|
|
90
|
+
: IsValueOf<Instance, Number> extends true
|
|
91
|
+
? number
|
|
92
|
+
: IsValueOf<Instance, String> extends true
|
|
93
|
+
? string
|
|
94
|
+
: Instance;
|
|
95
|
+
|
|
96
|
+
type IsTuple<T extends readonly any[] | { length: number }> = [T] extends [
|
|
97
|
+
never,
|
|
98
|
+
]
|
|
99
|
+
? false
|
|
100
|
+
: T extends readonly any[]
|
|
101
|
+
? number extends T["length"]
|
|
102
|
+
? false
|
|
103
|
+
: true
|
|
104
|
+
: false;
|
|
105
|
+
|
|
106
|
+
type IsValueOf<Instance, Object extends IValueOf<any>> = Instance extends Object
|
|
107
|
+
? Object extends IValueOf<infer Primitive>
|
|
108
|
+
? Instance extends Primitive
|
|
109
|
+
? false
|
|
110
|
+
: true // not Primitive, but Object
|
|
111
|
+
: false // cannot be
|
|
112
|
+
: false;
|
|
113
|
+
|
|
114
|
+
interface IValueOf<T> {
|
|
115
|
+
valueOf(): T;
|
|
116
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from "./IConnection";
|
|
2
2
|
export * from "./IEncryptionPassword";
|
|
3
|
+
export * from "./IPropagation";
|
|
3
4
|
export * from "./IRandomGenerator";
|
|
4
|
-
export * from "./Primitive";
|
|
5
5
|
export * from "./HttpError";
|
|
6
|
+
export * from "./Primitive";
|
|
7
|
+
export * from "./Resolved";
|
|
@@ -4,6 +4,7 @@ import { Primitive } from "../Primitive";
|
|
|
4
4
|
import { IFetchRoute } from "./IFetchRoute";
|
|
5
5
|
import { Singleton } from "./Singleton";
|
|
6
6
|
import { HttpError } from "../HttpError";
|
|
7
|
+
import { IPropagation } from "../IPropagation";
|
|
7
8
|
|
|
8
9
|
export namespace FetcherBase {
|
|
9
10
|
export interface IProps {
|
|
@@ -28,6 +29,49 @@ export namespace FetcherBase {
|
|
|
28
29
|
input?: Input,
|
|
29
30
|
stringify?: (input: Input) => string,
|
|
30
31
|
): Promise<Primitive<Output>> => {
|
|
32
|
+
const result = await _Propagate("fetch")(props)(
|
|
33
|
+
connection,
|
|
34
|
+
route,
|
|
35
|
+
input,
|
|
36
|
+
stringify,
|
|
37
|
+
);
|
|
38
|
+
if ((result as any).success === false)
|
|
39
|
+
throw new HttpError(
|
|
40
|
+
route.method,
|
|
41
|
+
route.path,
|
|
42
|
+
result.status as any as number,
|
|
43
|
+
result.headers,
|
|
44
|
+
result.data as string,
|
|
45
|
+
);
|
|
46
|
+
return result.data as Primitive<Output>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const propagate =
|
|
50
|
+
(props: IProps) =>
|
|
51
|
+
async <Input>(
|
|
52
|
+
connection: IConnection,
|
|
53
|
+
route: IFetchRoute<
|
|
54
|
+
"DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT"
|
|
55
|
+
>,
|
|
56
|
+
input?: Input,
|
|
57
|
+
stringify?: (input: Input) => string,
|
|
58
|
+
): Promise<IPropagation<any, any>> =>
|
|
59
|
+
_Propagate("propagate")(props)(connection, route, input, stringify);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
const _Propagate =
|
|
65
|
+
(method: string) =>
|
|
66
|
+
(props: IProps) =>
|
|
67
|
+
async <Input>(
|
|
68
|
+
connection: IConnection,
|
|
69
|
+
route: IFetchRoute<
|
|
70
|
+
"DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT"
|
|
71
|
+
>,
|
|
72
|
+
input?: Input,
|
|
73
|
+
stringify?: (input: Input) => string,
|
|
74
|
+
): Promise<IPropagation<any, any>> => {
|
|
31
75
|
//----
|
|
32
76
|
// REQUEST MESSSAGE
|
|
33
77
|
//----
|
|
@@ -86,46 +130,47 @@ export namespace FetcherBase {
|
|
|
86
130
|
await polyfill.get()
|
|
87
131
|
)(url.href, init);
|
|
88
132
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
response.status
|
|
94
|
-
response.status
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
// CONSTRUCT RESULT DATA
|
|
134
|
+
const result: IPropagation<any, any> = {
|
|
135
|
+
success:
|
|
136
|
+
response.status === 200 ||
|
|
137
|
+
response.status === 201 ||
|
|
138
|
+
response.status == route.status,
|
|
139
|
+
status: route.status,
|
|
140
|
+
headers: response_headers_to_object(response.headers),
|
|
141
|
+
data: undefined!,
|
|
142
|
+
} as any;
|
|
143
|
+
if ((result as any).success === false) {
|
|
144
|
+
// WHEN FAILED
|
|
145
|
+
result.data = await response.text();
|
|
146
|
+
const type = response.headers.get("content-type");
|
|
147
|
+
if (
|
|
148
|
+
method !== "fetch" &&
|
|
149
|
+
type &&
|
|
150
|
+
type.indexOf("application/json") !== -1
|
|
151
|
+
)
|
|
152
|
+
try {
|
|
153
|
+
result.data = JSON.parse(result.data);
|
|
154
|
+
} catch {}
|
|
155
|
+
} else {
|
|
156
|
+
// WHEN SUCCESS
|
|
157
|
+
if (route.method === "HEAD") result.data = undefined!;
|
|
158
|
+
else if (route.response?.type === "application/json") {
|
|
159
|
+
const text: string = await response.text();
|
|
160
|
+
result.data = text.length ? JSON.parse(text) : undefined;
|
|
161
|
+
} else
|
|
162
|
+
result.data = props.decode(
|
|
163
|
+
await response.text(),
|
|
164
|
+
result.headers,
|
|
165
|
+
);
|
|
121
166
|
}
|
|
122
|
-
return
|
|
123
|
-
await response.text(),
|
|
124
|
-
response_headers_to_object(response.headers),
|
|
125
|
-
) as Primitive<Output>;
|
|
167
|
+
return result;
|
|
126
168
|
};
|
|
127
169
|
}
|
|
128
170
|
|
|
171
|
+
/**
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
129
174
|
const polyfill = new Singleton(async (): Promise<typeof fetch> => {
|
|
130
175
|
if (
|
|
131
176
|
typeof global === "object" &&
|
|
@@ -134,16 +179,19 @@ const polyfill = new Singleton(async (): Promise<typeof fetch> => {
|
|
|
134
179
|
typeof global.process.versions.node !== undefined
|
|
135
180
|
) {
|
|
136
181
|
if (global.fetch === undefined)
|
|
137
|
-
global.fetch
|
|
182
|
+
global.fetch ??= ((await import2("node-fetch")) as any).default;
|
|
138
183
|
return (global as any).fetch;
|
|
139
184
|
}
|
|
140
185
|
return window.fetch;
|
|
141
186
|
});
|
|
142
187
|
|
|
188
|
+
/**
|
|
189
|
+
* @internal
|
|
190
|
+
*/
|
|
143
191
|
const response_headers_to_object = (
|
|
144
192
|
headers: Headers,
|
|
145
|
-
): Record<string,
|
|
146
|
-
const output: Record<string,
|
|
193
|
+
): Record<string, string | string[]> => {
|
|
194
|
+
const output: Record<string, string | string[]> = {};
|
|
147
195
|
headers.forEach((value, key) => {
|
|
148
196
|
if (key === "set-cookie") {
|
|
149
197
|
output[key] ??= [];
|