routesync 1.0.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/dist/core.mjs ADDED
@@ -0,0 +1,307 @@
1
+ // packages/core/src/client/HttpClient.ts
2
+ import axios from "axios";
3
+ var HttpClient = class {
4
+ constructor(config) {
5
+ this.client = axios.create({
6
+ baseURL: config.baseURL,
7
+ timeout: config.timeout ?? 1e4,
8
+ headers: {
9
+ "Content-Type": "application/json",
10
+ ...config.headers ?? {}
11
+ }
12
+ });
13
+ if (config.token) {
14
+ this.setToken(config.token);
15
+ }
16
+ this.setupInterceptors();
17
+ }
18
+ setupInterceptors() {
19
+ this.client.interceptors.response.use(
20
+ (response) => response,
21
+ (error) => {
22
+ const message = error.response?.data?.message ?? error.message ?? "Unknown error";
23
+ return Promise.reject({
24
+ success: false,
25
+ message,
26
+ status: error.response?.status,
27
+ errors: error.response?.data?.errors
28
+ });
29
+ }
30
+ );
31
+ }
32
+ setToken(token) {
33
+ this.client.defaults.headers.common["Authorization"] = `Bearer ${token}`;
34
+ }
35
+ removeToken() {
36
+ delete this.client.defaults.headers.common["Authorization"];
37
+ }
38
+ async get(url, config) {
39
+ const response = await this.client.get(url, config);
40
+ return response.data;
41
+ }
42
+ async post(url, body, config) {
43
+ const response = await this.client.post(url, body, config);
44
+ return response.data;
45
+ }
46
+ async put(url, body, config) {
47
+ const response = await this.client.put(url, body, config);
48
+ return response.data;
49
+ }
50
+ async patch(url, body, config) {
51
+ const response = await this.client.patch(url, body, config);
52
+ return response.data;
53
+ }
54
+ async delete(url, config) {
55
+ const response = await this.client.delete(url, config);
56
+ return response.data;
57
+ }
58
+ async upload(url, formData) {
59
+ const response = await this.client.post(url, formData, {
60
+ headers: { "Content-Type": "multipart/form-data" }
61
+ });
62
+ return response.data;
63
+ }
64
+ getInstance() {
65
+ return this.client;
66
+ }
67
+ };
68
+
69
+ // packages/core/src/client/Request.ts
70
+ var Request = class {
71
+ constructor() {
72
+ this._url = "";
73
+ this._method = "GET";
74
+ }
75
+ url(url) {
76
+ this._url = url;
77
+ return this;
78
+ }
79
+ method(method) {
80
+ this._method = method;
81
+ return this;
82
+ }
83
+ body(data) {
84
+ this._body = data;
85
+ return this;
86
+ }
87
+ options(opts) {
88
+ this._options = opts;
89
+ return this;
90
+ }
91
+ build() {
92
+ return {
93
+ url: this._url,
94
+ method: this._method,
95
+ body: this._body,
96
+ options: this._options
97
+ };
98
+ }
99
+ };
100
+
101
+ // packages/core/src/client/Response.ts
102
+ var Response = class {
103
+ constructor(raw) {
104
+ this.raw = raw;
105
+ }
106
+ get data() {
107
+ return this.raw.data;
108
+ }
109
+ get success() {
110
+ return this.raw.success;
111
+ }
112
+ get message() {
113
+ return this.raw.message;
114
+ }
115
+ isOk() {
116
+ return this.raw.success === true;
117
+ }
118
+ unwrap() {
119
+ if (!this.isOk()) {
120
+ throw new Error(this.raw.message ?? "Response failed");
121
+ }
122
+ return this.raw.data;
123
+ }
124
+ };
125
+
126
+ // packages/core/src/client/Interceptor.ts
127
+ var Interceptor = class {
128
+ constructor(client) {
129
+ this.client = client;
130
+ }
131
+ addRequestInterceptor(onFulfilled, onRejected) {
132
+ return this.client.interceptors.request.use(onFulfilled, onRejected);
133
+ }
134
+ addResponseInterceptor(onFulfilled, onRejected) {
135
+ return this.client.interceptors.response.use(onFulfilled, onRejected);
136
+ }
137
+ removeRequestInterceptor(id) {
138
+ this.client.interceptors.request.eject(id);
139
+ }
140
+ removeResponseInterceptor(id) {
141
+ this.client.interceptors.response.eject(id);
142
+ }
143
+ };
144
+
145
+ // packages/core/src/auth/TokenManager.ts
146
+ var _TokenManager = class _TokenManager {
147
+ constructor() {
148
+ this.token = null;
149
+ }
150
+ set(token) {
151
+ this.token = token;
152
+ if (typeof localStorage !== "undefined") {
153
+ localStorage.setItem(_TokenManager.TOKEN_KEY, token);
154
+ }
155
+ }
156
+ get() {
157
+ if (this.token) return this.token;
158
+ if (typeof localStorage !== "undefined") {
159
+ return localStorage.getItem(_TokenManager.TOKEN_KEY);
160
+ }
161
+ return null;
162
+ }
163
+ clear() {
164
+ this.token = null;
165
+ if (typeof localStorage !== "undefined") {
166
+ localStorage.removeItem(_TokenManager.TOKEN_KEY);
167
+ }
168
+ }
169
+ exists() {
170
+ return this.get() !== null;
171
+ }
172
+ };
173
+ _TokenManager.TOKEN_KEY = "routesync_token";
174
+ var TokenManager = _TokenManager;
175
+
176
+ // packages/core/src/auth/AuthMiddleware.ts
177
+ var AuthMiddleware = class {
178
+ constructor(tokenManager) {
179
+ this.tokenManager = tokenManager;
180
+ }
181
+ inject(config) {
182
+ const token = this.tokenManager.get();
183
+ if (token) {
184
+ config.headers = config.headers ?? {};
185
+ config.headers["Authorization"] = `Bearer ${token}`;
186
+ }
187
+ return config;
188
+ }
189
+ getAuthHeader() {
190
+ const token = this.tokenManager.get();
191
+ if (!token) return {};
192
+ return { Authorization: `Bearer ${token}` };
193
+ }
194
+ };
195
+
196
+ // packages/core/src/routing/PathResolver.ts
197
+ var PathResolver = class {
198
+ /**
199
+ * Resolve path params.
200
+ * e.g. resolvePath('/produk/:id', { id: 10 }) => '/produk/10'
201
+ */
202
+ static resolve(path, params) {
203
+ if (!params) return path;
204
+ let resolved = path;
205
+ for (const [key, value] of Object.entries(params)) {
206
+ resolved = resolved.replace(`:${key}`, String(value));
207
+ }
208
+ const unresolved = resolved.match(/:([a-zA-Z_]+)/g);
209
+ if (unresolved) {
210
+ throw new Error(
211
+ `Unresolved path params: ${unresolved.join(", ")}`
212
+ );
213
+ }
214
+ return resolved;
215
+ }
216
+ static extractParams(path) {
217
+ const matches = path.match(/:([a-zA-Z_]+)/g) ?? [];
218
+ return matches.map((m) => m.slice(1));
219
+ }
220
+ static hasParams(path) {
221
+ return /:([a-zA-Z_]+)/.test(path);
222
+ }
223
+ };
224
+
225
+ // packages/core/src/routing/QueryBuilder.ts
226
+ var QueryBuilder = class {
227
+ static build(params) {
228
+ if (!params || Object.keys(params).length === 0) return "";
229
+ const query = Object.entries(params).filter(([, v]) => v !== void 0 && v !== null && v !== "").map(([k, v]) => {
230
+ if (Array.isArray(v)) {
231
+ return v.map((item) => `${encodeURIComponent(k)}[]=${encodeURIComponent(item)}`).join("&");
232
+ }
233
+ return `${encodeURIComponent(k)}=${encodeURIComponent(v)}`;
234
+ }).join("&");
235
+ return query ? `?${query}` : "";
236
+ }
237
+ static append(url, params) {
238
+ const query = this.build(params);
239
+ return url + query;
240
+ }
241
+ };
242
+
243
+ // packages/core/src/errors/ApiError.ts
244
+ var ApiError = class extends Error {
245
+ constructor(message, status, errors) {
246
+ super(message);
247
+ this.success = false;
248
+ this.name = "ApiError";
249
+ this.status = status;
250
+ this.errors = errors;
251
+ }
252
+ isUnauthorized() {
253
+ return this.status === 401;
254
+ }
255
+ isForbidden() {
256
+ return this.status === 403;
257
+ }
258
+ isNotFound() {
259
+ return this.status === 404;
260
+ }
261
+ isValidationError() {
262
+ return this.status === 422;
263
+ }
264
+ isServerError() {
265
+ return (this.status ?? 0) >= 500;
266
+ }
267
+ getFirstError(field) {
268
+ return this.errors?.[field]?.[0];
269
+ }
270
+ getAllErrors() {
271
+ if (!this.errors) return [];
272
+ return Object.values(this.errors).flat();
273
+ }
274
+ };
275
+
276
+ // packages/core/src/errors/ErrorHandler.ts
277
+ var ErrorHandler = class {
278
+ static handle(error) {
279
+ if (error instanceof ApiError) throw error;
280
+ if (error?.response) {
281
+ throw new ApiError(
282
+ error.response.data?.message ?? "Request failed",
283
+ error.response.status,
284
+ error.response.data?.errors
285
+ );
286
+ }
287
+ if (error?.request) {
288
+ throw new ApiError("No response received from server");
289
+ }
290
+ throw new ApiError(error?.message ?? "Unknown error occurred");
291
+ }
292
+ static isApiError(error) {
293
+ return error instanceof ApiError;
294
+ }
295
+ };
296
+ export {
297
+ ApiError,
298
+ AuthMiddleware,
299
+ ErrorHandler,
300
+ HttpClient,
301
+ Interceptor,
302
+ PathResolver,
303
+ QueryBuilder,
304
+ Request,
305
+ Response,
306
+ TokenManager
307
+ };
@@ -0,0 +1,95 @@
1
+ import * as _tanstack_react_query from '@tanstack/react-query';
2
+ import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
3
+
4
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
5
+ type RouteTransform = (value: unknown) => unknown;
6
+ interface RouteTransformMap {
7
+ params?: RouteTransform;
8
+ query?: RouteTransform;
9
+ body?: RouteTransform;
10
+ request?: RouteTransform;
11
+ response?: RouteTransform;
12
+ }
13
+ type RouteMapper = RouteTransform | RouteTransformMap;
14
+ interface RouteParserSchema {
15
+ parse?: RouteTransform;
16
+ safeParse?: RouteTransform;
17
+ }
18
+ interface RouteSchemaMap {
19
+ params?: RouteSchemaValue;
20
+ query?: RouteSchemaValue;
21
+ body?: RouteSchemaValue;
22
+ request?: RouteSchemaValue;
23
+ response?: RouteSchemaValue;
24
+ }
25
+ type RouteSchemaValue = RouteTransform | RouteParserSchema;
26
+ type RouteSchema = RouteSchemaValue | RouteSchemaMap;
27
+ interface RouteDefinition {
28
+ method: HttpMethod;
29
+ path: string;
30
+ auth?: boolean;
31
+ schema?: RouteSchema;
32
+ mapper?: RouteMapper;
33
+ headers?: Record<string, string>;
34
+ cache?: unknown;
35
+ retry?: unknown;
36
+ body?: Record<string, any>;
37
+ params?: Record<string, any>;
38
+ query?: Record<string, any>;
39
+ }
40
+
41
+ type CallOptions = {
42
+ params?: Record<string, any>;
43
+ query?: Record<string, any>;
44
+ body?: Record<string, any>;
45
+ };
46
+ interface EndpointCallable {
47
+ (options?: CallOptions): Promise<any>;
48
+ /** Original RouteDefinition — used by useApiQuery / useApiMutation */
49
+ $def: RouteDefinition;
50
+ /** Stable TanStack query key: [group, action] */
51
+ $key: string[];
52
+ }
53
+
54
+ /**
55
+ * useApiQuery — accepts an endpoint callable directly.
56
+ *
57
+ * Usage:
58
+ * const { data, isLoading } = useApiQuery(api.produk.list)
59
+ * const { data } = useApiQuery(api.produk.detail, { params: { id: 10 } })
60
+ */
61
+ declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: CallOptions, queryOptions?: Omit<UseQueryOptions<T>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<T>, Error>;
62
+
63
+ /**
64
+ * useApiMutation — accepts an endpoint callable directly.
65
+ * Auto-invalidates the endpoint's group on success.
66
+ *
67
+ * Usage:
68
+ * const mutation = useApiMutation(api.cart.addItem)
69
+ * mutation.mutate({ body: { produk_id: 1, qty: 2 } })
70
+ *
71
+ * // Custom invalidation:
72
+ * const mutation = useApiMutation(api.orders.checkout, {
73
+ * invalidate: [api.cart.list, api.orders.index],
74
+ * })
75
+ */
76
+ interface ApiMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData, unknown, TVariables>, 'mutationFn'> {
77
+ /** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
78
+ invalidate?: EndpointCallable[];
79
+ }
80
+ declare function useApiMutation<TData = any, TVariables extends CallOptions = CallOptions>(endpoint: EndpointCallable, options?: ApiMutationOptions<TData, TVariables>): _tanstack_react_query.UseMutationResult<TData, unknown, TVariables, unknown>;
81
+
82
+ /**
83
+ * createHooks — generate typed hooks from an api group.
84
+ *
85
+ * Usage:
86
+ * const cartHooks = createHooks(api.cart)
87
+ * const { useList, useAddItem } = cartHooks
88
+ *
89
+ * // In component:
90
+ * const { data } = useList()
91
+ * const mutation = useAddItem()
92
+ */
93
+ declare function createHooks<T extends Record<string, EndpointCallable>>(group: T): { [K in keyof T as `use${Capitalize<string & K>}`]: T[K] extends EndpointCallable ? T[K]["$def"]["method"] extends "GET" | "DELETE" ? (options?: any, queryOptions?: any) => ReturnType<typeof useApiQuery> : (options?: any) => ReturnType<typeof useApiMutation> : never; };
94
+
95
+ export { type ApiMutationOptions, createHooks, useApiMutation, useApiQuery };
@@ -0,0 +1,95 @@
1
+ import * as _tanstack_react_query from '@tanstack/react-query';
2
+ import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
3
+
4
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
5
+ type RouteTransform = (value: unknown) => unknown;
6
+ interface RouteTransformMap {
7
+ params?: RouteTransform;
8
+ query?: RouteTransform;
9
+ body?: RouteTransform;
10
+ request?: RouteTransform;
11
+ response?: RouteTransform;
12
+ }
13
+ type RouteMapper = RouteTransform | RouteTransformMap;
14
+ interface RouteParserSchema {
15
+ parse?: RouteTransform;
16
+ safeParse?: RouteTransform;
17
+ }
18
+ interface RouteSchemaMap {
19
+ params?: RouteSchemaValue;
20
+ query?: RouteSchemaValue;
21
+ body?: RouteSchemaValue;
22
+ request?: RouteSchemaValue;
23
+ response?: RouteSchemaValue;
24
+ }
25
+ type RouteSchemaValue = RouteTransform | RouteParserSchema;
26
+ type RouteSchema = RouteSchemaValue | RouteSchemaMap;
27
+ interface RouteDefinition {
28
+ method: HttpMethod;
29
+ path: string;
30
+ auth?: boolean;
31
+ schema?: RouteSchema;
32
+ mapper?: RouteMapper;
33
+ headers?: Record<string, string>;
34
+ cache?: unknown;
35
+ retry?: unknown;
36
+ body?: Record<string, any>;
37
+ params?: Record<string, any>;
38
+ query?: Record<string, any>;
39
+ }
40
+
41
+ type CallOptions = {
42
+ params?: Record<string, any>;
43
+ query?: Record<string, any>;
44
+ body?: Record<string, any>;
45
+ };
46
+ interface EndpointCallable {
47
+ (options?: CallOptions): Promise<any>;
48
+ /** Original RouteDefinition — used by useApiQuery / useApiMutation */
49
+ $def: RouteDefinition;
50
+ /** Stable TanStack query key: [group, action] */
51
+ $key: string[];
52
+ }
53
+
54
+ /**
55
+ * useApiQuery — accepts an endpoint callable directly.
56
+ *
57
+ * Usage:
58
+ * const { data, isLoading } = useApiQuery(api.produk.list)
59
+ * const { data } = useApiQuery(api.produk.detail, { params: { id: 10 } })
60
+ */
61
+ declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: CallOptions, queryOptions?: Omit<UseQueryOptions<T>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<T>, Error>;
62
+
63
+ /**
64
+ * useApiMutation — accepts an endpoint callable directly.
65
+ * Auto-invalidates the endpoint's group on success.
66
+ *
67
+ * Usage:
68
+ * const mutation = useApiMutation(api.cart.addItem)
69
+ * mutation.mutate({ body: { produk_id: 1, qty: 2 } })
70
+ *
71
+ * // Custom invalidation:
72
+ * const mutation = useApiMutation(api.orders.checkout, {
73
+ * invalidate: [api.cart.list, api.orders.index],
74
+ * })
75
+ */
76
+ interface ApiMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData, unknown, TVariables>, 'mutationFn'> {
77
+ /** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
78
+ invalidate?: EndpointCallable[];
79
+ }
80
+ declare function useApiMutation<TData = any, TVariables extends CallOptions = CallOptions>(endpoint: EndpointCallable, options?: ApiMutationOptions<TData, TVariables>): _tanstack_react_query.UseMutationResult<TData, unknown, TVariables, unknown>;
81
+
82
+ /**
83
+ * createHooks — generate typed hooks from an api group.
84
+ *
85
+ * Usage:
86
+ * const cartHooks = createHooks(api.cart)
87
+ * const { useList, useAddItem } = cartHooks
88
+ *
89
+ * // In component:
90
+ * const { data } = useList()
91
+ * const mutation = useAddItem()
92
+ */
93
+ declare function createHooks<T extends Record<string, EndpointCallable>>(group: T): { [K in keyof T as `use${Capitalize<string & K>}`]: T[K] extends EndpointCallable ? T[K]["$def"]["method"] extends "GET" | "DELETE" ? (options?: any, queryOptions?: any) => ReturnType<typeof useApiQuery> : (options?: any) => ReturnType<typeof useApiMutation> : never; };
94
+
95
+ export { type ApiMutationOptions, createHooks, useApiMutation, useApiQuery };
package/dist/react.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/react/src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ createHooks: () => createHooks,
24
+ useApiMutation: () => useApiMutation,
25
+ useApiQuery: () => useApiQuery
26
+ });
27
+ module.exports = __toCommonJS(src_exports);
28
+
29
+ // packages/react/src/hooks/useQuery.ts
30
+ var import_react_query = require("@tanstack/react-query");
31
+ function useApiQuery(endpoint, options, queryOptions) {
32
+ const queryKey = options ? [...endpoint.$key, options] : endpoint.$key;
33
+ return (0, import_react_query.useQuery)({
34
+ queryKey,
35
+ queryFn: () => endpoint(options),
36
+ ...queryOptions
37
+ });
38
+ }
39
+
40
+ // packages/react/src/hooks/useMutation.ts
41
+ var import_react_query2 = require("@tanstack/react-query");
42
+ function useApiMutation(endpoint, options) {
43
+ const queryClient = (0, import_react_query2.useQueryClient)();
44
+ const [group] = endpoint.$key;
45
+ return (0, import_react_query2.useMutation)({
46
+ ...options,
47
+ mutationFn: (variables) => endpoint(variables),
48
+ onSuccess: (...args) => {
49
+ queryClient.invalidateQueries({ queryKey: [group] });
50
+ options?.invalidate?.forEach((ep) => {
51
+ queryClient.invalidateQueries({ queryKey: ep.$key });
52
+ });
53
+ options?.onSuccess?.(...args);
54
+ }
55
+ });
56
+ }
57
+
58
+ // packages/react/src/hooks/createHooks.ts
59
+ function createHooks(group) {
60
+ const hooks = {};
61
+ for (const [action, endpoint] of Object.entries(group)) {
62
+ const method = endpoint.$def.method;
63
+ const hookName = `use${action.charAt(0).toUpperCase()}${action.slice(1)}`;
64
+ if (method === "GET" || method === "DELETE") {
65
+ hooks[hookName] = (options, queryOptions) => useApiQuery(endpoint, options, queryOptions);
66
+ } else {
67
+ hooks[hookName] = (mutationOptions) => useApiMutation(endpoint, mutationOptions);
68
+ }
69
+ }
70
+ return hooks;
71
+ }
72
+ // Annotate the CommonJS export names for ESM import in node:
73
+ 0 && (module.exports = {
74
+ createHooks,
75
+ useApiMutation,
76
+ useApiQuery
77
+ });
package/dist/react.mjs ADDED
@@ -0,0 +1,48 @@
1
+ // packages/react/src/hooks/useQuery.ts
2
+ import { useQuery } from "@tanstack/react-query";
3
+ function useApiQuery(endpoint, options, queryOptions) {
4
+ const queryKey = options ? [...endpoint.$key, options] : endpoint.$key;
5
+ return useQuery({
6
+ queryKey,
7
+ queryFn: () => endpoint(options),
8
+ ...queryOptions
9
+ });
10
+ }
11
+
12
+ // packages/react/src/hooks/useMutation.ts
13
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
14
+ function useApiMutation(endpoint, options) {
15
+ const queryClient = useQueryClient();
16
+ const [group] = endpoint.$key;
17
+ return useMutation({
18
+ ...options,
19
+ mutationFn: (variables) => endpoint(variables),
20
+ onSuccess: (...args) => {
21
+ queryClient.invalidateQueries({ queryKey: [group] });
22
+ options?.invalidate?.forEach((ep) => {
23
+ queryClient.invalidateQueries({ queryKey: ep.$key });
24
+ });
25
+ options?.onSuccess?.(...args);
26
+ }
27
+ });
28
+ }
29
+
30
+ // packages/react/src/hooks/createHooks.ts
31
+ function createHooks(group) {
32
+ const hooks = {};
33
+ for (const [action, endpoint] of Object.entries(group)) {
34
+ const method = endpoint.$def.method;
35
+ const hookName = `use${action.charAt(0).toUpperCase()}${action.slice(1)}`;
36
+ if (method === "GET" || method === "DELETE") {
37
+ hooks[hookName] = (options, queryOptions) => useApiQuery(endpoint, options, queryOptions);
38
+ } else {
39
+ hooks[hookName] = (mutationOptions) => useApiMutation(endpoint, mutationOptions);
40
+ }
41
+ }
42
+ return hooks;
43
+ }
44
+ export {
45
+ createHooks,
46
+ useApiMutation,
47
+ useApiQuery
48
+ };