@ventlio/tanstack-query 0.5.14 → 0.6.1

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.
@@ -1,7 +1,8 @@
1
- import { useQuery } from '@tanstack/react-query';
2
- import { useState, useEffect } from 'react';
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import { useStore } from '../../node_modules/@tanstack/react-store/dist/esm/index.js';
3
+ import { useState, useMemo, useEffect } from 'react';
3
4
  import 'url-search-params-polyfill';
4
- import '../config/bootStore.js';
5
+ import { bootStore } from '../config/bootStore.js';
5
6
  import { useEnvironmentVariables } from '../config/useEnvironmentVariables.js';
6
7
  import '../stores/useBaseUrlStore.js';
7
8
  import { useHeaderStore } from '../stores/useHeaderStore.js';
@@ -12,82 +13,65 @@ import { HttpMethod } from '../request/request.enum.js';
12
13
 
13
14
  const useDeleteRequest = (deleteOptions) => {
14
15
  const { baseUrl, headers } = deleteOptions ?? {};
15
- const [requestPath, setRequestPath] = useState('');
16
- const [options, setOptions] = useState();
17
- // const { middleware: middlewares } = useStore(bootStore);
18
- // const [middleware] = middlewares as unknown as MiddlewareFunction[];
16
+ const { headerProvider } = useStore(bootStore);
19
17
  const [requestPayload, setRequestPayload] = useState();
20
- const isFutureQueriesPaused = usePauseFutureRequests((state) => state.isFutureQueriesPaused);
18
+ const isFutureMutationsPaused = usePauseFutureRequests((state) => state.isFutureMutationsPaused);
21
19
  const { API_URL, TIMEOUT } = useEnvironmentVariables();
22
- const globalHeaders = useHeaderStore((state) => state.headers);
23
- const sendRequest = async (res, rej, queryKey) => {
24
- const [url] = queryKey;
25
- const requestUrl = (url ?? requestPath);
20
+ const storeHeaders = useHeaderStore((state) => state.headers);
21
+ // Get headers from both the store and the headerProvider (if configured)
22
+ const globalHeaders = useMemo(() => {
23
+ const providerHeaders = headerProvider ? headerProvider() : undefined;
24
+ return { ...providerHeaders, ...storeHeaders };
25
+ }, [storeHeaders, headerProvider]);
26
+ const sendRequest = async (path) => {
26
27
  const requestOptions = {
27
- path: requestUrl,
28
+ path,
28
29
  headers: { ...globalHeaders, ...headers },
29
30
  baseURL: baseUrl ?? API_URL,
30
31
  method: HttpMethod.DELETE,
31
32
  timeout: TIMEOUT,
32
33
  };
33
- // let deleteResponse: IRequestError | IRequestSuccess<TResponse>;
34
- // if (middleware) {
35
- // // perform global middleware
36
- // deleteResponse = await middleware(
37
- // async (middlewareOptions) =>
38
- // await makeRequest<TResponse>(
39
- // middlewareOptions ? { ...requestOptions, ...middlewareOptions } : requestOptions
40
- // ),
41
- // {
42
- // path: requestUrl,
43
- // baseUrl: baseUrl ?? API_URL,
44
- // }
45
- // );
46
- // } else {
47
34
  const deleteResponse = await makeRequest(requestOptions);
48
- // }
49
35
  if (deleteResponse.status) {
50
- res(deleteResponse);
36
+ return deleteResponse;
51
37
  }
52
38
  else {
53
- rej(deleteResponse);
39
+ throw deleteResponse;
54
40
  }
55
41
  };
56
- const query = useQuery({
57
- queryKey: [requestPath, {}],
58
- queryFn: ({ queryKey }) => new Promise((res, rej) => sendRequest(res, rej, queryKey)),
59
- enabled: false,
60
- ...options,
42
+ // Use mutation instead of query for DELETE operations
43
+ const mutation = useMutation({
44
+ mutationFn: async ({ path }) => sendRequest(path),
61
45
  });
62
- const updatedPathAsync = async (link) => {
63
- return setRequestPath(link);
64
- };
65
- const setOptionsAsync = async (fetchOptions) => {
66
- return setOptions(fetchOptions);
67
- };
68
- const destroy = async (link, internalDeleteOptions) => {
69
- if (!isFutureQueriesPaused) {
70
- // set enabled to be true for every delete
71
- internalDeleteOptions = internalDeleteOptions
72
- ? { ...internalDeleteOptions, queryKey: [link, {}], enabled: true }
73
- : { queryKey: [link, {}], enabled: true };
74
- await setOptionsAsync(internalDeleteOptions);
75
- await updatedPathAsync(link);
76
- return query.data;
46
+ /**
47
+ * Perform a DELETE request to the specified path
48
+ * @param path - The API path to send the DELETE request to
49
+ * @param options - Optional mutation options (onSuccess, onError, etc.)
50
+ */
51
+ const destroy = async (path, options) => {
52
+ if (!isFutureMutationsPaused) {
53
+ return mutation.mutateAsync({ path }, options);
77
54
  }
78
55
  else {
79
- setRequestPayload({ link, internalDeleteOptions });
56
+ setRequestPayload({ path, options });
80
57
  return undefined;
81
58
  }
82
59
  };
60
+ // Resume paused requests when mutations are unpaused
83
61
  useEffect(() => {
84
- if (!isFutureQueriesPaused && requestPayload) {
85
- destroy(requestPayload.link, requestPayload.internalDeleteOptions);
62
+ if (!isFutureMutationsPaused && requestPayload) {
63
+ destroy(requestPayload.path, requestPayload.options);
86
64
  setRequestPayload(undefined);
87
65
  }
88
66
  // eslint-disable-next-line react-hooks/exhaustive-deps
89
- }, [isFutureQueriesPaused]);
90
- return { destroy, ...query, isLoading: query.isLoading || isFutureQueriesPaused };
67
+ }, [isFutureMutationsPaused]);
68
+ return {
69
+ destroy,
70
+ ...mutation,
71
+ isLoading: mutation.isPending || isFutureMutationsPaused,
72
+ // For backward compatibility - mutations don't have initial loading state
73
+ isInitialLoading: false,
74
+ };
91
75
  };
92
76
 
93
77
  export { useDeleteRequest };
@@ -1 +1 @@
1
- {"version":3,"file":"useDeleteRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"useDeleteRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,5 +1,5 @@
1
1
  import { useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
2
- import { useState, useMemo, useEffect, startTransition } from 'react';
2
+ import { useMemo, useState, useEffect, startTransition } from 'react';
3
3
  import 'url-search-params-polyfill';
4
4
  import { bootStore } from '../config/bootStore.js';
5
5
  import { useEnvironmentVariables } from '../config/useEnvironmentVariables.js';
@@ -13,10 +13,15 @@ import '../request/request.enum.js';
13
13
 
14
14
  const useGetInfiniteRequest = ({ path, load = false, queryOptions, keyTracker, baseUrl, headers, }) => {
15
15
  const { API_URL, TIMEOUT } = useEnvironmentVariables();
16
- const globalHeaders = useHeaderStore((state) => state.headers);
16
+ const { headerProvider } = useStore(bootStore);
17
+ const storeHeaders = useHeaderStore((state) => state.headers);
18
+ // Get headers from both the store and the headerProvider (if configured)
19
+ const globalHeaders = useMemo(() => {
20
+ const providerHeaders = headerProvider ? headerProvider() : undefined;
21
+ return { ...providerHeaders, ...storeHeaders };
22
+ }, [storeHeaders, headerProvider]);
17
23
  const [requestPath, setRequestPath] = useState(path);
18
24
  const [options, setOptions] = useState(queryOptions);
19
- useStore(bootStore);
20
25
  const [requestPayload, setRequestPayload] = useState();
21
26
  const isFutureQueriesPaused = usePauseFutureRequests((state) => state.isFutureQueriesPaused);
22
27
  let queryClient = useQueryClient();
@@ -1 +1 @@
1
- {"version":3,"file":"useGetInfiniteRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"useGetInfiniteRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,5 +1,5 @@
1
1
  import { useQueryClient, useQuery } from '@tanstack/react-query';
2
- import { useState, useMemo, useEffect, startTransition } from 'react';
2
+ import { useState, useMemo, useCallback, useEffect } from 'react';
3
3
  import 'url-search-params-polyfill';
4
4
  import { bootStore } from '../config/bootStore.js';
5
5
  import { useEnvironmentVariables } from '../config/useEnvironmentVariables.js';
@@ -16,24 +16,28 @@ import '../request/request.enum.js';
16
16
  */
17
17
  const useGetRequest = ({ path, load = false, queryOptions, keyTracker, baseUrl, headers, paginationConfig, }) => {
18
18
  const [requestPath, setRequestPath] = useState(path);
19
- const [options, setOptions] = useState(queryOptions);
20
19
  const [page, setPage] = useState(1);
21
20
  const { API_URL, TIMEOUT } = useEnvironmentVariables();
22
- const { middleware, pagination: globalPaginationConfig } = useStore(bootStore);
23
- const globalHeaders = useHeaderStore((state) => state.headers);
24
- const [requestPayload, setRequestPayload] = useState();
21
+ const { middleware, pagination: globalPaginationConfig, headerProvider } = useStore(bootStore);
22
+ const storeHeaders = useHeaderStore((state) => state.headers);
23
+ // Get headers from both the store and the headerProvider (if configured)
24
+ // headerProvider allows reading from cookies/localStorage synchronously
25
+ const globalHeaders = useMemo(() => {
26
+ const providerHeaders = headerProvider ? headerProvider() : undefined;
27
+ // Merge: store headers take precedence over provider headers
28
+ return { ...providerHeaders, ...storeHeaders };
29
+ }, [storeHeaders, headerProvider]);
25
30
  const isFutureQueriesPaused = usePauseFutureRequests((state) => state.isFutureQueriesPaused);
26
- let queryClient = useQueryClient();
27
- // eslint-disable-next-line react-hooks/exhaustive-deps
28
- queryClient = useMemo(() => queryClient, []);
31
+ const queryClient = useQueryClient();
29
32
  // Merge global and local pagination config
30
33
  const pagination = useMemo(() => ({
31
34
  ...globalPaginationConfig,
32
35
  ...paginationConfig,
33
36
  }), [globalPaginationConfig, paginationConfig]);
34
- const sendRequest = async (res, rej, queryKey) => {
35
- const [url] = queryKey;
36
- const requestUrl = (url ?? requestPath);
37
+ /**
38
+ * Core request function that makes the actual HTTP request
39
+ */
40
+ const executeRequest = useCallback(async (requestUrl) => {
37
41
  const requestOptions = {
38
42
  path: requestUrl,
39
43
  headers: { ...globalHeaders, ...headers },
@@ -60,26 +64,32 @@ const useGetRequest = ({ path, load = false, queryOptions, keyTracker, baseUrl,
60
64
  getResponse = await makeRequest(requestOptions);
61
65
  }
62
66
  if (getResponse.status) {
63
- res(getResponse);
67
+ return getResponse;
64
68
  }
65
69
  else {
66
- rej(getResponse);
70
+ throw getResponse;
67
71
  }
68
- };
72
+ }, [globalHeaders, headers, baseUrl, API_URL, TIMEOUT, middleware]);
73
+ // The declarative query - only runs when load is true
69
74
  const query = useQuery({
70
75
  queryKey: [requestPath, {}],
71
- queryFn: ({ queryKey }) => new Promise((res, rej) => sendRequest(res, rej, queryKey)),
72
- enabled: load && !isFutureQueriesPaused,
73
- ...options,
76
+ queryFn: async ({ queryKey }) => {
77
+ const [url] = queryKey;
78
+ return executeRequest(url);
79
+ },
80
+ // Only enable when load is explicitly true AND queries aren't paused
81
+ enabled: load === true && !isFutureQueriesPaused,
82
+ ...queryOptions,
74
83
  });
84
+ // Update request path when prop changes
75
85
  useEffect(() => {
76
- if (path) {
86
+ if (path && path !== requestPath) {
77
87
  setRequestPath(path);
78
88
  }
79
- }, [path]);
89
+ }, [path, requestPath]);
90
+ // Track query key for external reference
80
91
  useEffect(() => {
81
92
  if (keyTracker) {
82
- // set expiration time for the tracker
83
93
  queryClient.setQueryDefaults([keyTracker], {
84
94
  staleTime: Infinity,
85
95
  });
@@ -89,8 +99,7 @@ const useGetRequest = ({ path, load = false, queryOptions, keyTracker, baseUrl,
89
99
  /**
90
100
  * Extract pagination data from response using configured extractor
91
101
  */
92
- const getPaginationData = (response) => {
93
- // Use the configured pagination extractor or fall back to default
102
+ const getPaginationData = useCallback((response) => {
94
103
  const extractPagination = pagination.extractPagination ||
95
104
  ((res) => {
96
105
  if ('pagination' in res.data) {
@@ -99,90 +108,90 @@ const useGetRequest = ({ path, load = false, queryOptions, keyTracker, baseUrl,
99
108
  return undefined;
100
109
  });
101
110
  return extractPagination(response);
102
- };
111
+ }, [pagination.extractPagination]);
112
+ /**
113
+ * Construct a pagination URL using the configured builder
114
+ */
115
+ const constructPaginationLink = useCallback((link, pageNumber) => {
116
+ const buildPaginationUrl = pagination.buildPaginationUrl ||
117
+ ((url, targetPage) => {
118
+ const [pathname, queryString] = url.split('?');
119
+ const queryParams = new URLSearchParams(queryString || '');
120
+ const pageParamName = pagination.pageParamName || 'page';
121
+ queryParams.set(pageParamName, String(targetPage));
122
+ return pathname + '?' + queryParams.toString();
123
+ });
124
+ return buildPaginationUrl(link, pageNumber);
125
+ }, [pagination.buildPaginationUrl, pagination.pageParamName]);
103
126
  /**
104
127
  * Navigate to the next page if available
105
128
  */
106
- const nextPage = () => {
107
- // The linter thinks query.data is always falsy, but we know it can be defined after a successful query
108
- // Let's restructure to avoid the conditional
109
- const paginationData = query.data && getPaginationData(query.data);
129
+ const nextPage = useCallback(() => {
130
+ const data = query.data;
131
+ if (!data)
132
+ return;
133
+ const paginationData = getPaginationData(data);
110
134
  if (!paginationData)
111
135
  return;
112
136
  if (paginationData.next_page !== paginationData.current_page &&
113
137
  paginationData.next_page > paginationData.current_page) {
114
- setRequestPath(constructPaginationLink(requestPath, paginationData.next_page));
138
+ const newPath = constructPaginationLink(requestPath, paginationData.next_page);
139
+ setRequestPath(newPath);
140
+ setPage(paginationData.next_page);
115
141
  }
116
- };
142
+ }, [query.data, getPaginationData, constructPaginationLink, requestPath]);
117
143
  /**
118
144
  * Navigate to the previous page if available
119
145
  */
120
- const prevPage = () => {
121
- // The linter thinks query.data is always falsy, but we know it can be defined after a successful query
122
- // Let's restructure to avoid the conditional
123
- const paginationData = query.data && getPaginationData(query.data);
146
+ const prevPage = useCallback(() => {
147
+ const data = query.data;
148
+ if (!data)
149
+ return;
150
+ const paginationData = getPaginationData(data);
124
151
  if (!paginationData)
125
152
  return;
126
153
  if (paginationData.previous_page !== paginationData.current_page &&
127
154
  paginationData.previous_page < paginationData.current_page) {
128
- setRequestPath(constructPaginationLink(requestPath, paginationData.previous_page));
155
+ const newPath = constructPaginationLink(requestPath, paginationData.previous_page);
156
+ setRequestPath(newPath);
157
+ setPage(paginationData.previous_page);
129
158
  }
130
- };
159
+ }, [query.data, getPaginationData, constructPaginationLink, requestPath]);
131
160
  /**
132
- * Construct a pagination URL using the configured builder
161
+ * Navigate to a specific page
133
162
  */
134
- const constructPaginationLink = (link, pageNumber) => {
135
- // Use the configured pagination URL builder or fall back to default
136
- const buildPaginationUrl = pagination.buildPaginationUrl ||
137
- ((url, page) => {
138
- const [pathname, queryString] = url.split('?');
139
- const queryParams = new URLSearchParams(queryString || '');
140
- const pageParamName = pagination.pageParamName || 'page';
141
- const oldPage = Number(queryParams.get(pageParamName));
142
- queryParams.set(pageParamName, String(page));
143
- const newUrl = pathname + '?' + queryParams.toString();
144
- // only update page when pagination number changed
145
- if (oldPage !== pageNumber) {
146
- setPage(pageNumber);
147
- }
148
- return newUrl;
149
- });
150
- return buildPaginationUrl(link, pageNumber);
151
- };
163
+ const gotoPage = useCallback((pageNumber) => {
164
+ const newPath = constructPaginationLink(requestPath, pageNumber);
165
+ setRequestPath(newPath);
166
+ setPage(pageNumber);
167
+ }, [constructPaginationLink, requestPath]);
152
168
  /**
153
- * Navigate to a specific page
169
+ * Imperative GET request - fetches data from a dynamic URL
170
+ * Uses queryClient.fetchQuery for proper caching and deduplication
171
+ *
172
+ * @param url - The URL to fetch from
173
+ * @param fetchOptions - Optional query options (staleTime, gcTime, etc.)
174
+ * @returns Promise resolving to the response data
154
175
  */
155
- const gotoPage = (pageNumber) => {
156
- setRequestPath(constructPaginationLink(requestPath, pageNumber));
157
- };
158
- const updatedPathAsync = async (link) => {
159
- startTransition(() => {
160
- setRequestPath(link);
161
- });
162
- };
163
- const setOptionsAsync = async (fetchOptions) => {
164
- startTransition(() => {
165
- setOptions(fetchOptions);
166
- });
167
- };
168
- const get = async (link, fetchOptions) => {
169
- if (!isFutureQueriesPaused) {
170
- await setOptionsAsync(fetchOptions);
171
- await updatedPathAsync(link);
172
- return query.data;
173
- }
174
- else {
175
- setRequestPayload({ link, fetchOptions });
176
- return undefined;
177
- }
178
- };
179
- useEffect(() => {
180
- if (!isFutureQueriesPaused && requestPayload) {
181
- get(requestPayload.link, requestPayload.fetchOptions);
182
- setRequestPayload(undefined);
176
+ const get = useCallback(async (url, fetchOptions) => {
177
+ if (isFutureQueriesPaused) {
178
+ throw new Error('Queries are currently paused');
183
179
  }
184
- // eslint-disable-next-line react-hooks/exhaustive-deps
185
- }, [isFutureQueriesPaused]);
180
+ // Use fetchQuery for imperative fetching - this properly handles caching
181
+ const result = await queryClient.fetchQuery({
182
+ queryKey: [url, {}],
183
+ queryFn: () => executeRequest(url),
184
+ staleTime: fetchOptions?.staleTime,
185
+ gcTime: fetchOptions?.gcTime,
186
+ });
187
+ return result;
188
+ }, [queryClient, executeRequest, isFutureQueriesPaused]);
189
+ /**
190
+ * Refetch the current query with the existing path
191
+ */
192
+ const refetch = useCallback(() => {
193
+ return query.refetch();
194
+ }, [query]);
186
195
  return {
187
196
  ...query,
188
197
  isLoading: query.isLoading || isFutureQueriesPaused,
@@ -192,10 +201,11 @@ const useGetRequest = ({ path, load = false, queryOptions, keyTracker, baseUrl,
192
201
  get,
193
202
  gotoPage,
194
203
  page,
204
+ refetch,
195
205
  queryKey: [requestPath, {}],
196
- // Add pagination data accessor - restructured to avoid linter error
197
- getPaginationData: function () {
198
- return query.data ? getPaginationData(query.data) : undefined;
206
+ getPaginationData: () => {
207
+ const data = query.data;
208
+ return data ? getPaginationData(data) : undefined;
199
209
  },
200
210
  };
201
211
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useGetRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"useGetRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,13 +1,12 @@
1
1
  import { useMutation } from '@tanstack/react-query';
2
2
  import { useStore } from '../../node_modules/@tanstack/react-store/dist/esm/index.js';
3
- import { useState, useEffect } from 'react';
3
+ import { useMemo, useState, useEffect } from 'react';
4
4
  import 'url-search-params-polyfill';
5
5
  import { bootStore } from '../config/bootStore.js';
6
6
  import { useEnvironmentVariables } from '../config/useEnvironmentVariables.js';
7
7
  import '../stores/useBaseUrlStore.js';
8
8
  import { useHeaderStore } from '../stores/useHeaderStore.js';
9
9
  import { usePauseFutureRequests } from '../stores/usePauseFutureRequests.js';
10
- import { scrollToTop } from '../helpers/scrollToTop.js';
11
10
  import { useUploadProgress } from '../hooks/useUploadProgress.js';
12
11
  import 'axios';
13
12
  import { makeRequest } from '../request/make-request.js';
@@ -16,10 +15,15 @@ import { HttpMethod } from '../request/request.enum.js';
16
15
  const usePatchRequest = ({ path, baseUrl, headers }) => {
17
16
  const { API_URL, TIMEOUT } = useEnvironmentVariables();
18
17
  const { uploadProgressPercent, onUploadProgress } = useUploadProgress();
19
- const globalHeaders = useHeaderStore((state) => state.headers);
18
+ const { headerProvider } = useStore(bootStore);
19
+ const storeHeaders = useHeaderStore((state) => state.headers);
20
+ // Get headers from both the store and the headerProvider (if configured)
21
+ const globalHeaders = useMemo(() => {
22
+ const providerHeaders = headerProvider ? headerProvider() : undefined;
23
+ return { ...providerHeaders, ...storeHeaders };
24
+ }, [storeHeaders, headerProvider]);
20
25
  const [requestPayload, setRequestPayload] = useState();
21
26
  const isFutureMutationsPaused = usePauseFutureRequests((state) => state.isFutureMutationsPaused);
22
- const { context } = useStore(bootStore);
23
27
  const sendRequest = async (res, rej, data) => {
24
28
  // get request headers
25
29
  const requestOptions = {
@@ -50,17 +54,9 @@ const usePatchRequest = ({ path, baseUrl, headers }) => {
50
54
  const patchResponse = await makeRequest(requestOptions);
51
55
  // }
52
56
  if (patchResponse.status) {
53
- // scroll to top after success
54
- if (context !== 'app') {
55
- scrollToTop();
56
- }
57
57
  res(patchResponse);
58
58
  }
59
59
  else {
60
- // scroll to top after error
61
- if (context !== 'app') {
62
- scrollToTop();
63
- }
64
60
  rej(patchResponse);
65
61
  }
66
62
  };
@@ -1 +1 @@
1
- {"version":3,"file":"usePatchRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"usePatchRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -7,8 +7,7 @@ import { useHeaderStore } from '../stores/useHeaderStore.js';
7
7
  import { usePauseFutureRequests } from '../stores/usePauseFutureRequests.js';
8
8
  import { useReactNativeEnv } from '../config/useReactNativeEnv.js';
9
9
  import { useStore } from '../../node_modules/@tanstack/react-store/dist/esm/index.js';
10
- import { useState, useEffect } from 'react';
11
- import { scrollToTop } from '../helpers/scrollToTop.js';
10
+ import { useMemo, useState, useEffect } from 'react';
12
11
  import { useUploadProgress } from '../hooks/useUploadProgress.js';
13
12
  import 'axios';
14
13
  import { makeRequest } from '../request/make-request.js';
@@ -16,8 +15,15 @@ import { HttpMethod } from '../request/request.enum.js';
16
15
 
17
16
  const usePostRequest = ({ path, isFormData = false, baseUrl, headers, fileSelectors, }) => {
18
17
  const { API_URL, TIMEOUT } = useEnvironmentVariables();
19
- const { context } = useStore(bootStore);
20
- const globalHeaders = useHeaderStore((state) => state.headers);
18
+ const { headerProvider } = useStore(bootStore);
19
+ const storeHeaders = useHeaderStore((state) => state.headers);
20
+ // Get headers from both the store and the headerProvider (if configured)
21
+ // headerProvider allows reading from cookies/localStorage synchronously
22
+ const globalHeaders = useMemo(() => {
23
+ const providerHeaders = headerProvider ? headerProvider() : undefined;
24
+ // Merge: store headers take precedence over provider headers
25
+ return { ...providerHeaders, ...storeHeaders };
26
+ }, [storeHeaders, headerProvider]);
21
27
  const { isApp } = useReactNativeEnv();
22
28
  const { uploadProgressPercent, onUploadProgress } = useUploadProgress();
23
29
  const [requestPayload, setRequestPayload] = useState();
@@ -59,17 +65,9 @@ const usePostRequest = ({ path, isFormData = false, baseUrl, headers, fileSelect
59
65
  const postResponse = await makeRequest(requestOptions);
60
66
  // }
61
67
  if (postResponse.status) {
62
- // scroll to top after success
63
- if (context !== 'app') {
64
- scrollToTop();
65
- }
66
68
  res(postResponse);
67
69
  }
68
70
  else {
69
- // scroll to top after error
70
- if (context !== 'app') {
71
- scrollToTop();
72
- }
73
71
  rej(postResponse);
74
72
  }
75
73
  };
@@ -1 +1 @@
1
- {"version":3,"file":"usePostRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"usePostRequest.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,6 +1,6 @@
1
1
  import type { AxiosProgressEvent, RawAxiosRequestHeaders } from 'axios';
2
- import type { AppFileConfig, HttpMethod, IMakeRequest, IRequestError, IRequestSuccess } from '../request';
3
2
  import type { IPagination } from '../queries';
3
+ import type { AppFileConfig, HttpMethod, IMakeRequest, IRequestError, IRequestSuccess } from '../request';
4
4
  export type MiddlewareFunction<T = any> = (context: MiddlewareContext<T>, next: MiddlewareNext<T>) => Promise<IRequestError | IRequestSuccess<T>>;
5
5
  export interface MiddlewareContext<T = any> {
6
6
  baseUrl: string;
@@ -26,6 +26,22 @@ export interface BootstrapConfig {
26
26
  modelConfig?: BootstrapModelConfig;
27
27
  middleware?: MiddlewareFunction[] | LegacyMiddlewareFunction;
28
28
  pagination?: PaginationConfig;
29
+ /**
30
+ * Optional function to provide headers synchronously.
31
+ * This is called on every request to get the current headers.
32
+ * Use this to read auth tokens from cookies or other persistent storage.
33
+ * The returned headers are merged with headers from the header store.
34
+ *
35
+ * Example:
36
+ * ```
37
+ * headerProvider: () => {
38
+ * const token = getCookie('authToken');
39
+ * const spaceId = getCookie('spaceId');
40
+ * return token ? { Authorization: `Bearer ${token}`, } : undefined;
41
+ * }
42
+ * ```
43
+ */
44
+ headerProvider?: () => QueryHeaders;
29
45
  }
30
46
  export interface PaginationConfig {
31
47
  extractPagination?: <T>(response: IRequestSuccess<T>) => IPagination | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ventlio/tanstack-query",
3
- "version": "0.5.14",
3
+ "version": "0.6.1",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "contributors": [
@@ -1,3 +1,2 @@
1
1
  export { result } from './result';
2
- export * from './scrollToTop';
3
2
  export * from './timeFuncs';