@eecho/api-client 0.0.3 → 0.2.0
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 +30 -10
- package/dist/client.d.ts +15 -14
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +74 -68
- package/dist/client.js.map +1 -1
- package/dist/handlers.d.ts +2 -2
- package/dist/handlers.d.ts.map +1 -1
- package/dist/handlers.js +31 -22
- package/dist/handlers.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/spec.d.ts +13 -12
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js +59 -74
- package/dist/spec.js.map +1 -1
- package/package.json +14 -6
- package/dist/spec.generator.d.ts +0 -90
- package/dist/spec.generator.d.ts.map +0 -1
- package/dist/spec.generator.js +0 -92
- package/dist/spec.generator.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,22 +1,42 @@
|
|
|
1
1
|
# @eecho/api-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Validated HTTP execution for API contracts created by `@eecho/definition`.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @eecho/api-client @eecho/definition
|
|
8
|
+
npm install @eecho/api-client @eecho/definition zod
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Usage
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- TypeScript support with full type inference
|
|
17
|
-
- Customizable HTTP client configuration
|
|
13
|
+
```ts
|
|
14
|
+
import { createAPI, createHttpClient, createRetryHandler } from '@eecho/api-client';
|
|
15
|
+
import { PetAPI } from './pet-api.js';
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
const httpClient = createHttpClient();
|
|
18
|
+
httpClient.setHost('https://api.example.com');
|
|
19
|
+
httpClient.addExceptionHandler(createRetryHandler({
|
|
20
|
+
retryCount: 2,
|
|
21
|
+
timeout: 250,
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
const petAPI = createAPI({
|
|
25
|
+
apiSpec: PetAPI.ReadAPISpecification,
|
|
26
|
+
httpClient,
|
|
27
|
+
});
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
const response = await petAPI.getItems({
|
|
30
|
+
queryParams: {
|
|
31
|
+
filter: { species: 'Dog' },
|
|
32
|
+
sort: { name: 'asc' },
|
|
33
|
+
},
|
|
34
|
+
});
|
|
22
35
|
```
|
|
36
|
+
|
|
37
|
+
Requests are validated before they are sent. JSON responses are validated
|
|
38
|
+
before they are returned to application code. HTTP failures can be handled by
|
|
39
|
+
ordered exception handlers; retry behavior is opt-in.
|
|
40
|
+
|
|
41
|
+
`genAPIDefinition` is re-exported for compatibility. New code should import the
|
|
42
|
+
contract generator from `@eecho/definition`, which owns the shared contract.
|
package/dist/client.d.ts
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
type
|
|
2
|
-
headers?:
|
|
3
|
-
[key: string]: string;
|
|
4
|
-
};
|
|
1
|
+
type RequestOptions = Omit<RequestInit, 'headers'> & {
|
|
2
|
+
headers?: Record<string, string>;
|
|
5
3
|
};
|
|
6
4
|
export interface FetchExceptionContext {
|
|
7
|
-
errorType:
|
|
5
|
+
errorType: 'FetchException';
|
|
8
6
|
requestUrl: string;
|
|
9
7
|
response?: Response;
|
|
10
8
|
options: RequestInit;
|
|
11
9
|
timestamp: Date;
|
|
10
|
+
cause?: unknown;
|
|
12
11
|
}
|
|
13
|
-
export type APIExceptionHandler = (
|
|
12
|
+
export type APIExceptionHandler = (context: FetchExceptionContext) => Promise<{
|
|
14
13
|
result?: Response;
|
|
15
14
|
isNext: boolean;
|
|
16
15
|
}>;
|
|
17
|
-
export type RequestHandler = (
|
|
16
|
+
export type RequestHandler = (request: {
|
|
18
17
|
url: string;
|
|
19
|
-
options:
|
|
18
|
+
options: RequestOptions;
|
|
20
19
|
}) => Promise<{
|
|
21
20
|
url: string;
|
|
22
|
-
options:
|
|
21
|
+
options: RequestOptions;
|
|
23
22
|
}>;
|
|
24
23
|
export declare function createHttpClient(): {
|
|
25
24
|
setHost(url: string): void;
|
|
26
|
-
setHeader(
|
|
25
|
+
setHeader(nextHeaders: Record<string, string>): void;
|
|
27
26
|
addRequestHandler(handler: RequestHandler): void;
|
|
28
27
|
addExceptionHandler(handler: APIExceptionHandler): void;
|
|
29
28
|
readonly host: string;
|
|
30
|
-
readonly headers:
|
|
29
|
+
readonly headers: {
|
|
30
|
+
[x: string]: string;
|
|
31
|
+
};
|
|
31
32
|
readonly apiExceptionHandlers: APIExceptionHandler[];
|
|
32
|
-
fetch(
|
|
33
|
+
fetch(input: {
|
|
33
34
|
url: string;
|
|
34
|
-
options?:
|
|
35
|
-
}): Promise<Response
|
|
35
|
+
options?: RequestOptions;
|
|
36
|
+
}): Promise<Response>;
|
|
36
37
|
};
|
|
37
38
|
export {};
|
|
38
39
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,KAAK,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAErD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,cAAc,CAAC;CACzB,KAAK,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,CAAC;AA4DxD,wBAAgB,gBAAgB;iBAOf,MAAM;2BAGI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;+BAGlB,cAAc;iCAGZ,mBAAmB;;;;;;iBAc7B;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,cAAc,CAAA;KAAE;EAoC/D"}
|
package/dist/client.js
CHANGED
|
@@ -1,87 +1,93 @@
|
|
|
1
1
|
class FetchException extends Error {
|
|
2
|
-
constructor(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
this.
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
2
|
+
constructor(failure) {
|
|
3
|
+
const status = failure.response ? ` (${failure.response.status})` : '';
|
|
4
|
+
super(`Fetch failed for ${failure.requestUrl}${status}`);
|
|
5
|
+
this.name = 'FetchException';
|
|
6
|
+
this.errorType = 'FetchException';
|
|
7
|
+
this.timestamp = new Date();
|
|
8
|
+
this.requestUrl = failure.requestUrl;
|
|
9
|
+
this.options = failure.options;
|
|
10
|
+
this.response = failure.response;
|
|
11
|
+
this.cause = failure.cause;
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
function resolveRequestUrl(host, url) {
|
|
15
|
+
if (/^https?:\/\//i.test(url)) {
|
|
16
|
+
return url;
|
|
17
|
+
}
|
|
18
|
+
if (!host) {
|
|
19
|
+
throw new Error(`Cannot resolve relative request URL without a host: ${url}`);
|
|
20
|
+
}
|
|
21
|
+
const normalizedHost = host.replace(/\/$/, '');
|
|
22
|
+
const normalizedPath = url.startsWith('/') ? url : `/${url}`;
|
|
23
|
+
return `${normalizedHost}${normalizedPath}`;
|
|
24
|
+
}
|
|
25
|
+
async function runExceptionHandlers(exception, handlers) {
|
|
26
|
+
for (const handler of handlers) {
|
|
27
|
+
const { result, isNext } = await handler(exception);
|
|
28
|
+
if (!isNext) {
|
|
29
|
+
if (result) {
|
|
23
30
|
return result;
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
24
33
|
}
|
|
25
|
-
throw ctx;
|
|
26
34
|
}
|
|
35
|
+
throw exception;
|
|
36
|
+
}
|
|
37
|
+
export function createHttpClient() {
|
|
38
|
+
let host = '';
|
|
39
|
+
let headers = {};
|
|
40
|
+
const requestHandlers = [];
|
|
41
|
+
const exceptionHandlers = [];
|
|
27
42
|
return {
|
|
28
|
-
setHost(url) {
|
|
29
|
-
|
|
43
|
+
setHost(url) {
|
|
44
|
+
host = url;
|
|
45
|
+
},
|
|
46
|
+
setHeader(nextHeaders) {
|
|
47
|
+
headers = { ...nextHeaders };
|
|
48
|
+
},
|
|
30
49
|
addRequestHandler(handler) {
|
|
31
|
-
|
|
50
|
+
requestHandlers.push(handler);
|
|
32
51
|
},
|
|
33
52
|
addExceptionHandler(handler) {
|
|
34
|
-
|
|
53
|
+
exceptionHandlers.push(handler);
|
|
54
|
+
},
|
|
55
|
+
get host() {
|
|
56
|
+
return host;
|
|
35
57
|
},
|
|
36
|
-
get
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
58
|
+
get headers() {
|
|
59
|
+
return { ...headers };
|
|
60
|
+
},
|
|
61
|
+
get apiExceptionHandlers() {
|
|
62
|
+
return [...exceptionHandlers];
|
|
63
|
+
},
|
|
64
|
+
async fetch(input) {
|
|
65
|
+
let request = {
|
|
66
|
+
url: input.url,
|
|
67
|
+
options: {
|
|
68
|
+
...input.options,
|
|
69
|
+
headers: {
|
|
70
|
+
...headers,
|
|
71
|
+
...input.options?.headers,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
44
74
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const next = await handler({ url, options });
|
|
48
|
-
url = next.url;
|
|
49
|
-
options = next.options;
|
|
75
|
+
for (const handler of requestHandlers) {
|
|
76
|
+
request = await handler(request);
|
|
50
77
|
}
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
if (url.startsWith('/')) {
|
|
56
|
-
const hostUrl = new URL(__host);
|
|
57
|
-
return `${hostUrl.origin}${hostUrl.pathname.replace(/\/$/, '')}${url}`;
|
|
58
|
-
}
|
|
59
|
-
const normalizedHost = __host.endsWith('/') ? __host.slice(0, -1) : __host;
|
|
60
|
-
const normalizedUrl = url.startsWith('/') ? url : `/${url}`;
|
|
61
|
-
return `${normalizedHost}${normalizedUrl}`;
|
|
62
|
-
})();
|
|
78
|
+
const requestUrl = resolveRequestUrl(host, request.url);
|
|
79
|
+
let response;
|
|
80
|
+
let cause;
|
|
63
81
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
errorType: "FetchException",
|
|
69
|
-
requestUrl: fullUrl,
|
|
70
|
-
response: res,
|
|
71
|
-
options,
|
|
72
|
-
timestamp: new Date(),
|
|
73
|
-
});
|
|
74
|
-
return await runHandlers(ctx);
|
|
82
|
+
response = await fetch(requestUrl, request.options);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
cause = error;
|
|
75
86
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
errorType: "FetchException",
|
|
79
|
-
requestUrl: fullUrl,
|
|
80
|
-
options,
|
|
81
|
-
timestamp: new Date(),
|
|
82
|
-
});
|
|
83
|
-
return await runHandlers(netCtx);
|
|
87
|
+
if (response?.ok) {
|
|
88
|
+
return response;
|
|
84
89
|
}
|
|
90
|
+
return runExceptionHandlers(new FetchException({ requestUrl, options: request.options, response, cause }), exceptionHandlers);
|
|
85
91
|
},
|
|
86
92
|
};
|
|
87
93
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/handlers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { APIExceptionHandler } from
|
|
2
|
-
export declare function createRetryHandler(
|
|
1
|
+
import type { APIExceptionHandler } from './client.js';
|
|
2
|
+
export declare function createRetryHandler(options: {
|
|
3
3
|
timeout?: number;
|
|
4
4
|
retryCount: number;
|
|
5
5
|
}): APIExceptionHandler;
|
package/dist/handlers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAyB,MAAM,
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAyB,MAAM,aAAa,CAAC;AAY9E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,mBAAmB,CAwCtB"}
|
package/dist/handlers.js
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
const wait = (delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
2
|
+
function isRetryable(response) {
|
|
3
|
+
if (!response) {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
return response.status === 429 || response.status >= 500;
|
|
7
|
+
}
|
|
8
|
+
export function createRetryHandler(options) {
|
|
9
|
+
const { retryCount, timeout: delayMs = 1000 } = options;
|
|
10
|
+
if (!Number.isInteger(retryCount) || retryCount < 0) {
|
|
11
|
+
throw new RangeError('retryCount must be a non-negative integer.');
|
|
12
|
+
}
|
|
13
|
+
if (delayMs < 0) {
|
|
14
|
+
throw new RangeError('timeout must be non-negative.');
|
|
15
|
+
}
|
|
16
|
+
return async (context) => {
|
|
17
|
+
if (!isRetryable(context.response) || context.options.signal?.aborted) {
|
|
12
18
|
return { isNext: true };
|
|
13
19
|
}
|
|
14
|
-
|
|
15
|
-
for (let attempt =
|
|
16
|
-
await
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
let latestResponse;
|
|
21
|
+
for (let attempt = 0; attempt < retryCount; attempt += 1) {
|
|
22
|
+
await wait(delayMs);
|
|
23
|
+
if (context.options.signal?.aborted) {
|
|
24
|
+
return { isNext: true };
|
|
25
|
+
}
|
|
20
26
|
try {
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
return { result:
|
|
27
|
+
latestResponse = await fetch(context.requestUrl, context.options);
|
|
28
|
+
if (latestResponse.ok || !isRetryable(latestResponse)) {
|
|
29
|
+
return { result: latestResponse, isNext: false };
|
|
24
30
|
}
|
|
25
31
|
}
|
|
26
|
-
catch
|
|
32
|
+
catch {
|
|
33
|
+
latestResponse = undefined;
|
|
27
34
|
}
|
|
28
35
|
}
|
|
29
|
-
return
|
|
36
|
+
return latestResponse
|
|
37
|
+
? { result: latestResponse, isNext: false }
|
|
38
|
+
: { isNext: true };
|
|
30
39
|
};
|
|
31
40
|
}
|
|
32
41
|
//# sourceMappingURL=handlers.js.map
|
package/dist/handlers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAEA,MAAM,
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAEA,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAEzF,SAAS,WAAW,CAAC,QAAmB;IACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAGlC;IACC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,IAAK,EAAE,GAAG,OAAO,CAAC;IAEzD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,UAAU,CAAC,4CAA4C,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,KAAK,EAAE,OAA8B,EAAE,EAAE;QAC9C,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YACtE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC;QAED,IAAI,cAAoC,CAAC;QAEzC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,UAAU,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;YAEpB,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;gBACpC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YAC1B,CAAC;YAED,IAAI,CAAC;gBACH,cAAc,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;gBAElE,IAAI,cAAc,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,CAAC;oBACtD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBACnD,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc,GAAG,SAAS,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,OAAO,cAAc;YACnB,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE;YAC3C,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { createHttpClient } from './client';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export { createHttpClient } from './client.js';
|
|
2
|
+
export type { APIExceptionHandler, FetchExceptionContext, RequestHandler } from './client.js';
|
|
3
|
+
export { createRetryHandler } from './handlers.js';
|
|
4
|
+
export { createAPI } from './spec.js';
|
|
5
|
+
export type { APIMapOf } from './spec.js';
|
|
6
|
+
export { genAPIDefinition } from '@eecho/definition';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { createHttpClient } from './client';
|
|
2
|
-
export { createRetryHandler } from './handlers';
|
|
3
|
-
export { createAPI } from './spec';
|
|
4
|
-
export
|
|
1
|
+
export { createHttpClient } from './client.js';
|
|
2
|
+
export { createRetryHandler } from './handlers.js';
|
|
3
|
+
export { createAPI } from './spec.js';
|
|
4
|
+
// Compatibility re-export: API contracts are owned by @eecho/definition.
|
|
5
|
+
export { genAPIDefinition } from '@eecho/definition';
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,yEAAyE;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/spec.d.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ClientAPISpecification } from '@eecho/definition';
|
|
3
|
+
import { createHttpClient } from './client.js';
|
|
4
|
+
type InferInputIfSchema<T> = T extends z.ZodTypeAny ? z.input<T> : never;
|
|
5
|
+
type InferOutputIfSchema<T> = T extends z.ZodTypeAny ? z.output<T> : never;
|
|
6
|
+
export type APIMapOf<TSpec extends ClientAPISpecification> = {
|
|
7
|
+
[K in TSpec['operationId']]: (input?: {
|
|
8
|
+
queryParams?: InferInputIfSchema<TSpec['Request']['queryParams']>;
|
|
9
|
+
body?: InferInputIfSchema<TSpec['Request']['body']>;
|
|
10
|
+
}) => Promise<InferOutputIfSchema<TSpec['Response']['body']>>;
|
|
9
11
|
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
apiSpec: S;
|
|
12
|
+
export declare function createAPI<TSpec extends ClientAPISpecification>(options: {
|
|
13
|
+
apiSpec: TSpec;
|
|
13
14
|
httpClient: ReturnType<typeof createHttpClient>;
|
|
14
15
|
contentType?: 'application/json' | 'multipart/form-data';
|
|
15
16
|
responseType?: 'json' | 'blob';
|
|
16
|
-
}): APIMapOf<
|
|
17
|
+
}): APIMapOf<TSpec>;
|
|
17
18
|
export {};
|
|
18
19
|
//# sourceMappingURL=spec.d.ts.map
|
package/dist/spec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,KAAK,kBAAkB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AACzE,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAE3E,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,sBAAsB,IAAI;KAC1D,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QACpC,WAAW,CAAC,EAAE,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC,EAAE,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;KACrD,KAAK,OAAO,CAAC,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;CAC9D,CAAC;AA0DF,wBAAgB,SAAS,CAAC,KAAK,SAAS,sBAAsB,EAAE,OAAO,EAAE;IACvE,OAAO,EAAE,KAAK,CAAC;IACf,UAAU,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;IAChD,WAAW,CAAC,EAAE,kBAAkB,GAAG,qBAAqB,CAAC;IACzD,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC,GAsDM,QAAQ,CAAC,KAAK,CAAC,CACrB"}
|
package/dist/spec.js
CHANGED
|
@@ -1,86 +1,71 @@
|
|
|
1
1
|
import { stringify } from 'qs';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
function createValidationError(label, error) {
|
|
3
|
+
const validationError = new Error(`${label}: ${error.message}`);
|
|
4
|
+
Object.assign(validationError, { cause: error });
|
|
5
|
+
return validationError;
|
|
6
|
+
}
|
|
7
|
+
function parseRequestPart(schema, value, label) {
|
|
8
|
+
if (!schema) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
const result = schema.safeParse(value);
|
|
12
|
+
if (!result.success) {
|
|
13
|
+
throw createValidationError(label, result.error);
|
|
14
|
+
}
|
|
15
|
+
return result.data;
|
|
16
|
+
}
|
|
17
|
+
function appendFormValue(formData, key, value) {
|
|
18
|
+
if (value === undefined || value === null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
value.forEach((item) => appendFormValue(formData, key, item));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
formData.append(key, value instanceof Blob ? value : String(value));
|
|
26
|
+
}
|
|
27
|
+
function serializeBody(value, contentType) {
|
|
28
|
+
if (value === undefined) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
if (contentType === 'application/json') {
|
|
32
|
+
return {
|
|
33
|
+
body: JSON.stringify(value),
|
|
34
|
+
headers: { 'Content-Type': 'application/json' },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const formData = new FormData();
|
|
38
|
+
if (typeof value === 'object' && value !== null) {
|
|
39
|
+
Object.entries(value).forEach(([key, item]) => appendFormValue(formData, key, item));
|
|
40
|
+
}
|
|
41
|
+
return { body: formData };
|
|
42
|
+
}
|
|
43
|
+
export function createAPI(options) {
|
|
44
|
+
const { apiSpec, httpClient, contentType = 'application/json', responseType = 'json', } = options;
|
|
45
|
+
const operation = `${apiSpec.operationId} ${apiSpec.Method} ${apiSpec.APIEndpoint}`;
|
|
6
46
|
const handler = async (input) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (apiSpec.Request.body && input?.body) {
|
|
16
|
-
const bodyParamsParsing = apiSpec.Request.body.safeParse(input.body);
|
|
17
|
-
if (!bodyParamsParsing.success) {
|
|
18
|
-
console.error(`API Body Params Validation Error: ${apiSpec.operationId} ${apiSpec.Method} ${apiSpec.APIEndpoint}`, bodyParamsParsing.error);
|
|
19
|
-
console.error(`Input Body Params:`, input?.body);
|
|
20
|
-
throw new Error(`API Body Params Validation Error: ${bodyParamsParsing.error.message}`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
let url = httpClient.host + apiSpec.APIEndpoint;
|
|
24
|
-
let queryString = "";
|
|
25
|
-
if (input?.queryParams) {
|
|
26
|
-
queryString = stringify(input.queryParams, { addQueryPrefix: true, arrayFormat: 'brackets' });
|
|
27
|
-
}
|
|
28
|
-
url += queryString;
|
|
29
|
-
// Content-Type에 따른 body 처리
|
|
30
|
-
let body;
|
|
31
|
-
let headers = {};
|
|
32
|
-
if (input?.body) {
|
|
33
|
-
if (contentType === 'application/json') {
|
|
34
|
-
body = JSON.stringify(input.body);
|
|
35
|
-
headers = { 'Content-Type': 'application/json' };
|
|
36
|
-
}
|
|
37
|
-
else if (contentType === 'multipart/form-data') {
|
|
38
|
-
// FormData로 변환
|
|
39
|
-
const formData = new FormData();
|
|
40
|
-
if (typeof input.body === 'object' && input.body !== null) {
|
|
41
|
-
Object.entries(input.body).forEach(([key, value]) => {
|
|
42
|
-
if (value instanceof File) {
|
|
43
|
-
formData.append(key, value);
|
|
44
|
-
}
|
|
45
|
-
else if (value !== undefined && value !== null) {
|
|
46
|
-
formData.append(key, String(value));
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
body = formData;
|
|
51
|
-
// multipart/form-data는 브라우저가 자동으로 Content-Type을 설정하므로 헤더를 설정하지 않음
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// 3) fetch
|
|
55
|
-
const res = await httpClient.fetch({
|
|
56
|
-
url: url.toString(),
|
|
47
|
+
const queryParams = parseRequestPart(apiSpec.Request.queryParams, input?.queryParams ?? {}, `Invalid query parameters for ${operation}`);
|
|
48
|
+
const bodyParams = parseRequestPart(apiSpec.Request.body, input?.body, `Invalid request body for ${operation}`);
|
|
49
|
+
const queryString = queryParams
|
|
50
|
+
? stringify(queryParams, { addQueryPrefix: true, arrayFormat: 'brackets' })
|
|
51
|
+
: '';
|
|
52
|
+
const requestBody = serializeBody(bodyParams, contentType);
|
|
53
|
+
const response = await httpClient.fetch({
|
|
54
|
+
url: `${apiSpec.APIEndpoint}${queryString}`,
|
|
57
55
|
options: {
|
|
58
56
|
method: apiSpec.Method,
|
|
59
|
-
|
|
60
|
-
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
57
|
+
...requestBody,
|
|
61
58
|
},
|
|
62
59
|
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (responseType === 'json') {
|
|
66
|
-
data = await res?.json();
|
|
67
|
-
}
|
|
68
|
-
else if (responseType === 'blob') {
|
|
69
|
-
data = await res?.blob();
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
throw new Error(`API request failed for ${operation}: ${response.status} ${response.statusText}`);
|
|
70
62
|
}
|
|
63
|
+
const data = responseType === 'json'
|
|
64
|
+
? await response.json()
|
|
65
|
+
: await response.blob();
|
|
71
66
|
const parsedResult = apiSpec.Response.body.safeParse(data);
|
|
72
|
-
if (res && !res.ok) {
|
|
73
|
-
console.error(`API Error: ${apiSpec.operationId} ${apiSpec.Method} ${apiSpec.APIEndpoint}`, {
|
|
74
|
-
status: res.status,
|
|
75
|
-
statusText: res.statusText,
|
|
76
|
-
data: parsedResult.error,
|
|
77
|
-
});
|
|
78
|
-
throw new Error(`API Error: ${res.status} ${res.statusText}`);
|
|
79
|
-
}
|
|
80
67
|
if (!parsedResult.success) {
|
|
81
|
-
|
|
82
|
-
console.error(`Response Data:`, data);
|
|
83
|
-
throw new Error(`API Response Validation Error: ${parsedResult.error.message}`);
|
|
68
|
+
throw createValidationError(`Invalid API response for ${operation}`, parsedResult.error);
|
|
84
69
|
}
|
|
85
70
|
return parsedResult.data;
|
|
86
71
|
};
|
package/dist/spec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eecho/api-client",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Validated HTTP client for shared EEcho API contracts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
7
13
|
"type": "module",
|
|
8
14
|
"files": [
|
|
9
15
|
"dist/**/*"
|
|
@@ -17,15 +23,17 @@
|
|
|
17
23
|
"license": "MIT",
|
|
18
24
|
"repository": {
|
|
19
25
|
"type": "git",
|
|
20
|
-
"url": "https://github.com/eecho/eechojs.git"
|
|
26
|
+
"url": "git+https://github.com/eecho/eechojs.git"
|
|
21
27
|
},
|
|
22
28
|
"dependencies": {
|
|
23
|
-
"@eecho/definition": "^0.0
|
|
24
|
-
"@types/qs": "^6.14.0",
|
|
29
|
+
"@eecho/definition": "^0.2.0",
|
|
25
30
|
"qs": "^6.14.0"
|
|
26
31
|
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"zod": "^4.1.12"
|
|
34
|
+
},
|
|
27
35
|
"devDependencies": {
|
|
28
|
-
"
|
|
36
|
+
"@types/qs": "^6.14.0",
|
|
29
37
|
"typescript": "^5.0.0"
|
|
30
38
|
},
|
|
31
39
|
"publishConfig": {
|
package/dist/spec.generator.d.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { Definition } from '@eecho/definition';
|
|
3
|
-
export declare function genAPIDefinition<TDefinition extends Definition, const TPrefix extends string>(params: {
|
|
4
|
-
definition: TDefinition;
|
|
5
|
-
endpointPrefix: TPrefix;
|
|
6
|
-
}): {
|
|
7
|
-
CreateAPISpecification: {
|
|
8
|
-
readonly APIEndpoint: `${TPrefix}/createItems`;
|
|
9
|
-
readonly Method: "POST";
|
|
10
|
-
readonly operationId: "createItems";
|
|
11
|
-
readonly Request: {
|
|
12
|
-
readonly body: z.ZodObject<{
|
|
13
|
-
data: z.ZodObject<({ [K_1 in keyof TDefinition]: TDefinition[K_1] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<any, any, infer TApi extends import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TApi["create"] extends readonly unknown[] ? Extract<"Optional", TApi["create"][number]> | Extract<"System", TApi["create"][number]> extends never ? K_1 : never : K_1 : never; }[keyof TDefinition] extends infer T_1 extends keyof TDefinition ? { [K in T_1 as TDefinition[K] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? K : never]: TDefinition[K] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<infer TSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TSchema : never; } : never) extends infer T ? { -readonly [P in keyof T]: T[P]; } : never, z.core.$strip>;
|
|
14
|
-
}, z.core.$strip>;
|
|
15
|
-
};
|
|
16
|
-
readonly Response: {
|
|
17
|
-
readonly body: z.ZodObject<{
|
|
18
|
-
success: z.ZodLiteral<true>;
|
|
19
|
-
data: z.ZodObject<{}, z.core.$strip>;
|
|
20
|
-
}, z.core.$strip>;
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
ReadAPISpecification: {
|
|
24
|
-
readonly APIEndpoint: `${TPrefix}/getItems`;
|
|
25
|
-
readonly Method: "GET";
|
|
26
|
-
readonly operationId: "getItems";
|
|
27
|
-
readonly Request: {
|
|
28
|
-
readonly queryParams: z.ZodObject<{
|
|
29
|
-
page: z.ZodOptional<z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
|
|
30
|
-
limit: z.ZodOptional<z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
|
|
31
|
-
filter: z.ZodUnion<readonly [z.ZodOptional<z.ZodObject<(({ [K_4 in keyof TDefinition]: TDefinition[K_4] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<any, any, infer TApi extends import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TApi["read"] extends readonly unknown[] ? "Searchable" extends infer T_5 ? T_5 extends "Searchable" ? T_5 extends TApi["read"][number] ? K_4 : never : never : never : never : never; }[keyof TDefinition] extends infer T_4 extends keyof TDefinition ? { [K_3 in T_4 as TDefinition[K_3] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? K_3 : never]: TDefinition[K_3] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<infer TSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TSchema : never; } : never) extends infer T_3 extends Record<string, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>> ? { [K_2 in keyof T_3]: z.ZodOptional<T_3[K_2]>; } : never) extends infer T_2 ? { -readonly [P_1 in keyof T_2]: T_2[P_1]; } : never, z.core.$strip>>, z.ZodOptional<z.ZodObject<(({ [K_7 in keyof TDefinition]: TDefinition[K_7] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<any, any, infer TApi extends import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TApi["read"] extends readonly unknown[] ? "SearchableArray" extends infer T_8 ? T_8 extends "SearchableArray" ? T_8 extends TApi["read"][number] ? K_7 : never : never : never : never : never; }[keyof TDefinition] extends infer T_7 extends keyof TDefinition ? { [K_6 in T_7 as TDefinition[K_6] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? K_6 : never]: TDefinition[K_6] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<infer TSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TSchema : never; } : never) extends infer T_6 extends Record<string, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>> ? { [K_5 in keyof T_6]: z.ZodOptional<z.ZodArray<z.ZodOptional<T_6[K_5]>>>; } : never) extends infer T_5 ? { -readonly [P_2 in keyof T_5]: T_5[P_2]; } : never, z.core.$strip>>]>;
|
|
32
|
-
sort: z.ZodOptional<z.ZodObject<(({ [K_10 in keyof TDefinition]: TDefinition[K_10] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<any, any, infer TApi extends import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TApi["read"] extends readonly unknown[] ? "Sortable" extends infer T_11 ? T_11 extends "Sortable" ? T_11 extends TApi["read"][number] ? K_10 : never : never : never : never : never; }[keyof TDefinition] extends infer T_10 extends keyof TDefinition ? { [K_9 in T_10 as TDefinition[K_9] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? K_9 : never]: TDefinition[K_9] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<infer TSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TSchema : never; } : never) extends infer T_9 extends Record<string, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>> ? { [K_8 in keyof T_9]: z.ZodOptional<T_9[K_8]>; } : never) extends infer T_8 ? { -readonly [P_3 in keyof T_8]: T_8[P_3]; } : never, z.core.$strip>>;
|
|
33
|
-
}, z.core.$strip>;
|
|
34
|
-
};
|
|
35
|
-
readonly Response: {
|
|
36
|
-
readonly body: z.ZodObject<{
|
|
37
|
-
success: z.ZodLiteral<true>;
|
|
38
|
-
data: z.ZodArray<z.ZodObject<({ [K_12 in keyof TDefinition]: TDefinition[K_12] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<any, any, infer TApi extends import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TApi["read"] extends readonly unknown[] ? Extract<"Hidden", TApi["read"][number]> | Extract<"Detail", TApi["read"][number]> extends never ? K_12 : never : K_12 : never; }[keyof TDefinition] extends infer T_12 extends keyof TDefinition ? { [K_11 in T_12 as TDefinition[K_11] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? K_11 : never]: TDefinition[K_11] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<infer TSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TSchema : never; } : never) extends infer T_11 ? { -readonly [P_4 in keyof T_11]: T_11[P_4]; } : never, z.core.$strip>>;
|
|
39
|
-
}, z.core.$strip>;
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
UpdateAPISpecification: {
|
|
43
|
-
readonly APIEndpoint: `${TPrefix}/updateItem`;
|
|
44
|
-
readonly Method: "POST";
|
|
45
|
-
readonly operationId: "updateItem";
|
|
46
|
-
readonly Request: {
|
|
47
|
-
readonly body: z.ZodObject<{
|
|
48
|
-
id: z.ZodAny;
|
|
49
|
-
data: z.ZodObject<(({ [K_15 in keyof TDefinition]: TDefinition[K_15] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<any, any, infer TApi extends import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TApi["update"] extends readonly unknown[] ? "Updatable" extends infer T_16 ? T_16 extends "Updatable" ? T_16 extends TApi["update"][number] ? K_15 : never : never : never : never : never; }[keyof TDefinition] extends infer T_15 extends keyof TDefinition ? { [K_14 in T_15 as TDefinition[K_14] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? K_14 : never]: TDefinition[K_14] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<infer TSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TSchema : never; } : never) extends infer T_14 extends Record<string, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>> ? { [K_13 in keyof T_14]: z.ZodOptional<T_14[K_13]>; } : never) extends infer T_13 ? { -readonly [P_5 in keyof T_13]: T_13[P_5]; } : never, z.core.$strip>;
|
|
50
|
-
}, z.core.$strip>;
|
|
51
|
-
};
|
|
52
|
-
readonly Response: {
|
|
53
|
-
readonly body: z.ZodObject<{
|
|
54
|
-
success: z.ZodLiteral<true>;
|
|
55
|
-
}, z.core.$strip>;
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
DeleteAPISpecification: {
|
|
59
|
-
readonly APIEndpoint: `${TPrefix}/deleteItems`;
|
|
60
|
-
readonly Method: "POST";
|
|
61
|
-
readonly operationId: "deleteItems";
|
|
62
|
-
readonly Request: {
|
|
63
|
-
readonly body: z.ZodObject<{
|
|
64
|
-
ids: z.ZodArray<z.ZodObject<{}, z.core.$strip>>;
|
|
65
|
-
}, z.core.$strip>;
|
|
66
|
-
};
|
|
67
|
-
readonly Response: {
|
|
68
|
-
readonly body: z.ZodObject<{
|
|
69
|
-
success: z.ZodLiteral<true>;
|
|
70
|
-
}, z.core.$strip>;
|
|
71
|
-
};
|
|
72
|
-
};
|
|
73
|
-
PutAPISpecification: {
|
|
74
|
-
readonly APIEndpoint: `${TPrefix}/putItem`;
|
|
75
|
-
readonly Method: "PUT";
|
|
76
|
-
readonly operationId: "putItem";
|
|
77
|
-
readonly Request: {
|
|
78
|
-
readonly body: z.ZodObject<{
|
|
79
|
-
data: z.ZodObject<({ [K_1 in keyof TDefinition]: TDefinition[K_1] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<any, any, infer TApi extends import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TApi["create"] extends readonly unknown[] ? Extract<"Optional", TApi["create"][number]> | Extract<"System", TApi["create"][number]> extends never ? K_1 : never : K_1 : never; }[keyof TDefinition] extends infer T_17 extends keyof TDefinition ? { [K in T_17 as TDefinition[K] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? K : never]: TDefinition[K] extends import("@eecho/definition/dist/model/model.define.type").PrimitiveDefinition<infer TSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, readonly import("@eecho/definition/dist/model/model.define.type").PrimitiveIndex[], import("@eecho/definition/dist/model/model.define.type").APIIndex, string> ? TSchema : never; } : never) extends infer T_16 ? { -readonly [P in keyof T_16]: T_16[P]; } : never, z.core.$strip>;
|
|
80
|
-
}, z.core.$strip>;
|
|
81
|
-
};
|
|
82
|
-
readonly Response: {
|
|
83
|
-
readonly body: z.ZodObject<{
|
|
84
|
-
success: z.ZodLiteral<true>;
|
|
85
|
-
data: z.ZodObject<{}, z.core.$strip>;
|
|
86
|
-
}, z.core.$strip>;
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
//# sourceMappingURL=spec.generator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spec.generator.d.ts","sourceRoot":"","sources":["../src/spec.generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAOL,UAAU,EACX,MAAM,mBAAmB,CAAC;AAE3B,wBAAgB,gBAAgB,CAAC,WAAW,SAAS,UAAU,EAAE,KAAK,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE;IACrG,UAAU,EAAE,WAAW,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;CACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgGA"}
|
package/dist/spec.generator.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { extractCreateRequiredField, extractReadbleField, extractSearchArrayOption, extractSearchOption, extractSortableOption, extractUpdateOption } from '@eecho/definition';
|
|
3
|
-
export function genAPIDefinition(params) {
|
|
4
|
-
const { definition, endpointPrefix } = params;
|
|
5
|
-
const createRequiredField = extractCreateRequiredField({ definition });
|
|
6
|
-
const readableField = extractReadbleField({ definition });
|
|
7
|
-
const searchableOption = extractSearchOption({ definition });
|
|
8
|
-
const searchableArrayOption = extractSearchArrayOption({ definition });
|
|
9
|
-
const sortableOption = extractSortableOption({ definition });
|
|
10
|
-
const updatableOption = extractUpdateOption({ definition });
|
|
11
|
-
const CreateAPISpecification = {
|
|
12
|
-
APIEndpoint: `${endpointPrefix}/createItems`,
|
|
13
|
-
Method: 'POST',
|
|
14
|
-
operationId: 'createItems',
|
|
15
|
-
Request: {
|
|
16
|
-
body: z.object({ data: z.object(createRequiredField) }),
|
|
17
|
-
},
|
|
18
|
-
Response: {
|
|
19
|
-
body: z.object({
|
|
20
|
-
success: z.literal(true),
|
|
21
|
-
data: z.object({}),
|
|
22
|
-
}),
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
const ReadAPISpecification = {
|
|
26
|
-
APIEndpoint: `${endpointPrefix}/getItems`,
|
|
27
|
-
Method: 'GET',
|
|
28
|
-
operationId: 'getItems',
|
|
29
|
-
Request: {
|
|
30
|
-
queryParams: z.object({
|
|
31
|
-
page: z.coerce.number().default(1).optional(),
|
|
32
|
-
limit: z.coerce.number().default(15).optional(),
|
|
33
|
-
filter: z.union([
|
|
34
|
-
z.object(searchableOption).optional(),
|
|
35
|
-
z.object(searchableArrayOption).optional()
|
|
36
|
-
]),
|
|
37
|
-
sort: z.object(sortableOption).optional(),
|
|
38
|
-
}),
|
|
39
|
-
},
|
|
40
|
-
Response: {
|
|
41
|
-
body: z.object({
|
|
42
|
-
success: z.literal(true),
|
|
43
|
-
data: z.array(z.object(readableField)),
|
|
44
|
-
})
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
const UpdateAPISpecification = {
|
|
48
|
-
APIEndpoint: `${endpointPrefix}/updateItem`,
|
|
49
|
-
Method: 'POST',
|
|
50
|
-
operationId: 'updateItem',
|
|
51
|
-
Request: {
|
|
52
|
-
body: z.object({
|
|
53
|
-
id: z.any(),
|
|
54
|
-
data: z.object(updatableOption),
|
|
55
|
-
})
|
|
56
|
-
},
|
|
57
|
-
Response: {
|
|
58
|
-
body: z.object({
|
|
59
|
-
success: z.literal(true),
|
|
60
|
-
}),
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
const DeleteAPISpecification = {
|
|
64
|
-
APIEndpoint: `${endpointPrefix}/deleteItems`,
|
|
65
|
-
Method: 'POST',
|
|
66
|
-
operationId: 'deleteItems',
|
|
67
|
-
Request: {
|
|
68
|
-
body: z.object({
|
|
69
|
-
ids: z.array(z.object({})),
|
|
70
|
-
}),
|
|
71
|
-
},
|
|
72
|
-
Response: {
|
|
73
|
-
body: z.object({
|
|
74
|
-
success: z.literal(true),
|
|
75
|
-
}),
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
const PutAPISpecification = {
|
|
79
|
-
...CreateAPISpecification,
|
|
80
|
-
APIEndpoint: `${endpointPrefix}/putItem`,
|
|
81
|
-
Method: 'PUT',
|
|
82
|
-
operationId: 'putItem'
|
|
83
|
-
};
|
|
84
|
-
return {
|
|
85
|
-
CreateAPISpecification,
|
|
86
|
-
ReadAPISpecification,
|
|
87
|
-
UpdateAPISpecification,
|
|
88
|
-
DeleteAPISpecification,
|
|
89
|
-
PutAPISpecification
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
//# sourceMappingURL=spec.generator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spec.generator.js","sourceRoot":"","sources":["../src/spec.generator.ts"],"names":[],"mappings":"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"}
|