@eecho/api-client 0.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 ADDED
@@ -0,0 +1,22 @@
1
+ # @eecho/api-client
2
+
3
+ Type-safe API client library for the EEcho framework.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @eecho/api-client @eecho/definition
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - Generate type-safe API clients
14
+ - Automatic API specification generation
15
+ - Built-in request/response handling
16
+ - TypeScript support with full type inference
17
+ - Customizable HTTP client configuration
18
+
19
+ ## Usage
20
+
21
+ ```typescript
22
+ ```
@@ -0,0 +1,38 @@
1
+ type SimpleInit = Omit<RequestInit, "headers"> & {
2
+ headers?: {
3
+ [key: string]: string;
4
+ };
5
+ };
6
+ export interface FetchExceptionContext {
7
+ errorType: "FetchException";
8
+ requestUrl: string;
9
+ response?: Response;
10
+ options: RequestInit;
11
+ timestamp: Date;
12
+ }
13
+ export type APIExceptionHandler = (ctx: FetchExceptionContext) => Promise<{
14
+ result?: Response;
15
+ isNext: boolean;
16
+ }>;
17
+ export type RequestHandler = (p: {
18
+ url: string;
19
+ options: SimpleInit;
20
+ }) => Promise<{
21
+ url: string;
22
+ options: SimpleInit;
23
+ }>;
24
+ export declare function createHttpClient(): {
25
+ setHost(url: string): void;
26
+ setHeader(header: Record<string, string>): void;
27
+ addRequestHandler(handler: RequestHandler): void;
28
+ addExceptionHandler(handler: APIExceptionHandler): void;
29
+ readonly host: string;
30
+ readonly headers: Record<string, string>;
31
+ readonly apiExceptionHandlers: APIExceptionHandler[];
32
+ fetch(p: {
33
+ url: string;
34
+ options?: SimpleInit;
35
+ }): Promise<Response | undefined>;
36
+ };
37
+ export {};
38
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,KAAK,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG;IAC/C,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACrC,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;CACjB;AAED,MAAM,MAAM,mBAAmB,GAC7B,CAAC,GAAG,EAAE,qBAAqB,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEhF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,EAAE;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,KAAK,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC;AAkBxH,wBAAgB,gBAAgB;iBAgBf,MAAM;sBACD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;+BACb,cAAc;iCAGZ,mBAAmB;;;;aAQjC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,UAAU,CAAA;KAAE;EAuDvD"}
package/dist/client.js ADDED
@@ -0,0 +1,88 @@
1
+ class FetchException extends Error {
2
+ constructor(ctx) {
3
+ super(`Fetch error: ${ctx.errorType} at ${ctx.timestamp.toISOString()}`);
4
+ this.ctx = ctx;
5
+ this.errorType = "FetchException";
6
+ this.requestUrl = ctx.requestUrl;
7
+ this.response = ctx.response;
8
+ this.options = ctx.options;
9
+ this.timestamp = ctx.timestamp;
10
+ }
11
+ }
12
+ export function createHttpClient() {
13
+ let __host = "";
14
+ let __headers = {};
15
+ let __requestHandlers = [];
16
+ let __apiExceptionHandlers = [];
17
+ async function runHandlers(ctx) {
18
+ if (__apiExceptionHandlers.length === 0)
19
+ throw ctx;
20
+ for (const handler of __apiExceptionHandlers) {
21
+ const { result, isNext } = await handler(ctx);
22
+ if (!isNext)
23
+ return result;
24
+ }
25
+ throw ctx;
26
+ }
27
+ return {
28
+ setHost(url) { __host = url; },
29
+ setHeader(header) { __headers = header; },
30
+ addRequestHandler(handler) {
31
+ __requestHandlers.push(handler);
32
+ },
33
+ addExceptionHandler(handler) {
34
+ __apiExceptionHandlers.push(handler);
35
+ },
36
+ get host() { return __host; },
37
+ get headers() { return __headers; },
38
+ get apiExceptionHandlers() { return __apiExceptionHandlers; },
39
+ async fetch(p) {
40
+ let { url, options = {} } = p;
41
+ const combinedHeaders = {
42
+ ...__headers,
43
+ ...(options.headers ?? {}),
44
+ };
45
+ options = { ...options, headers: combinedHeaders };
46
+ for (const handler of __requestHandlers) {
47
+ const next = await handler({ url, options });
48
+ url = next.url;
49
+ options = next.options;
50
+ }
51
+ const fullUrl = (() => {
52
+ if (url.startsWith('http://') || url.startsWith('https://')) {
53
+ return url;
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
+ })();
63
+ try {
64
+ const res = await fetch(fullUrl, options);
65
+ if (res.ok)
66
+ return res;
67
+ const ctx = new FetchException({
68
+ errorType: "FetchException",
69
+ requestUrl: fullUrl,
70
+ response: res,
71
+ options,
72
+ timestamp: new Date(),
73
+ });
74
+ return await runHandlers(ctx);
75
+ }
76
+ catch (err) {
77
+ const netCtx = new FetchException({
78
+ errorType: "FetchException",
79
+ requestUrl: fullUrl,
80
+ options,
81
+ timestamp: new Date(),
82
+ });
83
+ return await runHandlers(netCtx);
84
+ }
85
+ },
86
+ };
87
+ }
88
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { APIExceptionHandler } from "./client";
2
+ export declare function createRetryHandler(p: {
3
+ timeout?: number;
4
+ retryCount: number;
5
+ }): APIExceptionHandler;
6
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAyB,MAAM,UAAU,CAAC;AAEtE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,mBAAmB,CAuCnG"}
@@ -0,0 +1,32 @@
1
+ export function createRetryHandler(p) {
2
+ return async (ctx) => {
3
+ const status = ctx.response?.status;
4
+ const shouldRetry = ctx.response == null ||
5
+ status === 429 ||
6
+ (status != null && status >= 500 && status <= 599);
7
+ if (!shouldRetry) {
8
+ return { isNext: true };
9
+ }
10
+ const retryUrl = ctx.requestUrl;
11
+ if (!retryUrl) {
12
+ return { isNext: true };
13
+ }
14
+ const delayMs = p.timeout ?? 1000;
15
+ for (let attempt = 1; attempt <= p.retryCount; attempt++) {
16
+ await new Promise((r) => setTimeout(r, delayMs));
17
+ const signal = ctx.options.signal?.aborted
18
+ ? undefined
19
+ : ctx.options.signal;
20
+ try {
21
+ const retryRes = await fetch(retryUrl, { ...ctx.options, signal });
22
+ if (retryRes.ok) {
23
+ return { result: retryRes, isNext: false };
24
+ }
25
+ }
26
+ catch (err) {
27
+ }
28
+ }
29
+ return { isNext: false };
30
+ };
31
+ }
32
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,CAA2C;IAC5E,OAAO,KAAK,EAAE,GAA0B,EAAE,EAAE;QAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;QACpC,MAAM,WAAW,GACf,GAAG,CAAC,QAAQ,IAAI,IAAI;YACpB,MAAM,KAAK,GAAG;YACd,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC;QAErD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC;QAChC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC;QAElC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;YACzD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YAEjD,MAAM,MAAM,GACT,GAAG,CAAC,OAAO,CAAC,MAAkC,EAAE,OAAO;gBACtD,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;YAEzB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBAEnE,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;oBAChB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC7C,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;YACf,CAAC;QACH,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { createHttpClient } from './client';
2
+ export { createRetryHandler } from './handlers';
3
+ export { createAPI } from './spec';
4
+ export { genAPIDefinition } from './spec.generator';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { createHttpClient } from './client';
2
+ export { createRetryHandler } from './handlers';
3
+ export { createAPI } from './spec';
4
+ export { genAPIDefinition } from './spec.generator';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/spec.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import { createHttpClient } from "./client";
3
+ import { ClientAPISpecification } from '@eecho/definition';
4
+ export type APIMapOf<S extends ClientAPISpecification> = {
5
+ [K in S["operationId"]]: (input?: {
6
+ queryParams?: InferIfSchema<S["Request"]["queryParams"]>;
7
+ body?: InferIfSchema<S["Request"]["body"]>;
8
+ }) => Promise<z.infer<S["Response"]["body"]>>;
9
+ };
10
+ type InferIfSchema<T> = T extends z.ZodTypeAny ? z.infer<T> : never;
11
+ export declare function createAPI<S extends ClientAPISpecification>(p: {
12
+ apiSpec: S;
13
+ httpClient: ReturnType<typeof createHttpClient>;
14
+ contentType?: 'application/json' | 'multipart/form-data';
15
+ responseType?: 'json' | 'blob';
16
+ }): APIMapOf<S>;
17
+ export {};
18
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,sBAAsB,IAAI;KACtD,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QAChC,WAAW,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;KAC5C,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;CAC9C,CAAC;AAEF,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAIpE,wBAAgB,SAAS,CAAC,CAAC,SAAS,sBAAsB,EAAE,CAAC,EAAE;IAC7D,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;IAChD,WAAW,CAAC,EAAE,kBAAkB,GAAG,qBAAqB,CAAC;IACvD,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAElC,GAiGM,QAAQ,CAAC,CAAC,CAAC,CACjB"}
@@ -0,0 +1,90 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,92 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.generator.js","sourceRoot":"","sources":["../src/spec.generator.ts"],"names":[],"mappings":"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"}
package/dist/spec.js ADDED
@@ -0,0 +1,91 @@
1
+ import { stringify } from 'qs';
2
+ // Create API function
3
+ // this return a function that can be called with queryParams and body the types are inferred from the APISpecification
4
+ export function createAPI(p) {
5
+ const { apiSpec, httpClient, contentType = "application/json", responseType = "json" } = p;
6
+ const handler = async (input) => {
7
+ if (apiSpec.Request.queryParams && input?.queryParams) {
8
+ const queryParamsParsing = apiSpec.Request.queryParams.safeParse(input.queryParams);
9
+ if (!queryParamsParsing.success) {
10
+ console.error(`API Query Params Validation Error: ${apiSpec.operationId} ${apiSpec.Method} ${apiSpec.APIEndpoint}`, queryParamsParsing.error);
11
+ console.error(`Input Query Params:`, input?.queryParams);
12
+ throw new Error(`API Query Params Validation Error: ${queryParamsParsing.error.message}`);
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(),
57
+ options: {
58
+ method: apiSpec.Method,
59
+ body,
60
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
61
+ },
62
+ });
63
+ // 4) 응답 검증
64
+ let data;
65
+ if (responseType === 'json') {
66
+ data = await res?.json();
67
+ }
68
+ else if (responseType === 'blob') {
69
+ data = await res?.blob();
70
+ }
71
+ 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
+ if (!parsedResult.success) {
81
+ console.error(`API Response Validation Error: ${apiSpec.operationId} ${apiSpec.Method} ${apiSpec.APIEndpoint}`, parsedResult.error);
82
+ console.error(`Response Data:`, data);
83
+ throw new Error(`API Response Validation Error: ${parsedResult.error.message}`);
84
+ }
85
+ return parsedResult.data;
86
+ };
87
+ return {
88
+ [apiSpec.operationId]: handler,
89
+ };
90
+ }
91
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@eecho/api-client",
3
+ "version": "0.0.2",
4
+ "description": "EEcho API client for declarative server applications",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "files": [
9
+ "dist/**/*"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc -p tsconfig.build.json",
13
+ "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
14
+ "prepublishOnly": "npm run clean && npm run build"
15
+ },
16
+ "author": "Cogi",
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/eecho/eechojs.git"
21
+ },
22
+ "dependencies": {
23
+ "@eecho/definition": "^0.0.2",
24
+ "@types/qs": "^6.14.0",
25
+ "qs": "^6.14.0"
26
+ },
27
+ "devDependencies": {
28
+ "ts-node": "^10.9.2",
29
+ "typescript": "^5.0.0"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public",
33
+ "registry": "https://registry.npmjs.org/"
34
+ }
35
+ }