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