routesync 1.0.20 → 1.0.22

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/cli.js CHANGED
@@ -8461,9 +8461,9 @@ foreach ($routes as $route) {
8461
8461
  $resourceName = null;
8462
8462
  $collection = false;
8463
8463
 
8464
- if (preg_match('/returns+news+([a-zA-Z0-9_]+Resource)/', $methodSource, $matches)) {
8464
+ if (preg_match('/return\\s+new\\s+([a-zA-Z0-9_]+Resource)/', $methodSource, $matches)) {
8465
8465
  $resourceName = $matches[1];
8466
- } elseif (preg_match('/returns+([a-zA-Z0-9_]+Resource)::collection/', $methodSource, $matches)) {
8466
+ } elseif (preg_match('/return\\s+([a-zA-Z0-9_]+Resource)::collection/', $methodSource, $matches)) {
8467
8467
  $resourceName = $matches[1];
8468
8468
  $collection = true;
8469
8469
  }
@@ -8489,7 +8489,7 @@ foreach ($routes as $route) {
8489
8489
 
8490
8490
  if (!$responseMetadata) {
8491
8491
  $docComment = $resReflector->getDocComment();
8492
- if ($docComment && preg_match('/@mixins+([\\\\a-zA-Z0-9_]+)/', $docComment, $mixinMatches)) {
8492
+ if ($docComment && preg_match('/@mixin\\s+([\\\\\\\\a-zA-Z0-9_]+)/', $docComment, $mixinMatches)) {
8493
8493
  $responseMetadata = [
8494
8494
  'type' => class_basename($mixinMatches[1]),
8495
8495
  'collection' => $collection
@@ -8755,6 +8755,7 @@ var SDKGenerator = class {
8755
8755
  if (usesZod) {
8756
8756
  lines.push(`import { z } from 'zod'`);
8757
8757
  lines.push(`import * as Schemas from './schemas'`);
8758
+ lines.push(`export * as Schemas from './schemas'`);
8758
8759
  }
8759
8760
  if (usesTypes) {
8760
8761
  lines.push(`import * as Types from './types'`);
@@ -8766,7 +8767,7 @@ var SDKGenerator = class {
8766
8767
  const TitleCaseAction = route.actionName.charAt(0).toUpperCase() + route.actionName.slice(1);
8767
8768
  const ContractName = `${TitleCaseGroup}${TitleCaseAction}Contract`;
8768
8769
  const pathParams = Array.from(route.runtimePath.matchAll(/:([a-zA-Z0-9_]+)/g)).map((m) => m[1]);
8769
- const paramsType = pathParams.length > 0 ? `{ ${pathParams.map((p) => `${p}: string`).join(", ")} }` : `Record<string, never>`;
8770
+ const paramsType = pathParams.length > 0 ? `{ ${pathParams.map((p) => `${p}: string`).join(", ")} }` : `unknown`;
8770
8771
  const methodActionName = TitleCaseGroup + TitleCaseAction;
8771
8772
  const bodyType = route.schema?.rules && usesZod ? `z.infer<typeof Schemas.${methodActionName}Schema>` : `unknown`;
8772
8773
  const responseType = route.response ? `Types.${route.response.type}${route.response.collection ? "[]" : ""}` : `unknown`;
@@ -8797,7 +8798,7 @@ var SDKGenerator = class {
8797
8798
  lines.push(` body: Schemas.${ContractName.replace("Contract", "Schema")}`);
8798
8799
  lines.push(` },`);
8799
8800
  }
8800
- if (options.zod && route.response) {
8801
+ if (options.zod && route.response && options.models) {
8801
8802
  lines.push(` responseSchema: Schemas.${route.response.type}Schema${route.response.collection ? ".array()" : ""},`);
8802
8803
  }
8803
8804
  lines.push(` }),`);
@@ -9041,7 +9042,7 @@ var HookGenerator = class _HookGenerator {
9041
9042
  const lines = [];
9042
9043
  lines.push(`// Auto-generated by routesync. Do not edit manually.`);
9043
9044
  lines.push(``);
9044
- lines.push(`import { useApiQuery, useApiMutation } from '@routesync/react'`);
9045
+ lines.push(`import { useApiQuery, useApiMutation } from 'routesync/react'`);
9045
9046
  lines.push(`import { api } from './api'`);
9046
9047
  lines.push(``);
9047
9048
  const grouped = buildGeneratedRoutes(manifest.routes);
@@ -9053,7 +9054,8 @@ var HookGenerator = class _HookGenerator {
9053
9054
  const queryKey = `['${group}', '${route.actionName}']`;
9054
9055
  if (method === "GET") {
9055
9056
  lines.push(`/**`);
9056
- lines.push(` * @deprecated Use \`useApiQuery(api.${group}.${route.actionName}, ...args)\` instead.`);
9057
+ lines.push(` * @deprecated Generated hooks will become optional in v2.`);
9058
+ lines.push(` * Prefer \`useApiQuery(api.${group}.${route.actionName}, ...args)\` for future compatibility.`);
9057
9059
  lines.push(` */`);
9058
9060
  lines.push(`export function ${hookName}(...args: Parameters<typeof api.${group}.${route.actionName}>) {`);
9059
9061
  lines.push(` return useApiQuery(api.${group}.${route.actionName}, ...args as any)`);
@@ -9061,7 +9063,8 @@ var HookGenerator = class _HookGenerator {
9061
9063
  lines.push(``);
9062
9064
  } else {
9063
9065
  lines.push(`/**`);
9064
- lines.push(` * @deprecated Use \`useApiMutation(api.${group}.${route.actionName}, options)\` instead.`);
9066
+ lines.push(` * @deprecated Generated hooks will become optional in v2.`);
9067
+ lines.push(` * Prefer \`useApiMutation(api.${group}.${route.actionName}, options)\` for future compatibility.`);
9065
9068
  lines.push(` */`);
9066
9069
  lines.push(`export function ${hookName}() {`);
9067
9070
  lines.push(` return useApiMutation(api.${group}.${route.actionName})`);
@@ -9100,23 +9103,35 @@ var NextActionGenerator = class {
9100
9103
  for (const [groupName, routes] of Object.entries(grouped)) {
9101
9104
  for (const route of routes) {
9102
9105
  const actionName = `${groupName}${toTypeName(route.actionName)}`;
9103
- lines.push(`export async function ${actionName}Action(payload?: Record<string, unknown>) {`);
9106
+ const TitleCaseGroup = groupName.charAt(0).toUpperCase() + groupName.slice(1);
9107
+ const TitleCaseAction = route.actionName.charAt(0).toUpperCase() + route.actionName.slice(1);
9108
+ const ContractName = `${TitleCaseGroup}${TitleCaseAction}Contract`;
9109
+ const hasBody = route.schema && route.schema.rules && Object.keys(route.schema.rules).length > 0;
9110
+ const hasQuery = route.method === "GET";
9111
+ const hasParams = route.path.includes(":");
9112
+ let payloadType = "never";
9113
+ if (hasBody) payloadType = `${ContractName}['request']['body']`;
9114
+ else if (hasQuery) payloadType = `${ContractName}['request']['query']`;
9115
+ else if (hasParams) payloadType = `${ContractName}['request']['params']`;
9116
+ const payloadParam = hasBody || hasQuery || hasParams ? `payload: ${payloadType}` : `payload?: unknown`;
9117
+ lines.push(`export async function ${actionName}Action(${payloadParam}) {`);
9104
9118
  const args = [];
9105
- if (route.path.includes(":")) {
9106
- args.push(`params: payload as any`);
9119
+ if (hasParams) {
9120
+ args.push(`params: payload`);
9107
9121
  }
9108
- if (route.method === "GET") {
9122
+ if (hasQuery) {
9109
9123
  args.push(`query: payload`);
9110
- } else {
9124
+ } else if (hasBody) {
9111
9125
  args.push(`body: payload`);
9112
9126
  }
9113
9127
  if (route.auth) {
9114
9128
  args.push(`headers: await getAuthHeaders()`);
9115
9129
  }
9116
- const apiCall = `await api.${groupName}.${route.actionName}({ ${args.join(", ")} })`;
9130
+ const argsString = args.length > 0 ? `{ ${args.join(", ")} }` : "";
9131
+ const apiCall = `await api.${groupName}.${route.actionName}(${argsString})`;
9117
9132
  lines.push(` try {`);
9118
9133
  lines.push(` const response = ${apiCall}`);
9119
- lines.push(` return { success: true, data: response.data }`);
9134
+ lines.push(` return { success: true, data: response }`);
9120
9135
  lines.push(` } catch (error: unknown) {`);
9121
9136
  lines.push(` return { success: false, error: error instanceof Error ? error.message : String(error) }`);
9122
9137
  lines.push(` }`);
@@ -9124,6 +9139,10 @@ var NextActionGenerator = class {
9124
9139
  lines.push(``);
9125
9140
  }
9126
9141
  }
9142
+ lines.splice(3, 1, `import { api, type ${Object.values(grouped).flatMap((routes) => routes.map((r) => {
9143
+ const g = r.groupName || Object.keys(grouped).find((k) => grouped[k] === routes) || "";
9144
+ return g.charAt(0).toUpperCase() + g.slice(1) + r.actionName.charAt(0).toUpperCase() + r.actionName.slice(1) + "Contract";
9145
+ })).join(", type ")} } from './api'`);
9127
9146
  await import_fs_extra7.default.writeFile(import_path6.default.join(outputDir, "actions.ts"), lines.join("\n"));
9128
9147
  }
9129
9148
  };
package/dist/react.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
2
+ import { UseQueryOptions, InfiniteData, UseInfiniteQueryOptions, UseSuspenseQueryOptions, UseMutationOptions, QueryClient } from '@tanstack/react-query';
3
3
 
4
4
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
5
5
  type RouteTransform = (value: unknown) => unknown;
@@ -80,6 +80,20 @@ declare function useApiQuery<TResponse = unknown, TParams = unknown, TBody = unk
80
80
  ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
81
81
  queryOptions?: Omit<UseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
82
82
  ]): _tanstack_react_query.UseQueryResult<NoInfer<TData>, TError>;
83
+ /**
84
+ * useApiSuspenseQuery — generic wrapper for Suspense-enabled data fetching (TanStack v5).
85
+ */
86
+ declare function useApiSuspenseQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = TResponse>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
87
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
88
+ queryOptions?: Omit<UseSuspenseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
89
+ ]): _tanstack_react_query.UseSuspenseQueryResult<TData, TError>;
90
+ /**
91
+ * useApiInfiniteQuery — framework agnostic paginated fetching.
92
+ */
93
+ declare function useApiInfiniteQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = InfiniteData<TResponse>, TPageParam = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
94
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
95
+ queryOptions: Omit<UseInfiniteQueryOptions<TResponse, TError, TData, any, TPageParam>, 'queryKey' | 'queryFn'>
96
+ ]): _tanstack_react_query.UseInfiniteQueryResult<TData, TError>;
83
97
 
84
98
  /**
85
99
  * useApiMutation — accepts an endpoint callable directly.
@@ -94,11 +108,40 @@ declare function useApiQuery<TResponse = unknown, TParams = unknown, TBody = unk
94
108
  * invalidate: [api.cart.list, api.orders.index],
95
109
  * })
96
110
  */
97
- interface ApiMutationOptions<TData, TError, TVariables> extends Omit<UseMutationOptions<TData, TError, TVariables>, 'mutationFn'> {
111
+ interface ApiMutationOptions<TData, TError, TVariables, TContext = unknown> extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {
98
112
  /** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
99
113
  invalidate?: EndpointCallable<any, any, any>[];
100
114
  }
101
- declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, unknown>;
115
+ declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TContext = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>;
116
+
117
+ /**
118
+ * useApiQueryClient — a typed wrapper over TanStack's QueryClient
119
+ *
120
+ * Provides ergonomic helpers like invalidateEndpoint and prefetchEndpoint
121
+ * with strong typing based on the RouteSync SDK contracts.
122
+ */
123
+ declare function useApiQueryClient(): {
124
+ queryClient: QueryClient;
125
+ /**
126
+ * Invalidate specific queries related to an endpoint.
127
+ * Optionally pass parameters to invalidate a more specific cache entry.
128
+ */
129
+ invalidateEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
130
+ /**
131
+ * Prefetch data for an endpoint into the cache.
132
+ * Useful for SSR, RSC hydration, or proactive prefetching.
133
+ */
134
+ prefetchEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
135
+ /**
136
+ * Manually update the cache for a specific endpoint.
137
+ * Often used for optimistic updates in mutations.
138
+ */
139
+ setEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options: EndpointCallableOptions<TParams, TBody> | undefined, updater: TResponse | ((oldData: TResponse | undefined) => TResponse)) => unknown;
140
+ /**
141
+ * Retrieve the current cached data for a specific endpoint.
142
+ */
143
+ getEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => TResponse | undefined;
144
+ };
102
145
 
103
146
  /**
104
147
  * createHooks — generate typed hooks from an api group.
@@ -113,4 +156,19 @@ declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody =
113
156
  */
114
157
  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; };
115
158
 
116
- export { type ApiMutationOptions, createHooks, useApiMutation, useApiQuery };
159
+ interface UseFormSetError<TFieldValues extends Record<string, any>> {
160
+ (name: keyof TFieldValues | string, error: {
161
+ type: string;
162
+ message?: string;
163
+ }): void;
164
+ }
165
+ /**
166
+ * Parses an unknown error and safely pipes 422 Unprocessable Entity
167
+ * validation messages to react-hook-form's setError.
168
+ *
169
+ * @param error - The error thrown by a RouteSync mutation
170
+ * @param setError - The `setError` function destructured from `useForm()`
171
+ */
172
+ declare function setFormErrors<TFieldValues extends Record<string, any>>(error: unknown, setError: UseFormSetError<TFieldValues>): void;
173
+
174
+ export { type ApiMutationOptions, createHooks, setFormErrors, useApiInfiniteQuery, useApiMutation, useApiQuery, useApiQueryClient, useApiSuspenseQuery };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
2
+ import { UseQueryOptions, InfiniteData, UseInfiniteQueryOptions, UseSuspenseQueryOptions, UseMutationOptions, QueryClient } from '@tanstack/react-query';
3
3
 
4
4
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
5
5
  type RouteTransform = (value: unknown) => unknown;
@@ -80,6 +80,20 @@ declare function useApiQuery<TResponse = unknown, TParams = unknown, TBody = unk
80
80
  ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
81
81
  queryOptions?: Omit<UseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
82
82
  ]): _tanstack_react_query.UseQueryResult<NoInfer<TData>, TError>;
83
+ /**
84
+ * useApiSuspenseQuery — generic wrapper for Suspense-enabled data fetching (TanStack v5).
85
+ */
86
+ declare function useApiSuspenseQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = TResponse>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
87
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
88
+ queryOptions?: Omit<UseSuspenseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
89
+ ]): _tanstack_react_query.UseSuspenseQueryResult<TData, TError>;
90
+ /**
91
+ * useApiInfiniteQuery — framework agnostic paginated fetching.
92
+ */
93
+ declare function useApiInfiniteQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = InfiniteData<TResponse>, TPageParam = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
94
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
95
+ queryOptions: Omit<UseInfiniteQueryOptions<TResponse, TError, TData, any, TPageParam>, 'queryKey' | 'queryFn'>
96
+ ]): _tanstack_react_query.UseInfiniteQueryResult<TData, TError>;
83
97
 
84
98
  /**
85
99
  * useApiMutation — accepts an endpoint callable directly.
@@ -94,11 +108,40 @@ declare function useApiQuery<TResponse = unknown, TParams = unknown, TBody = unk
94
108
  * invalidate: [api.cart.list, api.orders.index],
95
109
  * })
96
110
  */
97
- interface ApiMutationOptions<TData, TError, TVariables> extends Omit<UseMutationOptions<TData, TError, TVariables>, 'mutationFn'> {
111
+ interface ApiMutationOptions<TData, TError, TVariables, TContext = unknown> extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {
98
112
  /** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
99
113
  invalidate?: EndpointCallable<any, any, any>[];
100
114
  }
101
- declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, unknown>;
115
+ declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TContext = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>;
116
+
117
+ /**
118
+ * useApiQueryClient — a typed wrapper over TanStack's QueryClient
119
+ *
120
+ * Provides ergonomic helpers like invalidateEndpoint and prefetchEndpoint
121
+ * with strong typing based on the RouteSync SDK contracts.
122
+ */
123
+ declare function useApiQueryClient(): {
124
+ queryClient: QueryClient;
125
+ /**
126
+ * Invalidate specific queries related to an endpoint.
127
+ * Optionally pass parameters to invalidate a more specific cache entry.
128
+ */
129
+ invalidateEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
130
+ /**
131
+ * Prefetch data for an endpoint into the cache.
132
+ * Useful for SSR, RSC hydration, or proactive prefetching.
133
+ */
134
+ prefetchEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
135
+ /**
136
+ * Manually update the cache for a specific endpoint.
137
+ * Often used for optimistic updates in mutations.
138
+ */
139
+ setEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options: EndpointCallableOptions<TParams, TBody> | undefined, updater: TResponse | ((oldData: TResponse | undefined) => TResponse)) => unknown;
140
+ /**
141
+ * Retrieve the current cached data for a specific endpoint.
142
+ */
143
+ getEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => TResponse | undefined;
144
+ };
102
145
 
103
146
  /**
104
147
  * createHooks — generate typed hooks from an api group.
@@ -113,4 +156,19 @@ declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody =
113
156
  */
114
157
  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; };
115
158
 
116
- export { type ApiMutationOptions, createHooks, useApiMutation, useApiQuery };
159
+ interface UseFormSetError<TFieldValues extends Record<string, any>> {
160
+ (name: keyof TFieldValues | string, error: {
161
+ type: string;
162
+ message?: string;
163
+ }): void;
164
+ }
165
+ /**
166
+ * Parses an unknown error and safely pipes 422 Unprocessable Entity
167
+ * validation messages to react-hook-form's setError.
168
+ *
169
+ * @param error - The error thrown by a RouteSync mutation
170
+ * @param setError - The `setError` function destructured from `useForm()`
171
+ */
172
+ declare function setFormErrors<TFieldValues extends Record<string, any>>(error: unknown, setError: UseFormSetError<TFieldValues>): void;
173
+
174
+ export { type ApiMutationOptions, createHooks, setFormErrors, useApiInfiniteQuery, useApiMutation, useApiQuery, useApiQueryClient, useApiSuspenseQuery };
package/dist/react.js CHANGED
@@ -21,8 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  createHooks: () => createHooks,
24
+ setFormErrors: () => setFormErrors,
25
+ useApiInfiniteQuery: () => useApiInfiniteQuery,
24
26
  useApiMutation: () => useApiMutation,
25
- useApiQuery: () => useApiQuery
27
+ useApiQuery: () => useApiQuery,
28
+ useApiQueryClient: () => useApiQueryClient,
29
+ useApiSuspenseQuery: () => useApiSuspenseQuery
26
30
  });
27
31
  module.exports = __toCommonJS(src_exports);
28
32
 
@@ -38,6 +42,32 @@ function useApiQuery(endpoint, ...args) {
38
42
  ...queryOptions
39
43
  });
40
44
  }
45
+ function useApiSuspenseQuery(endpoint, ...args) {
46
+ const options = args[0];
47
+ const queryOptions = args[1];
48
+ const queryKey = endpoint.$queryKey(options);
49
+ return (0, import_react_query.useSuspenseQuery)({
50
+ queryKey,
51
+ queryFn: () => endpoint(options),
52
+ ...queryOptions
53
+ });
54
+ }
55
+ function useApiInfiniteQuery(endpoint, ...args) {
56
+ const options = args[0];
57
+ const queryOptions = args.length > 1 ? args[1] : args[0];
58
+ const queryKey = endpoint.$queryKey(options);
59
+ return (0, import_react_query.useInfiniteQuery)({
60
+ queryKey,
61
+ queryFn: ({ pageParam }) => {
62
+ const fetchOptions = { ...options };
63
+ if (pageParam !== void 0) {
64
+ fetchOptions.query = { ...fetchOptions.query || {}, page: pageParam };
65
+ }
66
+ return endpoint(fetchOptions);
67
+ },
68
+ ...queryOptions
69
+ });
70
+ }
41
71
 
42
72
  // packages/react/src/hooks/useMutation.ts
43
73
  var import_react_query2 = require("@tanstack/react-query");
@@ -57,6 +87,47 @@ function useApiMutation(endpoint, options) {
57
87
  });
58
88
  }
59
89
 
90
+ // packages/react/src/hooks/useQueryClient.ts
91
+ var import_react_query3 = require("@tanstack/react-query");
92
+ function useApiQueryClient() {
93
+ const queryClient = (0, import_react_query3.useQueryClient)();
94
+ return {
95
+ queryClient,
96
+ /**
97
+ * Invalidate specific queries related to an endpoint.
98
+ * Optionally pass parameters to invalidate a more specific cache entry.
99
+ */
100
+ invalidateEndpoint: (endpoint, options) => {
101
+ return queryClient.invalidateQueries({
102
+ queryKey: endpoint.$queryKey(options)
103
+ });
104
+ },
105
+ /**
106
+ * Prefetch data for an endpoint into the cache.
107
+ * Useful for SSR, RSC hydration, or proactive prefetching.
108
+ */
109
+ prefetchEndpoint: (endpoint, options) => {
110
+ return queryClient.prefetchQuery({
111
+ queryKey: endpoint.$queryKey(options),
112
+ queryFn: () => endpoint(options)
113
+ });
114
+ },
115
+ /**
116
+ * Manually update the cache for a specific endpoint.
117
+ * Often used for optimistic updates in mutations.
118
+ */
119
+ setEndpointData: (endpoint, options, updater) => {
120
+ return queryClient.setQueryData(endpoint.$queryKey(options), updater);
121
+ },
122
+ /**
123
+ * Retrieve the current cached data for a specific endpoint.
124
+ */
125
+ getEndpointData: (endpoint, options) => {
126
+ return queryClient.getQueryData(endpoint.$queryKey(options));
127
+ }
128
+ };
129
+ }
130
+
60
131
  // packages/react/src/hooks/createHooks.ts
61
132
  function createHooks(group) {
62
133
  const hooks = {};
@@ -71,9 +142,30 @@ function createHooks(group) {
71
142
  }
72
143
  return hooks;
73
144
  }
145
+
146
+ // packages/react/src/utils/form.ts
147
+ function setFormErrors(error, setError) {
148
+ if (error && typeof error === "object" && "status" in error && error.status === 422) {
149
+ const apiError = error;
150
+ const errors = apiError.errors;
151
+ if (errors && typeof errors === "object") {
152
+ for (const [field, messages] of Object.entries(errors)) {
153
+ if (Array.isArray(messages) && messages.length > 0) {
154
+ setError(field, { type: "server", message: String(messages[0]) });
155
+ } else if (typeof messages === "string") {
156
+ setError(field, { type: "server", message: messages });
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
74
162
  // Annotate the CommonJS export names for ESM import in node:
75
163
  0 && (module.exports = {
76
164
  createHooks,
165
+ setFormErrors,
166
+ useApiInfiniteQuery,
77
167
  useApiMutation,
78
- useApiQuery
168
+ useApiQuery,
169
+ useApiQueryClient,
170
+ useApiSuspenseQuery
79
171
  });
package/dist/react.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // packages/react/src/hooks/useQuery.ts
2
- import { useQuery } from "@tanstack/react-query";
2
+ import { useQuery, useSuspenseQuery, useInfiniteQuery } from "@tanstack/react-query";
3
3
  function useApiQuery(endpoint, ...args) {
4
4
  const options = args[0];
5
5
  const queryOptions = args[1];
@@ -10,6 +10,32 @@ function useApiQuery(endpoint, ...args) {
10
10
  ...queryOptions
11
11
  });
12
12
  }
13
+ function useApiSuspenseQuery(endpoint, ...args) {
14
+ const options = args[0];
15
+ const queryOptions = args[1];
16
+ const queryKey = endpoint.$queryKey(options);
17
+ return useSuspenseQuery({
18
+ queryKey,
19
+ queryFn: () => endpoint(options),
20
+ ...queryOptions
21
+ });
22
+ }
23
+ function useApiInfiniteQuery(endpoint, ...args) {
24
+ const options = args[0];
25
+ const queryOptions = args.length > 1 ? args[1] : args[0];
26
+ const queryKey = endpoint.$queryKey(options);
27
+ return useInfiniteQuery({
28
+ queryKey,
29
+ queryFn: ({ pageParam }) => {
30
+ const fetchOptions = { ...options };
31
+ if (pageParam !== void 0) {
32
+ fetchOptions.query = { ...fetchOptions.query || {}, page: pageParam };
33
+ }
34
+ return endpoint(fetchOptions);
35
+ },
36
+ ...queryOptions
37
+ });
38
+ }
13
39
 
14
40
  // packages/react/src/hooks/useMutation.ts
15
41
  import { useMutation, useQueryClient } from "@tanstack/react-query";
@@ -29,6 +55,47 @@ function useApiMutation(endpoint, options) {
29
55
  });
30
56
  }
31
57
 
58
+ // packages/react/src/hooks/useQueryClient.ts
59
+ import { useQueryClient as useQueryClient2 } from "@tanstack/react-query";
60
+ function useApiQueryClient() {
61
+ const queryClient = useQueryClient2();
62
+ return {
63
+ queryClient,
64
+ /**
65
+ * Invalidate specific queries related to an endpoint.
66
+ * Optionally pass parameters to invalidate a more specific cache entry.
67
+ */
68
+ invalidateEndpoint: (endpoint, options) => {
69
+ return queryClient.invalidateQueries({
70
+ queryKey: endpoint.$queryKey(options)
71
+ });
72
+ },
73
+ /**
74
+ * Prefetch data for an endpoint into the cache.
75
+ * Useful for SSR, RSC hydration, or proactive prefetching.
76
+ */
77
+ prefetchEndpoint: (endpoint, options) => {
78
+ return queryClient.prefetchQuery({
79
+ queryKey: endpoint.$queryKey(options),
80
+ queryFn: () => endpoint(options)
81
+ });
82
+ },
83
+ /**
84
+ * Manually update the cache for a specific endpoint.
85
+ * Often used for optimistic updates in mutations.
86
+ */
87
+ setEndpointData: (endpoint, options, updater) => {
88
+ return queryClient.setQueryData(endpoint.$queryKey(options), updater);
89
+ },
90
+ /**
91
+ * Retrieve the current cached data for a specific endpoint.
92
+ */
93
+ getEndpointData: (endpoint, options) => {
94
+ return queryClient.getQueryData(endpoint.$queryKey(options));
95
+ }
96
+ };
97
+ }
98
+
32
99
  // packages/react/src/hooks/createHooks.ts
33
100
  function createHooks(group) {
34
101
  const hooks = {};
@@ -43,8 +110,29 @@ function createHooks(group) {
43
110
  }
44
111
  return hooks;
45
112
  }
113
+
114
+ // packages/react/src/utils/form.ts
115
+ function setFormErrors(error, setError) {
116
+ if (error && typeof error === "object" && "status" in error && error.status === 422) {
117
+ const apiError = error;
118
+ const errors = apiError.errors;
119
+ if (errors && typeof errors === "object") {
120
+ for (const [field, messages] of Object.entries(errors)) {
121
+ if (Array.isArray(messages) && messages.length > 0) {
122
+ setError(field, { type: "server", message: String(messages[0]) });
123
+ } else if (typeof messages === "string") {
124
+ setError(field, { type: "server", message: messages });
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
46
130
  export {
47
131
  createHooks,
132
+ setFormErrors,
133
+ useApiInfiniteQuery,
48
134
  useApiMutation,
49
- useApiQuery
135
+ useApiQuery,
136
+ useApiQueryClient,
137
+ useApiSuspenseQuery
50
138
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routesync",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "Laravel routes to typed frontend SDKs.",
5
5
  "main": "./dist/sdk.js",
6
6
  "module": "./dist/sdk.mjs",