@nestia/fetcher 14.0.0 → 14.0.2
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/README.md +1 -1
- package/lib/AesPkcs5.d.ts +19 -2
- package/lib/AesPkcs5.js +21 -4
- package/lib/AesPkcs5.js.map +1 -1
- package/lib/AesPkcs5.mjs +2 -2
- package/lib/AesPkcs5.mjs.map +1 -1
- package/lib/EncryptedFetcher.d.ts +34 -3
- package/lib/EncryptedFetcher.js +44 -54
- package/lib/EncryptedFetcher.js.map +1 -1
- package/lib/EncryptedFetcher.mjs +30 -25
- package/lib/EncryptedFetcher.mjs.map +1 -1
- package/lib/FormDataInput.d.ts +21 -8
- package/lib/IConnection.d.ts +49 -14
- package/lib/IEncryptionPassword.d.ts +18 -2
- package/lib/IFetchEvent.d.ts +25 -0
- package/lib/IFetchEvent.js +0 -18
- package/lib/IFetchEvent.js.map +1 -1
- package/lib/IFetchRoute.d.ts +19 -0
- package/lib/IPropagation.d.ts +34 -11
- package/lib/NestiaSimulator.d.ts +45 -2
- package/lib/NestiaSimulator.js +65 -14
- package/lib/NestiaSimulator.js.map +1 -1
- package/lib/NestiaSimulator.mjs +39 -9
- package/lib/NestiaSimulator.mjs.map +1 -1
- package/lib/PathParameter.d.ts +31 -0
- package/lib/PathParameter.js +41 -0
- package/lib/PathParameter.js.map +1 -0
- package/lib/PathParameter.mjs +13 -0
- package/lib/PathParameter.mjs.map +1 -0
- package/lib/PlainFetcher.d.ts +36 -5
- package/lib/PlainFetcher.js +6 -2
- package/lib/PlainFetcher.js.map +1 -1
- package/lib/PlainFetcher.mjs.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +2 -1
- package/lib/internal/FetcherBase.js +35 -12
- package/lib/internal/FetcherBase.js.map +1 -1
- package/lib/internal/FetcherBase.mjs +14 -10
- package/lib/internal/FetcherBase.mjs.map +1 -1
- package/lib/internal/is_binary_response_content_type.d.ts +12 -0
- package/lib/internal/is_binary_response_content_type.js +12 -0
- package/lib/internal/is_binary_response_content_type.js.map +1 -1
- package/lib/internal/is_binary_response_content_type.mjs +12 -0
- package/lib/internal/is_binary_response_content_type.mjs.map +1 -1
- package/package.json +4 -3
- package/src/AesPkcs5.ts +21 -4
- package/src/EncryptedFetcher.ts +77 -57
- package/src/FormDataInput.ts +26 -10
- package/src/IConnection.ts +54 -18
- package/src/IEncryptionPassword.ts +18 -2
- package/src/IFetchEvent.ts +32 -19
- package/src/IFetchRoute.ts +19 -0
- package/src/IPropagation.ts +41 -17
- package/src/NestiaSimulator.ts +83 -17
- package/src/PathParameter.ts +40 -0
- package/src/PlainFetcher.ts +50 -5
- package/src/index.ts +1 -0
- package/src/internal/FetcherBase.ts +49 -10
- package/src/internal/is_binary_response_content_type.ts +12 -0
package/lib/IConnection.d.ts
CHANGED
|
@@ -3,23 +3,26 @@ import { IFetchEvent } from "./IFetchEvent";
|
|
|
3
3
|
/**
|
|
4
4
|
* Connection information.
|
|
5
5
|
*
|
|
6
|
-
* `IConnection` is an interface
|
|
7
|
-
* the remote HTTP server. You can target the remote HTTP server by
|
|
6
|
+
* `IConnection` is an interface type that represents connection information of
|
|
7
|
+
* the remote HTTP server. You can target the remote HTTP server by writing the
|
|
8
8
|
* {@link IConnection.host} variable down. Also, you can configure special header
|
|
9
9
|
* values by specializing the {@link IConnection.headers} variable.
|
|
10
10
|
*
|
|
11
11
|
* If the remote HTTP server encrypts or decrypts its body data through the
|
|
12
|
-
* AES-128/256 algorithm, specify the {@link IConnection.encryption} with
|
|
12
|
+
* AES-128/192/256 algorithm, specify the {@link IConnection.encryption} with
|
|
13
13
|
* {@link IEncryptionPassword} or {@link IEncryptionPassword.Closure} variable.
|
|
14
14
|
*
|
|
15
|
-
* @author
|
|
15
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
16
16
|
* @author Seungjun We - https://github.com/SeungjunWe
|
|
17
17
|
*/
|
|
18
18
|
export interface IConnection<Headers extends object | undefined = object | undefined> {
|
|
19
19
|
/** Host address of the remote HTTP server. */
|
|
20
20
|
host: string;
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Header values delivered to the remote HTTP server; undefined entries are
|
|
23
|
+
* omitted.
|
|
24
|
+
*/
|
|
25
|
+
headers?: Record<string, IConnection.HeaderValue | undefined> & IConnection.Headerify<Headers>;
|
|
23
26
|
/**
|
|
24
27
|
* Use simulation mode.
|
|
25
28
|
*
|
|
@@ -30,7 +33,7 @@ export interface IConnection<Headers extends object | undefined = object | undef
|
|
|
30
33
|
* By the way, to utilize this simulation mode, SDK library must be generated
|
|
31
34
|
* with {@link INestiaConfig.simulate} option, too. Open `nestia.config.ts`
|
|
32
35
|
* file, and configure {@link INestiaConfig.simulate} property to be `true`.
|
|
33
|
-
*
|
|
36
|
+
* Then, newly generated SDK library would have a built-in mock-up data
|
|
34
37
|
* generator.
|
|
35
38
|
*
|
|
36
39
|
* @default false
|
|
@@ -39,9 +42,17 @@ export interface IConnection<Headers extends object | undefined = object | undef
|
|
|
39
42
|
/**
|
|
40
43
|
* Logger function.
|
|
41
44
|
*
|
|
42
|
-
* This function is called
|
|
45
|
+
* This function is called and awaited after transport and response
|
|
46
|
+
* processing, whether they succeeded or failed. Configuration, body encoding
|
|
47
|
+
* and URL errors that occur before transport do not produce an event. Logger
|
|
48
|
+
* errors are ignored; event input and output share the caller's payload
|
|
49
|
+
* references, so a logger should treat them as read-only.
|
|
43
50
|
*
|
|
44
51
|
* @param event Event information of the fetch event.
|
|
52
|
+
* @evidence contracts/common.md#principled-implementation The callback receives the event from the transport finally block after completed_at is set. respond_at and status stay null without a response, and output stays undefined if body processing throws. Its rejection is ignored, but its argument includes mutable payload references and its awaiting can delay completion.
|
|
53
|
+
* @evidence contracts/common.md#clear-and-simple-design One optional callback with a single event argument.
|
|
54
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The optional callback uses the connection's supported logging boundary; the pipeline catches its errors without replacing a transport or decoding failure.
|
|
55
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states when the callback runs, which pretransport errors create no event, that it is awaited, and why shared payload references should be treated as read-only.
|
|
45
56
|
*/
|
|
46
57
|
logger?: (event: IFetchEvent) => Promise<void>;
|
|
47
58
|
/**
|
|
@@ -66,6 +77,15 @@ export interface IConnection<Headers extends object | undefined = object | undef
|
|
|
66
77
|
*/
|
|
67
78
|
fetch?: typeof fetch;
|
|
68
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Support types of {@link IConnection}: the fetch options, the allowed header
|
|
82
|
+
* values, and the header mapping.
|
|
83
|
+
*
|
|
84
|
+
* @evidence contracts/common.md#principled-implementation The merged connection interface and namespace share one public identity for addressing, transport settings and support types. Header entries accept HeaderValue or undefined omission, while Headerify retains name-specific constraints; the HeaderValue union continues to exclude null and objects.
|
|
85
|
+
* @evidence contracts/common.md#clear-and-simple-design The interface separates addressing, header input, simulation, observation, encryption and fetch options; three supporting types organize their representations without runtime members.
|
|
86
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It contains types only.
|
|
87
|
+
* @evidence contracts/common.md#meaningful-documentation The interface member comments explain addressing, omitted headers and optional transport settings; the logger separately documents completion, awaiting and ignored errors. Each support type has its own documentation.
|
|
88
|
+
*/
|
|
69
89
|
export declare namespace IConnection {
|
|
70
90
|
/**
|
|
71
91
|
* Additional options for the `fetch` function.
|
|
@@ -73,9 +93,14 @@ export declare namespace IConnection {
|
|
|
73
93
|
* Almost same with {@link RequestInit} type of the {@link fetch} function, but
|
|
74
94
|
* `body`, `headers` and `method` properties are omitted.
|
|
75
95
|
*
|
|
76
|
-
* The
|
|
77
|
-
*
|
|
78
|
-
*
|
|
96
|
+
* The explicit option record exposes the supported subset independently of
|
|
97
|
+
* changes to {@link RequestInit}. DOM types are still required by the
|
|
98
|
+
* connection's custom fetch and abort signal members.
|
|
99
|
+
*
|
|
100
|
+
* @evidence contracts/common.md#principled-implementation The record exposes a subset of RequestInit options while omitting body, headers and method, whose construction belongs to the route pipeline; AbortSignal and the connection's fetch member still depend on DOM declarations.
|
|
101
|
+
* @evidence contracts/common.md#clear-and-simple-design A flat option record, with each member mirroring one field of the standard request options.
|
|
102
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type; the fetcher spreads the options into the request and then sets the method and headers itself.
|
|
103
|
+
* @evidence contracts/common.md#meaningful-documentation The comment explains the supported subset and remaining DOM type dependency, and each member documents the standard field's meaning.
|
|
79
104
|
*/
|
|
80
105
|
interface IOptions {
|
|
81
106
|
/**
|
|
@@ -126,8 +151,13 @@ export declare namespace IConnection {
|
|
|
126
151
|
* Type of allowed header values.
|
|
127
152
|
*
|
|
128
153
|
* Only atomic or array of atomic values are allowed.
|
|
154
|
+
*
|
|
155
|
+
* @evidence contracts/common.md#principled-implementation A header value is a string, boolean, number, or bigint, or an array of the non-string atomic types or of strings, which the request pipeline stringifies, one header line per array element.
|
|
156
|
+
* @evidence contracts/common.md#clear-and-simple-design A single union of the allowed atomic and array values.
|
|
157
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
158
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states that only atomic values and arrays of them are allowed.
|
|
129
159
|
*/
|
|
130
|
-
type HeaderValue = string | boolean | number | bigint |
|
|
160
|
+
type HeaderValue = string | boolean | number | bigint | Array<boolean> | Array<number> | Array<bigint> | Array<string>;
|
|
131
161
|
/**
|
|
132
162
|
* Type of headers
|
|
133
163
|
*
|
|
@@ -136,7 +166,7 @@ export declare namespace IConnection {
|
|
|
136
166
|
*
|
|
137
167
|
* Below are list of prohibited in HTTP headers.
|
|
138
168
|
*
|
|
139
|
-
* 1. Value type
|
|
169
|
+
* 1. Value type is neither {@link HeaderValue} nor omitted `undefined`
|
|
140
170
|
* 2. Key is "set-cookie", but value is not an Array type
|
|
141
171
|
* 3. Key is one of them, but value is Array type
|
|
142
172
|
*
|
|
@@ -158,8 +188,13 @@ export declare namespace IConnection {
|
|
|
158
188
|
* - "retry-after"
|
|
159
189
|
* - "server"
|
|
160
190
|
* - "user-agent"
|
|
191
|
+
*
|
|
192
|
+
* @evidence contracts/common.md#principled-implementation Each key admits only HeaderValue or omitted undefined. Classifying the defined value domain preserves optional array set-cookie inputs; singleton headers reject any array member even in a scalar/array union. An undefined-only domain transmits nothing and stays permitted. Lowercase keys follow HTTP's case-insensitive names, and ordinary keys retain their type.
|
|
193
|
+
* @evidence contracts/common.md#clear-and-simple-design One mapped type that rejects an entry by turning it into `never`, with the rule spelled out in the comment.
|
|
194
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
195
|
+
* @evidence contracts/common.md#meaningful-documentation The comment lists the prohibited cases and the singleton headers.
|
|
161
196
|
*/
|
|
162
197
|
type Headerify<T extends object | undefined> = {
|
|
163
|
-
[P in keyof T]?: T[P] extends HeaderValue | undefined ? P extends string ? Lowercase<P> extends "set-cookie" ? T[P] extends Array<HeaderValue> ? T[P] | undefined : never : Lowercase<P> extends "age" | "authorization" | "content-length" | "content-type" | "etag" | "expires" | "from" | "host" | "if-modified-since" | "if-unmodified-since" | "last-modified" | "location" | "max-forwards" | "proxy-authorization" | "referer" | "retry-after" | "server" | "user-agent" ? T[P]
|
|
198
|
+
[P in keyof T]?: T[P] extends HeaderValue | undefined ? P extends string ? Lowercase<P> extends "set-cookie" ? Exclude<T[P], undefined> extends Array<HeaderValue> ? T[P] | undefined : never : Lowercase<P> extends "age" | "authorization" | "content-length" | "content-type" | "etag" | "expires" | "from" | "host" | "if-modified-since" | "if-unmodified-since" | "last-modified" | "location" | "max-forwards" | "proxy-authorization" | "referer" | "retry-after" | "server" | "user-agent" ? Extract<Exclude<T[P], undefined>, Array<HeaderValue>> extends never ? T[P] | undefined : never : T[P] | undefined : never : never;
|
|
164
199
|
};
|
|
165
200
|
}
|
|
@@ -3,11 +3,15 @@ import { IConnection } from "./IConnection";
|
|
|
3
3
|
* Encryption password.
|
|
4
4
|
*
|
|
5
5
|
* `IEncryptionPassword` is a type of interface who represents encryption
|
|
6
|
-
* password used by the {@link Fetcher} with AES-128/256 algorithm. If your
|
|
6
|
+
* password used by the {@link Fetcher} with AES-128/192/256 algorithm. If your
|
|
7
7
|
* encryption password is not fixed but changes according to the input content,
|
|
8
8
|
* you can utilize the {@link IEncryptionPassword.Closure} function type.
|
|
9
9
|
*
|
|
10
10
|
* @author Jeongho Nam - https://github.com/samchon
|
|
11
|
+
* @evidence contracts/common.md#principled-implementation A key and an initialization vector are the two inputs of AES-CBC, so the interface holds exactly them, as strings that `AesPkcs5` reads as UTF-8 bytes.
|
|
12
|
+
* @evidence contracts/common.md#clear-and-simple-design A two-field record whose namespace adds the closure form for passwords that depend on the message.
|
|
13
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
14
|
+
* @evidence contracts/common.md#meaningful-documentation The comment says what the object represents and links the closure form.
|
|
11
15
|
*/
|
|
12
16
|
export interface IEncryptionPassword {
|
|
13
17
|
/** Secret key. */
|
|
@@ -22,6 +26,11 @@ export declare namespace IEncryptionPassword {
|
|
|
22
26
|
* `IEncryptionPassword.Closure` is a type of closure function who are
|
|
23
27
|
* returning the {@link IEncryptionPassword} object. It would be used when your
|
|
24
28
|
* encryption password be changed according to the input content.
|
|
29
|
+
*
|
|
30
|
+
* @evidence contracts/common.md#principled-implementation A call signature from the message context to a password lets a server-driven scheme choose the key from the headers, the body, and the direction of each call.
|
|
31
|
+
* @evidence contracts/common.md#clear-and-simple-design A callable interface with one signature and no members.
|
|
32
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
33
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states when to use it and documents the parameter and the return value.
|
|
25
34
|
*/
|
|
26
35
|
interface Closure {
|
|
27
36
|
/**
|
|
@@ -32,7 +41,14 @@ export declare namespace IEncryptionPassword {
|
|
|
32
41
|
*/
|
|
33
42
|
(props: IProps): IEncryptionPassword;
|
|
34
43
|
}
|
|
35
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Properties for the closure.
|
|
46
|
+
*
|
|
47
|
+
* @evidence contracts/common.md#principled-implementation The record carries what a password closure can choose by: the request or response headers, the body text, and whether the body is being encoded or decoded.
|
|
48
|
+
* @evidence contracts/common.md#clear-and-simple-design A three-field record with no behavior.
|
|
49
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
50
|
+
* @evidence contracts/common.md#meaningful-documentation The comment names it as the closure's properties; the direction values are self-descriptive.
|
|
51
|
+
*/
|
|
36
52
|
interface IProps {
|
|
37
53
|
headers: Record<string, IConnection.HeaderValue | undefined>;
|
|
38
54
|
body: string;
|
package/lib/IFetchEvent.d.ts
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
import { IFetchRoute } from "./IFetchRoute";
|
|
2
|
+
/**
|
|
3
|
+
* Event of one completed fetch, passed to {@link IConnection.logger}.
|
|
4
|
+
*
|
|
5
|
+
* `status` and `respond_at` are `null` when no response arrived, and
|
|
6
|
+
* `completed_at` is set after response processing or transport failure. Binary
|
|
7
|
+
* success streams are handed to the caller without reading their bytes, so this
|
|
8
|
+
* timestamp does not measure the duration of their consumption. `input` is the
|
|
9
|
+
* value the caller passed and `output` is the response data, the error body for
|
|
10
|
+
* a failed status, or `undefined` when the request threw. These values retain
|
|
11
|
+
* their original references. Errors before transport, such as encoding or URL
|
|
12
|
+
* construction failures, do not create a logged event.
|
|
13
|
+
*
|
|
14
|
+
* @evidence contracts/common.md#principled-implementation The event records the route, the request input, the observed status and output, and the three instants of the exchange, which is what a logger or a benchmark needs to compute latency and to group by endpoint.
|
|
15
|
+
* @evidence contracts/common.md#clear-and-simple-design A flat record; the two nullable members mark the states with no response.
|
|
16
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Every value is measured by the pipeline; none is defaulted to a plausible value.
|
|
17
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states the states with no response and what input and output hold.
|
|
18
|
+
*/
|
|
2
19
|
export interface IFetchEvent {
|
|
20
|
+
/** Metadata used to execute the request. */
|
|
3
21
|
route: IFetchRoute<"DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT">;
|
|
22
|
+
/** Route path normalized to one leading slash. */
|
|
4
23
|
path: string;
|
|
24
|
+
/** Received HTTP status, or null when transport produced no response. */
|
|
5
25
|
status: number | null;
|
|
26
|
+
/** Original request value; no defensive copy is made. */
|
|
6
27
|
input: any;
|
|
28
|
+
/** Decoded payload or transferred binary stream, absent on processing error. */
|
|
7
29
|
output: any;
|
|
30
|
+
/** Start of the transport operation, after request preparation. */
|
|
8
31
|
started_at: Date;
|
|
32
|
+
/** Response arrival, before response body processing; null without a response. */
|
|
9
33
|
respond_at: Date | null;
|
|
34
|
+
/** End of response processing, before the logger is awaited. */
|
|
10
35
|
completed_at: Date;
|
|
11
36
|
}
|
package/lib/IFetchEvent.js
CHANGED
|
@@ -1,21 +1,3 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
// export namespace IFetchEvent {
|
|
4
|
-
// export interface IFunction {
|
|
5
|
-
// (connection: IConnection, ...args: any[]): Promise<any>;
|
|
6
|
-
// METADATA: {
|
|
7
|
-
// method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
|
8
|
-
// path: string;
|
|
9
|
-
// request: null | {
|
|
10
|
-
// type: string;
|
|
11
|
-
// encrypted: boolean;
|
|
12
|
-
// };
|
|
13
|
-
// response: null | {
|
|
14
|
-
// type: string;
|
|
15
|
-
// encrypted: boolean;
|
|
16
|
-
// };
|
|
17
|
-
// };
|
|
18
|
-
// status: null | number;
|
|
19
|
-
// }
|
|
20
|
-
// }
|
|
21
3
|
//# sourceMappingURL=IFetchEvent.js.map
|
package/lib/IFetchEvent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IFetchEvent.js","sourceRoot":"","sources":["../src/IFetchEvent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"IFetchEvent.js","sourceRoot":"","sources":["../src/IFetchEvent.ts"],"names":[],"mappings":""}
|
package/lib/IFetchRoute.d.ts
CHANGED
|
@@ -29,15 +29,34 @@ export interface IFetchRoute<Method extends "HEAD" | "GET" | "POST" | "PUT" | "P
|
|
|
29
29
|
* If you've forgotten to configuring this `parseQuery` property about the
|
|
30
30
|
* `application/x-www-form-urlencoded` typed response body data, then only the
|
|
31
31
|
* `URLSearchParams` typed instance would be returned instead.
|
|
32
|
+
*
|
|
33
|
+
* @evidence contracts/common.md#principled-implementation A response of type `application/x-www-form-urlencoded` is parsed with the route's function when there is one and is returned as `URLSearchParams` otherwise.
|
|
34
|
+
* @evidence contracts/common.md#clear-and-simple-design One optional method with one argument.
|
|
35
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The parser is route data supplied by the generated SDK, with no default guess about the shape.
|
|
36
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states when it is called and what happens without it.
|
|
32
37
|
*/
|
|
33
38
|
parseQuery?(input: URLSearchParams): any;
|
|
34
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Support types of {@link IFetchRoute}: the metadata of a request or response
|
|
42
|
+
* body.
|
|
43
|
+
*
|
|
44
|
+
* @evidence contracts/common.md#principled-implementation The conditional member types encode HTTP: only `DELETE`, `POST`, `PUT`, and `PATCH` requests may have a body, and `HEAD` responses have none, so a route that contradicts its method does not compile.
|
|
45
|
+
* @evidence contracts/common.md#clear-and-simple-design A record of the route facts the pipeline needs (method, path, optional template, bodies, status, query parser), with the nested body metadata in the namespace.
|
|
46
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
47
|
+
* @evidence contracts/common.md#meaningful-documentation Each member documents its meaning, including that the template exists since version 3.2.2.
|
|
48
|
+
*/
|
|
35
49
|
export declare namespace IFetchRoute {
|
|
36
50
|
/**
|
|
37
51
|
* Metadata of body.
|
|
38
52
|
*
|
|
39
53
|
* Describes how content-type being used in body, and whether encrypted or
|
|
40
54
|
* not.
|
|
55
|
+
*
|
|
56
|
+
* @evidence contracts/common.md#principled-implementation A body is described by its content type, which selects the encoding, and by whether it is encrypted, which selects the fetcher; the union keeps the common types visible while allowing any other string.
|
|
57
|
+
* @evidence contracts/common.md#clear-and-simple-design Two fields, one of them optional.
|
|
58
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
59
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states that it describes the content type and the encryption.
|
|
41
60
|
*/
|
|
42
61
|
interface IBody {
|
|
43
62
|
type: "application/json" | "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | (string & {});
|
package/lib/IPropagation.d.ts
CHANGED
|
@@ -7,20 +7,21 @@
|
|
|
7
7
|
*
|
|
8
8
|
* ```typescript
|
|
9
9
|
* type Output = IPropagation<{
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* 200: ISeller.IAuthorized;
|
|
11
|
+
* 400: TypeGuardError.IProps;
|
|
12
|
+
* }>;
|
|
13
13
|
*
|
|
14
14
|
* const output: Output = await sdk.sellers.authenticate.join(input);
|
|
15
15
|
* if (output.success) {
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* // automatically casted to "ISeller.IAuthorized" type
|
|
17
|
+
* const authorized: ISeller.IAuthorized = output.data;
|
|
18
18
|
* } else if (output.status === 400) {
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* // The unknown-status fallback overlaps numeric statuses. Validate the
|
|
20
|
+
* // body before treating it as TypeGuardError.IProps.
|
|
21
|
+
* const error: unknown = output.data;
|
|
21
22
|
* } else {
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* // unknown type when out of pre-defined status codes
|
|
24
|
+
* const result: unknown = output.data;
|
|
24
25
|
* }
|
|
25
26
|
* ```
|
|
26
27
|
*
|
|
@@ -33,6 +34,10 @@
|
|
|
33
34
|
* @author Jeongho Nam - https://github.com/samchon
|
|
34
35
|
* @template StatusMap Map of status code and its body data type.
|
|
35
36
|
* @template Success Default success status code.
|
|
37
|
+
* @evidence contracts/common.md#principled-implementation Each configured status becomes a branch whose success flag is true for configured success statuses, 200 and 201 by default. A false-success fallback with numeric status and unknown data represents unconfigured responses; TypeScript cannot subtract numeric literals from number, so this fallback also overlaps configured failure statuses and status-only narrowing cannot prove their payload shape.
|
|
38
|
+
* @evidence contracts/common.md#clear-and-simple-design One mapped type indexed into a union, plus the fallback branch.
|
|
39
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
40
|
+
* @evidence contracts/common.md#meaningful-documentation The comment gives an example of narrowing and says which generated SDK option uses the type.
|
|
36
41
|
*/
|
|
37
42
|
export type IPropagation<StatusMap extends {
|
|
38
43
|
[P in IPropagation.Status]?: any;
|
|
@@ -46,6 +51,11 @@ export declare namespace IPropagation {
|
|
|
46
51
|
* The special characters like `2XX`, `3XX`, `4XX`, `5XX` are meaning the
|
|
47
52
|
* range of status codes. If `5XX` is specified, it means the status code is
|
|
48
53
|
* in the range of `500` to `599`.
|
|
54
|
+
*
|
|
55
|
+
* @evidence contracts/common.md#principled-implementation A status is a number or one of the four range spellings, which is enough to configure both exact and ranged branches.
|
|
56
|
+
* @evidence contracts/common.md#clear-and-simple-design A single union.
|
|
57
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
58
|
+
* @evidence contracts/common.md#meaningful-documentation The comment defines the range spellings.
|
|
49
59
|
*/
|
|
50
60
|
export type Status = number | "2XX" | "3XX" | "4XX" | "5XX";
|
|
51
61
|
/**
|
|
@@ -54,6 +64,11 @@ export declare namespace IPropagation {
|
|
|
54
64
|
* `IPropagation.IBranch` is a branch type composing `IPropagation` type,
|
|
55
65
|
* which is gathering all possible status codes and their body data types as a
|
|
56
66
|
* union type.
|
|
67
|
+
*
|
|
68
|
+
* @evidence contracts/common.md#principled-implementation A branch pairs a literal success flag with the status, the data, and the headers, and turns a range spelling into the union of its integers, so a narrowed status is a number the caller can compare.
|
|
69
|
+
* @evidence contracts/common.md#clear-and-simple-design One record with a conditional on the status member.
|
|
70
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
71
|
+
* @evidence contracts/common.md#meaningful-documentation The comment explains that it is the element of the propagation union.
|
|
57
72
|
*/
|
|
58
73
|
export interface IBranch<Success extends boolean, StatusValue, BodyData> {
|
|
59
74
|
success: Success;
|
|
@@ -61,8 +76,16 @@ export declare namespace IPropagation {
|
|
|
61
76
|
data: BodyData;
|
|
62
77
|
headers: Record<string, string | string[]>;
|
|
63
78
|
}
|
|
64
|
-
/**
|
|
65
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Range of status codes by the first digit, `"4XX"` for `400` to `499`.
|
|
81
|
+
*
|
|
82
|
+
* @evidence contracts/common.md#principled-implementation The first-digit spelling maps to the integers from its hundred up to the next hundred, computed by excluding a smaller enumeration from a larger one.
|
|
83
|
+
* @evidence contracts/common.md#clear-and-simple-design One conditional over the four spellings, using two private helper types.
|
|
84
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
85
|
+
* @evidence contracts/common.md#meaningful-documentation The comment gives the range rule with an example.
|
|
86
|
+
*/
|
|
87
|
+
export type StatusRange<T extends "2XX" | "3XX" | "4XX" | "5XX"> = T extends "2XX" ? IntRange<200, 300> : T extends "3XX" ? IntRange<300, 400> : T extends "4XX" ? IntRange<400, 500> : IntRange<500, 600>;
|
|
88
|
+
/** Integers from `F` up to, not including, `T`. */
|
|
66
89
|
type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;
|
|
67
90
|
type Enumerate<N extends number, Acc extends number[] = []> = Acc["length"] extends N ? Acc[number] : Enumerate<N, [...Acc, Acc["length"]]>;
|
|
68
91
|
export {};
|
package/lib/NestiaSimulator.d.ts
CHANGED
|
@@ -1,13 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request validation for the mockup simulator of a generated SDK.
|
|
3
|
+
*
|
|
4
|
+
* A simulated function does not call a server. It validates its input with
|
|
5
|
+
* typia and, when the input is wrong, throws the `HttpError` with status 400
|
|
6
|
+
* that the real server would answer with.
|
|
7
|
+
*
|
|
8
|
+
* @evidence contracts/common.md#principled-implementation Each validator runs the caller's assertion and converts a readable typia `TypeGuardError` shape into an `HttpError` 400 whose JSON body carries the method, path, expected type and value plus a message naming the failing part. A shared snapshot reads each needed property once; malformed or unreadable shapes rethrow the caller's original value. Payload values must support JSON serialization, whose errors still propagate.
|
|
9
|
+
* @evidence contracts/common.md#clear-and-simple-design One public entry point, `assert`, returns four validators that differ only in their message, sharing one private conversion; the shape snapshot reader and the error interface are module-private.
|
|
10
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Classification checks the readable error structure (method, path, expected type, name, message and stack) rather than its class, then captures the payload value. A value that lacks any of those fields with the expected types, or whose property access throws, is not classified as a type guard failure and is rethrown unchanged; unrelated task errors are neither replaced nor swallowed.
|
|
11
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states what the simulator validates and what it throws.
|
|
12
|
+
*/
|
|
1
13
|
export declare namespace NestiaSimulator {
|
|
14
|
+
/**
|
|
15
|
+
* Route facts the simulator needs to build its 400 error: the host, the path,
|
|
16
|
+
* and the method.
|
|
17
|
+
*
|
|
18
|
+
* `contentType` is the content type of the route's success response, which
|
|
19
|
+
* the generated code answers with; the simulated 400 is JSON whatever it is.
|
|
20
|
+
*
|
|
21
|
+
* @evidence contracts/common.md#principled-implementation The host, path, and method identify the request in the error, and the content type describes the success response of the generated function, which the generated code answers with.
|
|
22
|
+
* @evidence contracts/common.md#clear-and-simple-design A four-field record with no behavior.
|
|
23
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The values are supplied by the generated SDK for its own route.
|
|
24
|
+
* @evidence contracts/common.md#meaningful-documentation The comment says what each part is used for, with the `contentType` member documenting when it is `null`.
|
|
25
|
+
*/
|
|
2
26
|
interface IProps {
|
|
3
27
|
host: string;
|
|
4
28
|
path: string;
|
|
5
|
-
method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
|
|
6
|
-
|
|
29
|
+
method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE" | "HEAD";
|
|
30
|
+
/**
|
|
31
|
+
* Content type of the route's success response, `null` for one without a
|
|
32
|
+
* body such as `HEAD`'s. The simulated 400 is JSON whatever it is, as the
|
|
33
|
+
* server's is.
|
|
34
|
+
*/
|
|
35
|
+
contentType: string | null;
|
|
7
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates the validators of one simulated route: `param(name)`, `query`,
|
|
39
|
+
* `body`, and `headers`.
|
|
40
|
+
*
|
|
41
|
+
* Each validator takes the closure that performs the typia assertion. A
|
|
42
|
+
* failed assertion throws an `HttpError` with status 400 and a JSON body; any
|
|
43
|
+
* other error is rethrown as it is.
|
|
44
|
+
*
|
|
45
|
+
* @evidence contracts/common.md#principled-implementation The four validators share the conversion in `validate` and differ in the message they attach, which names the URL parameter or states that the query, body, or headers do not follow the promised type.
|
|
46
|
+
* @evidence contracts/common.md#clear-and-simple-design One function returning the four validators as an object, so a generated simulator has one import.
|
|
47
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The HTTP error is the one the real server returns; nothing is simulated beyond running the assertion.
|
|
48
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states what it returns and what each validator throws.
|
|
49
|
+
*/
|
|
8
50
|
const assert: (props: IProps) => {
|
|
9
51
|
param: (name: string) => <T>(task: () => T) => void;
|
|
10
52
|
query: <T>(task: () => T) => void;
|
|
11
53
|
body: <T>(task: () => T) => void;
|
|
54
|
+
headers: <T>(task: () => T) => void;
|
|
12
55
|
};
|
|
13
56
|
}
|
package/lib/NestiaSimulator.js
CHANGED
|
@@ -3,13 +3,39 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.NestiaSimulator = void 0;
|
|
4
4
|
const HttpError_1 = require("./HttpError");
|
|
5
5
|
const join_host_and_path_1 = require("./internal/join_host_and_path");
|
|
6
|
+
/**
|
|
7
|
+
* Request validation for the mockup simulator of a generated SDK.
|
|
8
|
+
*
|
|
9
|
+
* A simulated function does not call a server. It validates its input with
|
|
10
|
+
* typia and, when the input is wrong, throws the `HttpError` with status 400
|
|
11
|
+
* that the real server would answer with.
|
|
12
|
+
*
|
|
13
|
+
* @evidence contracts/common.md#principled-implementation Each validator runs the caller's assertion and converts a readable typia `TypeGuardError` shape into an `HttpError` 400 whose JSON body carries the method, path, expected type and value plus a message naming the failing part. A shared snapshot reads each needed property once; malformed or unreadable shapes rethrow the caller's original value. Payload values must support JSON serialization, whose errors still propagate.
|
|
14
|
+
* @evidence contracts/common.md#clear-and-simple-design One public entry point, `assert`, returns four validators that differ only in their message, sharing one private conversion; the shape snapshot reader and the error interface are module-private.
|
|
15
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Classification checks the readable error structure (method, path, expected type, name, message and stack) rather than its class, then captures the payload value. A value that lacks any of those fields with the expected types, or whose property access throws, is not classified as a type guard failure and is rethrown unchanged; unrelated task errors are neither replaced nor swallowed.
|
|
16
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states what the simulator validates and what it throws.
|
|
17
|
+
*/
|
|
6
18
|
var NestiaSimulator;
|
|
7
19
|
(function (NestiaSimulator) {
|
|
20
|
+
/**
|
|
21
|
+
* Creates the validators of one simulated route: `param(name)`, `query`,
|
|
22
|
+
* `body`, and `headers`.
|
|
23
|
+
*
|
|
24
|
+
* Each validator takes the closure that performs the typia assertion. A
|
|
25
|
+
* failed assertion throws an `HttpError` with status 400 and a JSON body; any
|
|
26
|
+
* other error is rethrown as it is.
|
|
27
|
+
*
|
|
28
|
+
* @evidence contracts/common.md#principled-implementation The four validators share the conversion in `validate` and differ in the message they attach, which names the URL parameter or states that the query, body, or headers do not follow the promised type.
|
|
29
|
+
* @evidence contracts/common.md#clear-and-simple-design One function returning the four validators as an object, so a generated simulator has one import.
|
|
30
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The HTTP error is the one the real server returns; nothing is simulated beyond running the assertion.
|
|
31
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states what it returns and what each validator throws.
|
|
32
|
+
*/
|
|
8
33
|
NestiaSimulator.assert = (props) => {
|
|
9
34
|
return {
|
|
10
35
|
param: param(props),
|
|
11
36
|
query: query(props),
|
|
12
37
|
body: body(props),
|
|
38
|
+
headers: headers(props),
|
|
13
39
|
};
|
|
14
40
|
};
|
|
15
41
|
const param = (props) => (name) => (task) => {
|
|
@@ -17,29 +43,54 @@ var NestiaSimulator;
|
|
|
17
43
|
};
|
|
18
44
|
const query = (props) => (task) => validate(() => "Request query parameters are not following the promised type.")(props)(task);
|
|
19
45
|
const body = (props) => (task) => validate(() => "Request body is not following the promised type.")(props)(task);
|
|
20
|
-
const
|
|
46
|
+
const headers = (props) => (task) => validate(() => "Request headers are not following the promised type.")(props)(task);
|
|
47
|
+
const validate = (message) => (props) => (task) => {
|
|
21
48
|
try {
|
|
22
49
|
task();
|
|
23
50
|
}
|
|
24
51
|
catch (exp) {
|
|
25
|
-
|
|
52
|
+
const guard = readTypeGuardError(exp);
|
|
53
|
+
if (guard !== null)
|
|
26
54
|
throw new HttpError_1.HttpError(props.method, (0, join_host_and_path_1.join_host_and_path)(props.host, props.path), 400, {
|
|
27
|
-
"Content-Type":
|
|
55
|
+
"Content-Type": "application/json",
|
|
28
56
|
}, JSON.stringify({
|
|
29
|
-
method:
|
|
30
|
-
path:
|
|
31
|
-
expected:
|
|
32
|
-
value:
|
|
33
|
-
message: message(
|
|
57
|
+
method: guard.method,
|
|
58
|
+
path: guard.path,
|
|
59
|
+
expected: guard.expected,
|
|
60
|
+
value: guard.value,
|
|
61
|
+
message: message(guard),
|
|
34
62
|
}));
|
|
35
63
|
throw exp;
|
|
36
64
|
}
|
|
37
65
|
};
|
|
38
66
|
})(NestiaSimulator || (exports.NestiaSimulator = NestiaSimulator = {}));
|
|
39
|
-
const
|
|
40
|
-
(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
67
|
+
const readTypeGuardError = (input) => {
|
|
68
|
+
if (typeof input !== "object" || input === null)
|
|
69
|
+
return null;
|
|
70
|
+
try {
|
|
71
|
+
const method = input.method;
|
|
72
|
+
if (typeof method !== "string")
|
|
73
|
+
return null;
|
|
74
|
+
const path = input.path;
|
|
75
|
+
if (path !== undefined && typeof path !== "string")
|
|
76
|
+
return null;
|
|
77
|
+
const expected = input.expected;
|
|
78
|
+
if (typeof expected !== "string")
|
|
79
|
+
return null;
|
|
80
|
+
const name = input.name;
|
|
81
|
+
if (typeof name !== "string")
|
|
82
|
+
return null;
|
|
83
|
+
const message = input.message;
|
|
84
|
+
if (typeof message !== "string")
|
|
85
|
+
return null;
|
|
86
|
+
const stack = input.stack;
|
|
87
|
+
if (stack !== undefined && typeof stack !== "string")
|
|
88
|
+
return null;
|
|
89
|
+
const value = input.value;
|
|
90
|
+
return { method, path, expected, name, message, stack, value };
|
|
91
|
+
}
|
|
92
|
+
catch (_a) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
45
96
|
//# sourceMappingURL=NestiaSimulator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NestiaSimulator.js","sourceRoot":"","sources":["../src/NestiaSimulator.ts"],"names":[],"mappings":";;;AAAA,2CAAwC;AACxC,sEAAmE;AAEnE,IAAiB,eAAe,
|
|
1
|
+
{"version":3,"file":"NestiaSimulator.js","sourceRoot":"","sources":["../src/NestiaSimulator.ts"],"names":[],"mappings":"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"}
|
package/lib/NestiaSimulator.mjs
CHANGED
|
@@ -7,7 +7,8 @@ let NestiaSimulator;
|
|
|
7
7
|
return {
|
|
8
8
|
param: param(props),
|
|
9
9
|
query: query(props),
|
|
10
|
-
body: body(props)
|
|
10
|
+
body: body(props),
|
|
11
|
+
headers: headers(props)
|
|
11
12
|
};
|
|
12
13
|
};
|
|
13
14
|
const param = (props) => (name) => (task) => {
|
|
@@ -15,22 +16,51 @@ let NestiaSimulator;
|
|
|
15
16
|
};
|
|
16
17
|
const query = (props) => (task) => validate(() => "Request query parameters are not following the promised type.")(props)(task);
|
|
17
18
|
const body = (props) => (task) => validate(() => "Request body is not following the promised type.")(props)(task);
|
|
18
|
-
const
|
|
19
|
+
const headers = (props) => (task) => validate(() => "Request headers are not following the promised type.")(props)(task);
|
|
20
|
+
const validate = (message) => (props) => (task) => {
|
|
19
21
|
try {
|
|
20
22
|
task();
|
|
21
23
|
} catch (exp) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const guard = readTypeGuardError(exp);
|
|
25
|
+
if (guard !== null) throw new HttpError(props.method, join_host_and_path(props.host, props.path), 400, { "Content-Type": "application/json" }, JSON.stringify({
|
|
26
|
+
method: guard.method,
|
|
27
|
+
path: guard.path,
|
|
28
|
+
expected: guard.expected,
|
|
29
|
+
value: guard.value,
|
|
30
|
+
message: message(guard)
|
|
28
31
|
}));
|
|
29
32
|
throw exp;
|
|
30
33
|
}
|
|
31
34
|
};
|
|
32
35
|
})(NestiaSimulator || (NestiaSimulator = {}));
|
|
33
|
-
const
|
|
36
|
+
const readTypeGuardError = (input) => {
|
|
37
|
+
if (typeof input !== "object" || input === null) return null;
|
|
38
|
+
try {
|
|
39
|
+
const method = input.method;
|
|
40
|
+
if (typeof method !== "string") return null;
|
|
41
|
+
const path = input.path;
|
|
42
|
+
if (path !== void 0 && typeof path !== "string") return null;
|
|
43
|
+
const expected = input.expected;
|
|
44
|
+
if (typeof expected !== "string") return null;
|
|
45
|
+
const name = input.name;
|
|
46
|
+
if (typeof name !== "string") return null;
|
|
47
|
+
const message = input.message;
|
|
48
|
+
if (typeof message !== "string") return null;
|
|
49
|
+
const stack = input.stack;
|
|
50
|
+
if (stack !== void 0 && typeof stack !== "string") return null;
|
|
51
|
+
return {
|
|
52
|
+
method,
|
|
53
|
+
path,
|
|
54
|
+
expected,
|
|
55
|
+
name,
|
|
56
|
+
message,
|
|
57
|
+
stack,
|
|
58
|
+
value: input.value
|
|
59
|
+
};
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
34
64
|
//#endregion
|
|
35
65
|
export { NestiaSimulator };
|
|
36
66
|
|