@ryneex/api-client 1.0.0-beta.1 → 1.0.0-beta.3

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.
Files changed (3) hide show
  1. package/index.d.ts +43 -10
  2. package/index.js +121 -67
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as axios from 'axios';
2
- import { AxiosRequestConfig, AxiosError, AxiosInstance } from 'axios';
2
+ import { AxiosRequestConfig, AxiosResponse, AxiosError, AxiosInstance } from 'axios';
3
3
  import z, { ZodError } from 'zod';
4
4
  import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
5
5
 
@@ -9,30 +9,43 @@ type ClientPayload<TInput, TVariables> = {} & (unknown extends TInput ? unknown
9
9
  variables: TVariables;
10
10
  });
11
11
  type OptionalPayload<T> = object extends T ? void : T;
12
- type ClientOptions<TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.infer<TOutputSchema>, TInput = z.infer<TInputSchema>, TVariables = z.infer<TVariablesSchema>> = {
12
+ type ClientOptions<TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.output<TOutputSchema>, TInput = z.input<TInputSchema>, TVariables = z.input<TVariablesSchema>> = {
13
13
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
14
14
  path: string | ((payload: ClientPayload<TInput, TVariables>) => string);
15
15
  axiosOptions?: (payload: ClientPayload<TInput, TVariables>) => AxiosRequestConfig;
16
16
  variablesSchema?: TVariablesSchema;
17
17
  inputSchema?: TInputSchema;
18
18
  outputSchema: TOutputSchema;
19
- transform?: (data: z.infer<TOutputSchema>, payload: ClientPayload<TInput, TVariables>) => TOutput;
19
+ transform?: (data: z.output<TOutputSchema>, payload: ClientPayload<TInput, TVariables>) => TOutput;
20
20
  };
21
21
 
22
- type ReactQueryOptions<TOutput, TInput, TVariables> = Omit<UseQueryOptions<TOutput, ZodError<TOutput> | AxiosError>, "queryFn" | "queryKey"> & {
22
+ type ReactQueryOptions<TOutput, TInput, TVariables> = Omit<UseQueryOptions<TOutput, ClientError>, "queryFn" | "queryKey"> & {
23
23
  queryKey?: unknown[];
24
24
  } & (object extends ClientPayload<TInput, TVariables> ? unknown : {
25
25
  data: ClientPayload<TInput, TVariables>;
26
26
  }) & {
27
27
  onSuccess?: (data: TOutput, payload: ClientPayload<TInput, TVariables>) => void;
28
- onError?: (error: ZodError<TOutput> | AxiosError, payload: ClientPayload<TInput, TVariables>) => void;
28
+ onError?: (error: ClientError, payload: ClientPayload<TInput, TVariables>) => void;
29
29
  };
30
- type ReactMutationOptions<TOutput, TInput, TVariables> = Omit<UseMutationOptions<TOutput, ZodError<TOutput> | AxiosError, object extends ClientPayload<TInput, TVariables> ? void : ClientPayload<TInput, TVariables>>, "mutationFn"> & {};
30
+ type ReactMutationOptions<TOutput, TInput, TVariables> = Omit<UseMutationOptions<TOutput, ClientError, object extends ClientPayload<TInput, TVariables> ? void : ClientPayload<TInput, TVariables>>, "mutationFn"> & {};
31
+
32
+ type Ok<T> = {
33
+ success: true;
34
+ data: T;
35
+ response: AxiosResponse;
36
+ };
37
+ type ClientError = ValidationError | AxiosError;
38
+ type Err<E> = {
39
+ success: false;
40
+ error: E;
41
+ };
42
+ type Result<T, E> = Ok<T> | Err<E>;
31
43
 
32
44
  declare function createClient(axios: AxiosInstance): {
33
- create: <TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.core.output<TOutputSchema>, TInput = z.core.output<TInputSchema>, TVariables = z.core.output<TVariablesSchema>>(opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables>) => ((_payload: OptionalPayload<ClientPayload<TInput, TVariables>>) => Promise<axios.AxiosResponse<TOutput, any, {}>>) & {
34
- queryOptions: (_opts: object extends ClientPayload<TInput, TVariables> ? ReactQueryOptions<TOutput, TInput, TVariables> | void : ReactQueryOptions<TOutput, TInput, TVariables>) => UseQueryOptions<TOutput, ZodError<TOutput> | AxiosError>;
35
- mutationOptions: (_opts: ReactMutationOptions<TOutput, TInput, TVariables> | void) => UseMutationOptions<TOutput, ZodError<TOutput> | AxiosError, object extends ClientPayload<TInput, TVariables> ? void : ClientPayload<TInput, TVariables>>;
45
+ create: <TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.core.output<TOutputSchema>, TInput = z.core.input<TInputSchema>, TVariables = z.core.input<TVariablesSchema>>(opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables>) => ((_payload: OptionalPayload<ClientPayload<TInput, TVariables>>) => Promise<Result<TOutput, ClientError>>) & {
46
+ call: (_payload: OptionalPayload<ClientPayload<TInput, TVariables>>) => Promise<Result<TOutput, ClientError>>;
47
+ queryOptions: (_opts: object extends ClientPayload<TInput, TVariables> ? ReactQueryOptions<TOutput, TInput, TVariables> | void : ReactQueryOptions<TOutput, TInput, TVariables>) => UseQueryOptions<TOutput, ClientError>;
48
+ mutationOptions: (_opts: ReactMutationOptions<TOutput, TInput, TVariables> | void) => UseMutationOptions<TOutput, ClientError, object extends ClientPayload<TInput, TVariables> ? void : ClientPayload<TInput, TVariables>>;
36
49
  queryKey: (data?: ClientPayload<TInput, TVariables>) => (string | ClientPayload<TInput, TVariables>)[];
37
50
  mutationKey: () => string[];
38
51
  config: {
@@ -48,4 +61,24 @@ declare function createClient(axios: AxiosInstance): {
48
61
  };
49
62
  };
50
63
 
51
- export { createClient };
64
+ declare function callApi<TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.output<TOutputSchema>, TInput = z.input<TInputSchema>, TVariables = z.input<TVariablesSchema>>(opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables> & {
65
+ axios: AxiosInstance;
66
+ }, data: ClientPayload<TInput, TVariables>): Promise<Result<TOutput, ClientError>>;
67
+ declare function getResponse<TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.output<TOutputSchema>, TInput = z.input<TInputSchema>, TVariables = z.input<TVariablesSchema>>(request: Promise<AxiosResponse<TOutput>>, opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables>, payload: ClientPayload<TInput, TVariables>): Promise<Result<TOutput, ClientError>>;
68
+
69
+ declare const VALIDATION_ERROR_NAMES: {
70
+ readonly INPUT: "InputValidationError";
71
+ readonly VARIABLE: "VariableValidationError";
72
+ readonly OUTPUT: "OutputValidationError";
73
+ };
74
+ type ApiClientErrorProps = {
75
+ type: keyof typeof VALIDATION_ERROR_NAMES;
76
+ issues: z.core.$ZodIssue[];
77
+ };
78
+ declare class ValidationError extends ZodError {
79
+ constructor({ type, issues }: ApiClientErrorProps);
80
+ }
81
+ declare function ok<T>(data: T, response: AxiosResponse): Ok<T>;
82
+ declare function err<E>(error: E): Err<E>;
83
+
84
+ export { type ApiClientErrorProps, type ClientError, type ClientOptions, type ClientPayload, type Err, type Ok, type OptionalPayload, type ReactMutationOptions, type ReactQueryOptions, type Result, VALIDATION_ERROR_NAMES, ValidationError, callApi, createClient, err, getResponse, ok };
package/index.js CHANGED
@@ -1,62 +1,5 @@
1
1
  // src/lib/api-client.ts
2
2
  import "zod";
3
-
4
- // src/lib/call-api.ts
5
- import "zod";
6
- async function callApi(opts, data) {
7
- if (typeof data !== "object")
8
- throw new Error("API SDK: Data must be an object");
9
- if (opts.inputSchema && "input" in data) {
10
- opts.inputSchema.parse(data.input);
11
- }
12
- if (opts.variablesSchema && "variables" in data) {
13
- opts.variablesSchema.parse(data.variables);
14
- }
15
- const axiosOptions = opts.axiosOptions?.(data);
16
- const url = typeof opts.path === "function" ? opts.path(data) : opts.path;
17
- if (opts.method === "GET") {
18
- const response = await opts.axios.get(url, axiosOptions);
19
- return getResponse(opts, data, response);
20
- }
21
- if (opts.method === "POST") {
22
- const response = await opts.axios.post(
23
- url,
24
- axiosOptions?.data,
25
- axiosOptions
26
- );
27
- return getResponse(opts, data, response);
28
- }
29
- if (opts.method === "PUT") {
30
- const response = await opts.axios.put(
31
- url,
32
- axiosOptions?.data,
33
- axiosOptions
34
- );
35
- return getResponse(opts, data, response);
36
- }
37
- if (opts.method === "PATCH") {
38
- const response = await opts.axios.patch(
39
- url,
40
- axiosOptions?.data,
41
- axiosOptions
42
- );
43
- return getResponse(opts, data, response);
44
- }
45
- if (opts.method === "DELETE") {
46
- const response = await opts.axios.delete(url, axiosOptions);
47
- return getResponse(opts, data, response);
48
- }
49
- throw new Error(`API SDK: Unsupported method: ${opts.method}`);
50
- }
51
- function getResponse(opts, payload, response) {
52
- const parsedData = opts.outputSchema.parse(response.data);
53
- if (opts.transform) {
54
- return { ...response, data: opts.transform(parsedData, payload) };
55
- }
56
- return { ...response, data: parsedData };
57
- }
58
-
59
- // src/lib/api-client.ts
60
3
  import "@tanstack/react-query";
61
4
  function createClient(axios) {
62
5
  function create(opts) {
@@ -73,14 +16,13 @@ function createClient(axios) {
73
16
  const data = _data ?? {};
74
17
  return {
75
18
  queryFn: async () => {
76
- try {
77
- const response = await callApi(apiOptionas, data);
78
- options.onSuccess?.(response.data, data);
79
- return response.data;
80
- } catch (error) {
81
- options.onError?.(error, data);
82
- throw error;
19
+ const result = await callApi(apiOptionas, data);
20
+ if (result.success) {
21
+ options.onSuccess?.(result.data, data);
22
+ return result.data;
83
23
  }
24
+ options.onError?.(result.error, data);
25
+ throw result.error;
84
26
  },
85
27
  queryKey: queryKey(data),
86
28
  ...options
@@ -91,14 +33,16 @@ function createClient(axios) {
91
33
  return {
92
34
  mutationFn: async (_data) => {
93
35
  const data = _data ?? {};
94
- const response = await callApi(apiOptionas, data);
95
- return response.data;
36
+ const result = await callApi(apiOptionas, data);
37
+ if (result.success) return result.data;
38
+ throw result.error;
96
39
  },
97
40
  mutationKey: mutationKey(),
98
41
  ...options
99
42
  };
100
43
  };
101
44
  return Object.assign(call, {
45
+ call,
102
46
  queryOptions,
103
47
  mutationOptions,
104
48
  queryKey,
@@ -112,6 +56,116 @@ function createClient(axios) {
112
56
  }
113
57
  return { create };
114
58
  }
59
+
60
+ // src/lib/call-api.ts
61
+ import "zod";
62
+ async function callApi(opts, data) {
63
+ if (typeof data !== "object")
64
+ throw new Error("API_CLIENT_INTERNAL_ERROR: Data must be an object");
65
+ if (opts.inputSchema && "input" in data) {
66
+ const parsedResult = opts.inputSchema.safeParse(data.input);
67
+ if (!parsedResult.success)
68
+ return err(
69
+ new ValidationError({
70
+ type: "INPUT",
71
+ issues: parsedResult.error.issues
72
+ })
73
+ );
74
+ }
75
+ if (opts.variablesSchema && "variables" in data) {
76
+ const parsedResult = opts.variablesSchema.safeParse(data.variables);
77
+ if (!parsedResult.success)
78
+ return err(
79
+ new ValidationError({
80
+ type: "VARIABLE",
81
+ issues: parsedResult.error.issues
82
+ })
83
+ );
84
+ }
85
+ const axiosOptions = opts.axiosOptions?.(data);
86
+ const url = typeof opts.path === "function" ? opts.path(data) : opts.path;
87
+ if (opts.method === "GET") {
88
+ return await getResponse(
89
+ opts.axios.get(url, axiosOptions),
90
+ opts,
91
+ data
92
+ );
93
+ }
94
+ if (opts.method === "POST") {
95
+ return await getResponse(
96
+ opts.axios.post(url, axiosOptions?.data, axiosOptions),
97
+ opts,
98
+ data
99
+ );
100
+ }
101
+ if (opts.method === "PUT") {
102
+ return await getResponse(
103
+ opts.axios.put(url, axiosOptions?.data, axiosOptions),
104
+ opts,
105
+ data
106
+ );
107
+ }
108
+ if (opts.method === "PATCH") {
109
+ return await getResponse(
110
+ opts.axios.patch(url, axiosOptions?.data, axiosOptions),
111
+ opts,
112
+ data
113
+ );
114
+ }
115
+ if (opts.method === "DELETE") {
116
+ return await getResponse(
117
+ opts.axios.delete(url, axiosOptions),
118
+ opts,
119
+ data
120
+ );
121
+ }
122
+ throw new Error(`API SDK: Unsupported method: ${opts.method}`);
123
+ }
124
+ async function getResponse(request, opts, payload) {
125
+ try {
126
+ const response = await request;
127
+ const parsedResult = opts.outputSchema.safeParse(response.data);
128
+ if (!parsedResult.success)
129
+ return err(
130
+ new ValidationError({
131
+ type: "OUTPUT",
132
+ issues: parsedResult.error.issues
133
+ })
134
+ );
135
+ if (opts.transform) {
136
+ return ok(opts.transform(parsedResult.data, payload), response);
137
+ }
138
+ return ok(parsedResult.data, response);
139
+ } catch (error) {
140
+ return err(error);
141
+ }
142
+ }
143
+
144
+ // src/lib/result.ts
145
+ import { ZodError } from "zod";
146
+ var VALIDATION_ERROR_NAMES = {
147
+ INPUT: "InputValidationError",
148
+ VARIABLE: "VariableValidationError",
149
+ OUTPUT: "OutputValidationError"
150
+ };
151
+ var ValidationError = class extends ZodError {
152
+ constructor({ type, issues }) {
153
+ super(issues);
154
+ this.name = VALIDATION_ERROR_NAMES[type];
155
+ }
156
+ };
157
+ function ok(data, response) {
158
+ return { success: true, data, response };
159
+ }
160
+ function err(error) {
161
+ return { success: false, error };
162
+ }
115
163
  export {
116
- createClient
164
+ VALIDATION_ERROR_NAMES,
165
+ ValidationError,
166
+ callApi,
167
+ createClient,
168
+ err,
169
+ getResponse,
170
+ ok
117
171
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@ryneex/api-client",
3
3
  "module": "src/index.ts",
4
4
  "type": "module",
5
- "version": "1.0.0-beta.1",
5
+ "version": "1.0.0-beta.3",
6
6
  "exports": {
7
7
  ".": "./index.js"
8
8
  },