enlace 0.0.1-beta.13 → 0.0.1-beta.14

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/README.md CHANGED
@@ -11,7 +11,7 @@ npm install enlace
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { createEnlaceHookReact } from "enlace/hook";
14
+ import { enlaceHookReact } from "enlace/hook";
15
15
  import { Endpoint } from "enlace";
16
16
 
17
17
  // Define your API error type
@@ -30,7 +30,7 @@ type ApiSchema = {
30
30
  };
31
31
 
32
32
  // Pass global error type as second generic
33
- const useAPI = createEnlaceHookReact<ApiSchema, ApiError>(
33
+ const useAPI = enlaceHookReact<ApiSchema, ApiError>(
34
34
  "https://api.example.com"
35
35
  );
36
36
  ```
@@ -41,13 +41,13 @@ Defining a schema is **recommended** for full type safety, but **optional**. You
41
41
 
42
42
  ```typescript
43
43
  // Without schema (untyped, but still works!)
44
- const useAPI = createEnlaceHookReact("https://api.example.com");
44
+ const useAPI = enlaceHookReact("https://api.example.com");
45
45
  const { data } = useAPI((api) => api.any.path.you.want.get());
46
46
  ```
47
47
 
48
48
  ```typescript
49
49
  // With schema (recommended for type safety)
50
- const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com");
50
+ const useAPI = enlaceHookReact<ApiSchema>("https://api.example.com");
51
51
  ```
52
52
 
53
53
  ### Schema Structure
@@ -77,7 +77,7 @@ type ApiSchema = {
77
77
  };
78
78
 
79
79
  // Pass global error type - applies to all endpoints
80
- const api = createEnlace<ApiSchema, ApiError>("https://api.example.com");
80
+ const api = enlace<ApiSchema, ApiError>("https://api.example.com");
81
81
 
82
82
  // Usage
83
83
  api.users.get(); // GET /users
@@ -197,9 +197,9 @@ type ApiSchema = {
197
197
  type ApiError = { message: string; code: number };
198
198
 
199
199
  // Second generic sets default error type for all endpoints
200
- const api = createEnlace<ApiSchema, ApiError>("https://api.example.com");
201
- // const useAPI = createEnlaceHookReact<ApiSchema, ApiError>("...");
202
- // const useAPI = createEnlaceHookNext<ApiSchema, ApiError>("...");
200
+ const api = enlace<ApiSchema, ApiError>("https://api.example.com");
201
+ // const useAPI = enlaceHookReact<ApiSchema, ApiError>("...");
202
+ // const useAPI = enlaceHookNext<ApiSchema, ApiError>("...");
203
203
  ```
204
204
 
205
205
  ## React Hooks
@@ -269,6 +269,74 @@ function Post({ id }: { id: number }) {
269
269
  }
270
270
  ```
271
271
 
272
+ ### Polling
273
+
274
+ Automatically refetch data at intervals using the `pollingInterval` option. Polling uses sequential timing — the interval starts counting **after** the previous request completes, preventing request pile-up:
275
+
276
+ ```typescript
277
+ function Notifications() {
278
+ const { data } = useAPI(
279
+ (api) => api.notifications.get(),
280
+ { pollingInterval: 5000 } // Refetch every 5 seconds after previous request completes
281
+ );
282
+
283
+ return <NotificationList notifications={data} />;
284
+ }
285
+ ```
286
+
287
+ **Behavior:**
288
+
289
+ - Polling starts after the initial fetch completes
290
+ - Next poll is scheduled only after the current request finishes (success or error)
291
+ - Continues polling even on errors (retry behavior)
292
+ - Stops when component unmounts or `enabled` becomes `false`
293
+ - Resets when component remounts
294
+
295
+ **Dynamic polling with function:**
296
+
297
+ Use a function to conditionally poll based on the response data or error:
298
+
299
+ ```typescript
300
+ function OrderStatus({ orderId }: { orderId: string }) {
301
+ const { data } = useAPI(
302
+ (api) => api.orders[orderId].get(),
303
+ {
304
+ // Poll every 2s while pending, stop when completed
305
+ pollingInterval: (order) => order?.status === "pending" ? 2000 : false,
306
+ }
307
+ );
308
+
309
+ return <div>Status: {data?.status}</div>;
310
+ }
311
+ ```
312
+
313
+ The function receives `(data, error)` and should return:
314
+ - `number`: Interval in milliseconds
315
+ - `false`: Stop polling
316
+
317
+ ```typescript
318
+ // Poll faster when there's an error (retry), slower otherwise
319
+ { pollingInterval: (data, error) => error ? 1000 : 10000 }
320
+
321
+ // Stop polling once data meets a condition
322
+ { pollingInterval: (order) => order?.status === "completed" ? false : 3000 }
323
+ ```
324
+
325
+ **Combined with conditional fetching:**
326
+
327
+ ```typescript
328
+ function OrderStatus({ orderId }: { orderId: string | undefined }) {
329
+ const { data } = useAPI(
330
+ (api) => api.orders[orderId!].get(),
331
+ {
332
+ enabled: !!orderId,
333
+ pollingInterval: 10000, // Poll every 10 seconds
334
+ }
335
+ );
336
+ // Polling only runs when orderId is defined
337
+ }
338
+ ```
339
+
272
340
  ### Request Deduplication
273
341
 
274
342
  Multiple components requesting the same data will share a single network request:
@@ -428,7 +496,7 @@ trigger({ body: { title: "New" } });
428
496
  Control how long cached data is considered fresh:
429
497
 
430
498
  ```typescript
431
- const useAPI = createEnlaceHookReact<ApiSchema>(
499
+ const useAPI = enlaceHookReact<ApiSchema>(
432
500
  "https://api.example.com",
433
501
  {},
434
502
  {
@@ -459,7 +527,7 @@ trigger({
459
527
  ### Disable Auto-Revalidation
460
528
 
461
529
  ```typescript
462
- const useAPI = createEnlaceHookReact<ApiSchema>(
530
+ const useAPI = enlaceHookReact<ApiSchema>(
463
531
  "https://api.example.com",
464
532
  {},
465
533
  {
@@ -472,7 +540,7 @@ const useAPI = createEnlaceHookReact<ApiSchema>(
472
540
  ## Hook Options
473
541
 
474
542
  ```typescript
475
- const useAPI = createEnlaceHookReact<ApiSchema>(
543
+ const useAPI = enlaceHookReact<ApiSchema>(
476
544
  "https://api.example.com",
477
545
  {
478
546
  // Default fetch options
@@ -493,17 +561,17 @@ Headers can be provided as a static value, sync function, or async function. Thi
493
561
 
494
562
  ```typescript
495
563
  // Static headers
496
- const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
564
+ const useAPI = enlaceHookReact<ApiSchema>("https://api.example.com", {
497
565
  headers: { Authorization: "Bearer token" },
498
566
  });
499
567
 
500
568
  // Sync function
501
- const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
569
+ const useAPI = enlaceHookReact<ApiSchema>("https://api.example.com", {
502
570
  headers: () => ({ Authorization: `Bearer ${getToken()}` }),
503
571
  });
504
572
 
505
573
  // Async function
506
- const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
574
+ const useAPI = enlaceHookReact<ApiSchema>("https://api.example.com", {
507
575
  headers: async () => {
508
576
  const token = await getTokenFromStorage();
509
577
  return { Authorization: `Bearer ${token}` };
@@ -529,7 +597,7 @@ const { data } = useAPI((api) =>
529
597
  You can set up global `onSuccess` and `onError` callbacks that are called for every request:
530
598
 
531
599
  ```typescript
532
- const useAPI = createEnlaceHookReact<ApiSchema>(
600
+ const useAPI = enlaceHookReact<ApiSchema>(
533
601
  "https://api.example.com",
534
602
  {
535
603
  headers: { Authorization: "Bearer token" },
@@ -585,7 +653,18 @@ const result = useAPI((api) => api.posts.get());
585
653
  // With options
586
654
  const result = useAPI(
587
655
  (api) => api.posts.get(),
588
- { enabled: true } // Skip fetching when false
656
+ {
657
+ enabled: true, // Skip fetching when false
658
+ pollingInterval: 5000 // Refetch every 5s after previous request completes
659
+ }
660
+ );
661
+
662
+ // With dynamic polling
663
+ const result = useAPI(
664
+ (api) => api.orders[id].get(),
665
+ {
666
+ pollingInterval: (order) => order?.status === "pending" ? 2000 : false
667
+ }
589
668
  );
590
669
 
591
670
  type UseEnlaceQueryResult<TData, TError> = {
@@ -608,6 +687,18 @@ type UseEnlaceSelectorResult<TMethod> = {
608
687
  };
609
688
  ```
610
689
 
690
+ ### Query Options
691
+
692
+ ```typescript
693
+ type UseEnlaceQueryOptions<TData, TError> = {
694
+ enabled?: boolean; // Skip fetching when false (default: true)
695
+ pollingInterval?: // Refetch interval after request completes
696
+ | number // Fixed interval in ms
697
+ | false // Disable polling
698
+ | ((data: TData | undefined, error: TError | undefined) => number | false); // Dynamic
699
+ };
700
+ ```
701
+
611
702
  ### Request Options
612
703
 
613
704
  ```typescript
@@ -628,14 +719,14 @@ type RequestOptions = {
628
719
 
629
720
  ### Server Components
630
721
 
631
- Use `createEnlaceNext` from `enlace` for server components:
722
+ Use `enlaceNext` from `enlace` for server components:
632
723
 
633
724
  ```typescript
634
- import { createEnlaceNext } from "enlace";
725
+ import { enlaceNext } from "enlace";
635
726
 
636
727
  type ApiError = { message: string };
637
728
 
638
- const api = createEnlaceNext<ApiSchema, ApiError>("https://api.example.com", {}, {
729
+ const api = enlaceNext<ApiSchema, ApiError>("https://api.example.com", {}, {
639
730
  autoGenerateTags: true,
640
731
  });
641
732
 
@@ -650,16 +741,16 @@ export default async function Page() {
650
741
 
651
742
  ### Client Components
652
743
 
653
- Use `createEnlaceHookNext` from `enlace/hook` for client components:
744
+ Use `enlaceHookNext` from `enlace/hook` for client components:
654
745
 
655
746
  ```typescript
656
747
  "use client";
657
748
 
658
- import { createEnlaceHookNext } from "enlace/hook";
749
+ import { enlaceHookNext } from "enlace/hook";
659
750
 
660
751
  type ApiError = { message: string };
661
752
 
662
- const useAPI = createEnlaceHookNext<ApiSchema, ApiError>(
753
+ const useAPI = enlaceHookNext<ApiSchema, ApiError>(
663
754
  "https://api.example.com"
664
755
  );
665
756
  ```
@@ -686,12 +777,12 @@ export async function revalidateAction(tags: string[], paths: string[]) {
686
777
 
687
778
  ```typescript
688
779
  // useAPI.ts
689
- import { createEnlaceHookNext } from "enlace/hook";
780
+ import { enlaceHookNext } from "enlace/hook";
690
781
  import { revalidateAction } from "./actions";
691
782
 
692
783
  type ApiError = { message: string };
693
784
 
694
- const useAPI = createEnlaceHookNext<ApiSchema, ApiError>(
785
+ const useAPI = enlaceHookNext<ApiSchema, ApiError>(
695
786
  "/api",
696
787
  {},
697
788
  {
@@ -721,7 +812,7 @@ function CreatePost() {
721
812
  For projects that primarily use client-side rendering with minimal SSR, you can disable server-side revalidation by default:
722
813
 
723
814
  ```typescript
724
- const useAPI = createEnlaceHookNext<ApiSchema, ApiError>(
815
+ const useAPI = enlaceHookNext<ApiSchema, ApiError>(
725
816
  "/api",
726
817
  {},
727
818
  {
@@ -767,26 +858,26 @@ Works with Next.js API routes:
767
858
 
768
859
  ```typescript
769
860
  // Client component calling /api/posts
770
- const useAPI = createEnlaceHookNext<ApiSchema, ApiError>("/api");
861
+ const useAPI = enlaceHookNext<ApiSchema, ApiError>("/api");
771
862
  ```
772
863
 
773
864
  ---
774
865
 
775
866
  ## API Reference
776
867
 
777
- ### `createEnlaceHookReact<TSchema, TDefaultError>(baseUrl, options?, hookOptions?)`
868
+ ### `enlaceHookReact<TSchema, TDefaultError>(baseUrl, options?, hookOptions?)`
778
869
 
779
870
  Creates a React hook for making API calls.
780
871
 
781
- ### `createEnlaceHookNext<TSchema, TDefaultError>(baseUrl, options?, hookOptions?)`
872
+ ### `enlaceHookNext<TSchema, TDefaultError>(baseUrl, options?, hookOptions?)`
782
873
 
783
874
  Creates a Next.js hook with server revalidation support.
784
875
 
785
- ### `createEnlace<TSchema, TDefaultError>(baseUrl, options?, callbacks?)`
876
+ ### `enlace<TSchema, TDefaultError>(baseUrl, options?, callbacks?)`
786
877
 
787
878
  Creates a typed API client (non-hook, for direct calls or server components).
788
879
 
789
- ### `createEnlaceNext<TSchema, TDefaultError>(baseUrl, options?, nextOptions?)`
880
+ ### `enlaceNext<TSchema, TDefaultError>(baseUrl, options?, nextOptions?)`
790
881
 
791
882
  Creates a Next.js typed API client with caching support.
792
883
 
@@ -19,14 +19,40 @@ type ReactRequestOptionsBase = {
19
19
  */
20
20
  params?: Record<string, string | number>;
21
21
  };
22
+ /** Polling interval value: milliseconds to wait, or false to stop polling */
23
+ type PollingIntervalValue = number | false;
24
+ /** Function that determines polling interval based on current data/error state */
25
+ type PollingIntervalFn<TData, TError> = (data: TData | undefined, error: TError | undefined) => PollingIntervalValue;
26
+ /** Polling interval option: static value or dynamic function */
27
+ type PollingInterval<TData = unknown, TError = unknown> = PollingIntervalValue | PollingIntervalFn<TData, TError>;
22
28
  /** Options for query mode hooks */
23
- type UseEnlaceQueryOptions = {
29
+ type UseEnlaceQueryOptions<TData = unknown, TError = unknown> = {
24
30
  /**
25
31
  * Whether the query should execute.
26
32
  * Set to false to skip fetching (useful when ID is "new" or undefined).
27
33
  * @default true
28
34
  */
29
35
  enabled?: boolean;
36
+ /**
37
+ * Polling interval in milliseconds, or a function that returns the interval.
38
+ * When set, the query will refetch after this interval AFTER the previous request completes.
39
+ * Uses sequential polling (setTimeout after fetch completes), not interval-based.
40
+ *
41
+ * Can be:
42
+ * - `number`: Fixed interval in milliseconds
43
+ * - `false`: Disable polling
44
+ * - `(data, error) => number | false`: Dynamic interval based on response
45
+ *
46
+ * @example
47
+ * // Fixed interval
48
+ * { pollingInterval: 5000 }
49
+ *
50
+ * // Conditional polling based on data
51
+ * { pollingInterval: (order) => order?.status === 'pending' ? 2000 : false }
52
+ *
53
+ * @default undefined (no polling)
54
+ */
55
+ pollingInterval?: PollingInterval<TData, TError>;
30
56
  };
31
57
  type ApiClient<TSchema, TDefaultError = unknown, TOptions = ReactRequestOptionsBase> = unknown extends TSchema ? WildcardClient<TOptions> : EnlaceClient<TSchema, TDefaultError, TOptions>;
32
58
  type QueryFn<TSchema, TData, TError, TDefaultError = unknown, TOptions = ReactRequestOptionsBase> = (api: ApiClient<TSchema, TDefaultError, TOptions>) => Promise<EnlaceResponse<TData, TError>>;
@@ -64,7 +90,7 @@ type UseEnlaceSelectorResult<TMethod> = {
64
90
  loading: boolean;
65
91
  fetching: boolean;
66
92
  } & HookResponseState<ExtractData<TMethod>, ExtractError<TMethod>>;
67
- /** Options for createEnlaceHookReact factory */
93
+ /** Options for enlaceHookReact factory */
68
94
  type EnlaceHookOptions = {
69
95
  /**
70
96
  * Auto-generate cache tags from URL path for GET requests.
@@ -81,10 +107,10 @@ type EnlaceHookOptions = {
81
107
  /** Callback called on error responses (HTTP errors or network failures) */
82
108
  onError?: (payload: EnlaceErrorCallbackPayload<unknown>) => void;
83
109
  };
84
- /** Hook type returned by createEnlaceHookReact */
110
+ /** Hook type returned by enlaceHookReact */
85
111
  type EnlaceHook<TSchema, TDefaultError = unknown> = {
86
112
  <TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: SelectorFn<TSchema, TMethod, TDefaultError>): UseEnlaceSelectorResult<TMethod>;
87
- <TData, TError>(queryFn: QueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
113
+ <TData, TError>(queryFn: QueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions<TData, TError>): UseEnlaceQueryResult<TData, TError>;
88
114
  };
89
115
 
90
116
  /**
@@ -92,7 +118,7 @@ type EnlaceHook<TSchema, TDefaultError = unknown> = {
92
118
  * Called at module level to create a reusable hook.
93
119
  *
94
120
  * @example
95
- * const useAPI = createEnlaceHookReact<ApiSchema>('https://api.com');
121
+ * const useAPI = enlaceHookReact<ApiSchema>('https://api.com');
96
122
  *
97
123
  * // Query mode - auto-fetch (auto-tracks changes, no deps array needed)
98
124
  * const { loading, data, error } = useAPI((api) => api.posts.get({ query: { userId } }));
@@ -101,7 +127,7 @@ type EnlaceHook<TSchema, TDefaultError = unknown> = {
101
127
  * const { trigger, loading, data, error } = useAPI((api) => api.posts.delete);
102
128
  * onClick={() => trigger({ body: { id: 1 } })}
103
129
  */
104
- declare function createEnlaceHookReact<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema, TDefaultError>;
130
+ declare function enlaceHookReact<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema, TDefaultError>;
105
131
 
106
132
  /**
107
133
  * Handler function called after successful mutations to trigger server-side revalidation.
@@ -109,14 +135,14 @@ declare function createEnlaceHookReact<TSchema = unknown, TDefaultError = unknow
109
135
  * @param paths - URL paths to revalidate
110
136
  */
111
137
  type ServerRevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
112
- /** Next.js-specific options (third argument for createEnlaceNext) */
138
+ /** Next.js-specific options (third argument for enlaceNext) */
113
139
  type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
114
140
  /**
115
141
  * Handler called after successful mutations to trigger server-side revalidation.
116
142
  * Receives auto-generated or manually specified tags and paths.
117
143
  * @example
118
144
  * ```ts
119
- * createEnlaceNext("http://localhost:3000/api/", {}, {
145
+ * enlaceNext("http://localhost:3000/api/", {}, {
120
146
  * serverRevalidator: (tags, paths) => revalidateServerAction(tags, paths)
121
147
  * });
122
148
  * ```
@@ -130,7 +156,7 @@ type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateT
130
156
  */
131
157
  skipServerRevalidation?: boolean;
132
158
  };
133
- /** Next.js hook options (third argument for createEnlaceHookNext) - extends React's EnlaceHookOptions */
159
+ /** Next.js hook options (third argument for enlaceHookNext) - extends React's EnlaceHookOptions */
134
160
  type NextHookOptions = EnlaceHookOptions & Pick<NextOptions, "serverRevalidator" | "skipServerRevalidation">;
135
161
  /** Per-request options for Next.js fetch - extends React's base options */
136
162
  type NextRequestOptionsBase = ReactRequestOptionsBase & {
@@ -151,10 +177,10 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
151
177
  };
152
178
  type NextQueryFn<TSchema, TData, TError, TDefaultError = unknown> = QueryFn<TSchema, TData, TError, TDefaultError, NextRequestOptionsBase>;
153
179
  type NextSelectorFn<TSchema, TMethod, TDefaultError = unknown> = SelectorFn<TSchema, TMethod, TDefaultError, NextRequestOptionsBase>;
154
- /** Hook type returned by createEnlaceHookNext */
180
+ /** Hook type returned by enlaceHookNext */
155
181
  type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
156
182
  <TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: NextSelectorFn<TSchema, TMethod, TDefaultError>): UseEnlaceSelectorResult<TMethod>;
157
- <TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
183
+ <TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions<TData, TError>): UseEnlaceQueryResult<TData, TError>;
158
184
  };
159
185
 
160
186
  /**
@@ -162,7 +188,7 @@ type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
162
188
  * Uses Next.js-specific features like serverRevalidator for server-side cache invalidation.
163
189
  *
164
190
  * @example
165
- * const useAPI = createEnlaceHookNext<ApiSchema>('https://api.com', {}, {
191
+ * const useAPI = enlaceHookNext<ApiSchema>('https://api.com', {}, {
166
192
  * serverRevalidator: (tags) => revalidateTagsAction(tags),
167
193
  * staleTime: 5000,
168
194
  * });
@@ -173,6 +199,6 @@ type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
173
199
  * // Selector mode - trigger for mutations
174
200
  * const { trigger } = useAPI((api) => api.posts.delete);
175
201
  */
176
- declare function createEnlaceHookNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema, TDefaultError>;
202
+ declare function enlaceHookNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema, TDefaultError>;
177
203
 
178
- export { type ApiClient, type EnlaceHook, type EnlaceHookOptions, HTTP_METHODS, type HookState, type NextEnlaceHook, type NextHookOptions, type QueryFn, type ReactRequestOptionsBase, type SelectorFn, type TrackedCall, type UseEnlaceQueryOptions, type UseEnlaceQueryResult, type UseEnlaceSelectorResult, createEnlaceHookNext, createEnlaceHookReact };
204
+ export { type ApiClient, type EnlaceHook, type EnlaceHookOptions, HTTP_METHODS, type HookState, type NextEnlaceHook, type NextHookOptions, type PollingInterval, type PollingIntervalFn, type PollingIntervalValue, type QueryFn, type ReactRequestOptionsBase, type SelectorFn, type TrackedCall, type UseEnlaceQueryOptions, type UseEnlaceQueryResult, type UseEnlaceSelectorResult, enlaceHookNext, enlaceHookReact };
@@ -19,14 +19,40 @@ type ReactRequestOptionsBase = {
19
19
  */
20
20
  params?: Record<string, string | number>;
21
21
  };
22
+ /** Polling interval value: milliseconds to wait, or false to stop polling */
23
+ type PollingIntervalValue = number | false;
24
+ /** Function that determines polling interval based on current data/error state */
25
+ type PollingIntervalFn<TData, TError> = (data: TData | undefined, error: TError | undefined) => PollingIntervalValue;
26
+ /** Polling interval option: static value or dynamic function */
27
+ type PollingInterval<TData = unknown, TError = unknown> = PollingIntervalValue | PollingIntervalFn<TData, TError>;
22
28
  /** Options for query mode hooks */
23
- type UseEnlaceQueryOptions = {
29
+ type UseEnlaceQueryOptions<TData = unknown, TError = unknown> = {
24
30
  /**
25
31
  * Whether the query should execute.
26
32
  * Set to false to skip fetching (useful when ID is "new" or undefined).
27
33
  * @default true
28
34
  */
29
35
  enabled?: boolean;
36
+ /**
37
+ * Polling interval in milliseconds, or a function that returns the interval.
38
+ * When set, the query will refetch after this interval AFTER the previous request completes.
39
+ * Uses sequential polling (setTimeout after fetch completes), not interval-based.
40
+ *
41
+ * Can be:
42
+ * - `number`: Fixed interval in milliseconds
43
+ * - `false`: Disable polling
44
+ * - `(data, error) => number | false`: Dynamic interval based on response
45
+ *
46
+ * @example
47
+ * // Fixed interval
48
+ * { pollingInterval: 5000 }
49
+ *
50
+ * // Conditional polling based on data
51
+ * { pollingInterval: (order) => order?.status === 'pending' ? 2000 : false }
52
+ *
53
+ * @default undefined (no polling)
54
+ */
55
+ pollingInterval?: PollingInterval<TData, TError>;
30
56
  };
31
57
  type ApiClient<TSchema, TDefaultError = unknown, TOptions = ReactRequestOptionsBase> = unknown extends TSchema ? WildcardClient<TOptions> : EnlaceClient<TSchema, TDefaultError, TOptions>;
32
58
  type QueryFn<TSchema, TData, TError, TDefaultError = unknown, TOptions = ReactRequestOptionsBase> = (api: ApiClient<TSchema, TDefaultError, TOptions>) => Promise<EnlaceResponse<TData, TError>>;
@@ -64,7 +90,7 @@ type UseEnlaceSelectorResult<TMethod> = {
64
90
  loading: boolean;
65
91
  fetching: boolean;
66
92
  } & HookResponseState<ExtractData<TMethod>, ExtractError<TMethod>>;
67
- /** Options for createEnlaceHookReact factory */
93
+ /** Options for enlaceHookReact factory */
68
94
  type EnlaceHookOptions = {
69
95
  /**
70
96
  * Auto-generate cache tags from URL path for GET requests.
@@ -81,10 +107,10 @@ type EnlaceHookOptions = {
81
107
  /** Callback called on error responses (HTTP errors or network failures) */
82
108
  onError?: (payload: EnlaceErrorCallbackPayload<unknown>) => void;
83
109
  };
84
- /** Hook type returned by createEnlaceHookReact */
110
+ /** Hook type returned by enlaceHookReact */
85
111
  type EnlaceHook<TSchema, TDefaultError = unknown> = {
86
112
  <TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: SelectorFn<TSchema, TMethod, TDefaultError>): UseEnlaceSelectorResult<TMethod>;
87
- <TData, TError>(queryFn: QueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
113
+ <TData, TError>(queryFn: QueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions<TData, TError>): UseEnlaceQueryResult<TData, TError>;
88
114
  };
89
115
 
90
116
  /**
@@ -92,7 +118,7 @@ type EnlaceHook<TSchema, TDefaultError = unknown> = {
92
118
  * Called at module level to create a reusable hook.
93
119
  *
94
120
  * @example
95
- * const useAPI = createEnlaceHookReact<ApiSchema>('https://api.com');
121
+ * const useAPI = enlaceHookReact<ApiSchema>('https://api.com');
96
122
  *
97
123
  * // Query mode - auto-fetch (auto-tracks changes, no deps array needed)
98
124
  * const { loading, data, error } = useAPI((api) => api.posts.get({ query: { userId } }));
@@ -101,7 +127,7 @@ type EnlaceHook<TSchema, TDefaultError = unknown> = {
101
127
  * const { trigger, loading, data, error } = useAPI((api) => api.posts.delete);
102
128
  * onClick={() => trigger({ body: { id: 1 } })}
103
129
  */
104
- declare function createEnlaceHookReact<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema, TDefaultError>;
130
+ declare function enlaceHookReact<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema, TDefaultError>;
105
131
 
106
132
  /**
107
133
  * Handler function called after successful mutations to trigger server-side revalidation.
@@ -109,14 +135,14 @@ declare function createEnlaceHookReact<TSchema = unknown, TDefaultError = unknow
109
135
  * @param paths - URL paths to revalidate
110
136
  */
111
137
  type ServerRevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
112
- /** Next.js-specific options (third argument for createEnlaceNext) */
138
+ /** Next.js-specific options (third argument for enlaceNext) */
113
139
  type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
114
140
  /**
115
141
  * Handler called after successful mutations to trigger server-side revalidation.
116
142
  * Receives auto-generated or manually specified tags and paths.
117
143
  * @example
118
144
  * ```ts
119
- * createEnlaceNext("http://localhost:3000/api/", {}, {
145
+ * enlaceNext("http://localhost:3000/api/", {}, {
120
146
  * serverRevalidator: (tags, paths) => revalidateServerAction(tags, paths)
121
147
  * });
122
148
  * ```
@@ -130,7 +156,7 @@ type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateT
130
156
  */
131
157
  skipServerRevalidation?: boolean;
132
158
  };
133
- /** Next.js hook options (third argument for createEnlaceHookNext) - extends React's EnlaceHookOptions */
159
+ /** Next.js hook options (third argument for enlaceHookNext) - extends React's EnlaceHookOptions */
134
160
  type NextHookOptions = EnlaceHookOptions & Pick<NextOptions, "serverRevalidator" | "skipServerRevalidation">;
135
161
  /** Per-request options for Next.js fetch - extends React's base options */
136
162
  type NextRequestOptionsBase = ReactRequestOptionsBase & {
@@ -151,10 +177,10 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
151
177
  };
152
178
  type NextQueryFn<TSchema, TData, TError, TDefaultError = unknown> = QueryFn<TSchema, TData, TError, TDefaultError, NextRequestOptionsBase>;
153
179
  type NextSelectorFn<TSchema, TMethod, TDefaultError = unknown> = SelectorFn<TSchema, TMethod, TDefaultError, NextRequestOptionsBase>;
154
- /** Hook type returned by createEnlaceHookNext */
180
+ /** Hook type returned by enlaceHookNext */
155
181
  type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
156
182
  <TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: NextSelectorFn<TSchema, TMethod, TDefaultError>): UseEnlaceSelectorResult<TMethod>;
157
- <TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
183
+ <TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError, TDefaultError>, options?: UseEnlaceQueryOptions<TData, TError>): UseEnlaceQueryResult<TData, TError>;
158
184
  };
159
185
 
160
186
  /**
@@ -162,7 +188,7 @@ type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
162
188
  * Uses Next.js-specific features like serverRevalidator for server-side cache invalidation.
163
189
  *
164
190
  * @example
165
- * const useAPI = createEnlaceHookNext<ApiSchema>('https://api.com', {}, {
191
+ * const useAPI = enlaceHookNext<ApiSchema>('https://api.com', {}, {
166
192
  * serverRevalidator: (tags) => revalidateTagsAction(tags),
167
193
  * staleTime: 5000,
168
194
  * });
@@ -173,6 +199,6 @@ type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
173
199
  * // Selector mode - trigger for mutations
174
200
  * const { trigger } = useAPI((api) => api.posts.delete);
175
201
  */
176
- declare function createEnlaceHookNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema, TDefaultError>;
202
+ declare function enlaceHookNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema, TDefaultError>;
177
203
 
178
- export { type ApiClient, type EnlaceHook, type EnlaceHookOptions, HTTP_METHODS, type HookState, type NextEnlaceHook, type NextHookOptions, type QueryFn, type ReactRequestOptionsBase, type SelectorFn, type TrackedCall, type UseEnlaceQueryOptions, type UseEnlaceQueryResult, type UseEnlaceSelectorResult, createEnlaceHookNext, createEnlaceHookReact };
204
+ export { type ApiClient, type EnlaceHook, type EnlaceHookOptions, HTTP_METHODS, type HookState, type NextEnlaceHook, type NextHookOptions, type PollingInterval, type PollingIntervalFn, type PollingIntervalValue, type QueryFn, type ReactRequestOptionsBase, type SelectorFn, type TrackedCall, type UseEnlaceQueryOptions, type UseEnlaceQueryResult, type UseEnlaceSelectorResult, enlaceHookNext, enlaceHookReact };
@@ -23,12 +23,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
23
23
  var hook_exports = {};
24
24
  __export(hook_exports, {
25
25
  HTTP_METHODS: () => HTTP_METHODS,
26
- createEnlaceHookNext: () => createEnlaceHookNext,
27
- createEnlaceHookReact: () => createEnlaceHookReact
26
+ enlaceHookNext: () => enlaceHookNext,
27
+ enlaceHookReact: () => enlaceHookReact
28
28
  });
29
29
  module.exports = __toCommonJS(hook_exports);
30
30
 
31
- // src/react/createEnlaceHookReact.ts
31
+ // src/react/enlaceHookReact.ts
32
32
  var import_enlace_core = require("enlace-core");
33
33
 
34
34
  // src/react/useQueryMode.ts
@@ -200,7 +200,7 @@ function resolvePath(path, params) {
200
200
  });
201
201
  }
202
202
  function useQueryMode(api, trackedCall, options) {
203
- const { autoGenerateTags, staleTime, enabled } = options;
203
+ const { autoGenerateTags, staleTime, enabled, pollingInterval } = options;
204
204
  const queryKey = createQueryKey(trackedCall);
205
205
  const requestOptions = trackedCall.options;
206
206
  const resolvedPath = resolvePath(trackedCall.path, requestOptions?.params);
@@ -225,15 +225,41 @@ function useQueryMode(api, trackedCall, options) {
225
225
  );
226
226
  const mountedRef = (0, import_react.useRef)(true);
227
227
  const fetchRef = (0, import_react.useRef)(null);
228
+ const pollingTimeoutRef = (0, import_react.useRef)(null);
229
+ const pollingIntervalRef = (0, import_react.useRef)(pollingInterval);
230
+ pollingIntervalRef.current = pollingInterval;
228
231
  (0, import_react.useEffect)(() => {
229
232
  mountedRef.current = true;
230
233
  if (!enabled) {
231
234
  dispatch({ type: "RESET" });
235
+ if (pollingTimeoutRef.current) {
236
+ clearTimeout(pollingTimeoutRef.current);
237
+ pollingTimeoutRef.current = null;
238
+ }
232
239
  return () => {
233
240
  mountedRef.current = false;
234
241
  };
235
242
  }
236
243
  dispatch({ type: "RESET", state: getCacheState(true) });
244
+ const scheduleNextPoll = () => {
245
+ const currentPollingInterval = pollingIntervalRef.current;
246
+ if (!mountedRef.current || !enabled || currentPollingInterval === void 0) {
247
+ return;
248
+ }
249
+ const cached2 = getCache(queryKey);
250
+ const interval = typeof currentPollingInterval === "function" ? currentPollingInterval(cached2?.data, cached2?.error) : currentPollingInterval;
251
+ if (interval === false || interval <= 0) {
252
+ return;
253
+ }
254
+ if (pollingTimeoutRef.current) {
255
+ clearTimeout(pollingTimeoutRef.current);
256
+ }
257
+ pollingTimeoutRef.current = setTimeout(() => {
258
+ if (mountedRef.current && enabled && fetchRef.current) {
259
+ fetchRef.current();
260
+ }
261
+ }, interval);
262
+ };
237
263
  const doFetch = () => {
238
264
  const cached2 = getCache(queryKey);
239
265
  if (cached2?.promise) {
@@ -259,6 +285,8 @@ function useQueryMode(api, trackedCall, options) {
259
285
  timestamp: Date.now(),
260
286
  tags: queryTags
261
287
  });
288
+ }).finally(() => {
289
+ scheduleNextPoll();
262
290
  });
263
291
  setCache(queryKey, {
264
292
  promise: fetchPromise,
@@ -269,6 +297,7 @@ function useQueryMode(api, trackedCall, options) {
269
297
  const cached = getCache(queryKey);
270
298
  if (cached?.data !== void 0 && !isStale(queryKey, staleTime)) {
271
299
  dispatch({ type: "SYNC_CACHE", state: getCacheState() });
300
+ scheduleNextPoll();
272
301
  } else {
273
302
  doFetch();
274
303
  }
@@ -280,6 +309,10 @@ function useQueryMode(api, trackedCall, options) {
280
309
  return () => {
281
310
  mountedRef.current = false;
282
311
  fetchRef.current = null;
312
+ if (pollingTimeoutRef.current) {
313
+ clearTimeout(pollingTimeoutRef.current);
314
+ pollingTimeoutRef.current = null;
315
+ }
283
316
  unsubscribe();
284
317
  };
285
318
  }, [queryKey, enabled]);
@@ -394,8 +427,8 @@ function useSelectorMode(config) {
394
427
  };
395
428
  }
396
429
 
397
- // src/react/createEnlaceHookReact.ts
398
- function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
430
+ // src/react/enlaceHookReact.ts
431
+ function enlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
399
432
  const {
400
433
  autoGenerateTags = true,
401
434
  autoRevalidateTags = true,
@@ -403,7 +436,7 @@ function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
403
436
  onSuccess,
404
437
  onError
405
438
  } = hookOptions;
406
- const api = (0, import_enlace_core.createEnlace)(baseUrl, defaultOptions, {
439
+ const api = (0, import_enlace_core.enlace)(baseUrl, defaultOptions, {
407
440
  onSuccess,
408
441
  onError
409
442
  });
@@ -435,7 +468,12 @@ function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
435
468
  return useQueryMode(
436
469
  api,
437
470
  trackingResult.trackedCall,
438
- { autoGenerateTags, staleTime, enabled: queryOptions?.enabled ?? true }
471
+ {
472
+ autoGenerateTags,
473
+ staleTime,
474
+ enabled: queryOptions?.enabled ?? true,
475
+ pollingInterval: queryOptions?.pollingInterval
476
+ }
439
477
  );
440
478
  }
441
479
  return useEnlaceHook;
@@ -492,7 +530,7 @@ async function executeNextFetch(baseUrl, path, method, combinedOptions, requestO
492
530
  }
493
531
 
494
532
  // src/next/index.ts
495
- function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
533
+ function enlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
496
534
  const combinedOptions = { ...defaultOptions, ...nextOptions };
497
535
  return (0, import_enlace_core3.createProxyHandler)(
498
536
  baseUrl,
@@ -502,15 +540,15 @@ function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
502
540
  );
503
541
  }
504
542
 
505
- // src/next/createEnlaceHookNext.ts
506
- function createEnlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
543
+ // src/next/enlaceHookNext.ts
544
+ function enlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
507
545
  const {
508
546
  autoGenerateTags = true,
509
547
  autoRevalidateTags = true,
510
548
  staleTime = 0,
511
549
  ...nextOptions
512
550
  } = hookOptions;
513
- const api = createEnlaceNext(
551
+ const api = enlaceNext(
514
552
  baseUrl,
515
553
  defaultOptions,
516
554
  {
@@ -547,7 +585,12 @@ function createEnlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
547
585
  return useQueryMode(
548
586
  api,
549
587
  trackedCall,
550
- { autoGenerateTags, staleTime, enabled: queryOptions?.enabled ?? true }
588
+ {
589
+ autoGenerateTags,
590
+ staleTime,
591
+ enabled: queryOptions?.enabled ?? true,
592
+ pollingInterval: queryOptions?.pollingInterval
593
+ }
551
594
  );
552
595
  }
553
596
  return useEnlaceHook;
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  "use client";
3
3
 
4
- // src/react/createEnlaceHookReact.ts
4
+ // src/react/enlaceHookReact.ts
5
5
  import {
6
- createEnlace
6
+ enlace
7
7
  } from "enlace-core";
8
8
 
9
9
  // src/react/useQueryMode.ts
@@ -175,7 +175,7 @@ function resolvePath(path, params) {
175
175
  });
176
176
  }
177
177
  function useQueryMode(api, trackedCall, options) {
178
- const { autoGenerateTags, staleTime, enabled } = options;
178
+ const { autoGenerateTags, staleTime, enabled, pollingInterval } = options;
179
179
  const queryKey = createQueryKey(trackedCall);
180
180
  const requestOptions = trackedCall.options;
181
181
  const resolvedPath = resolvePath(trackedCall.path, requestOptions?.params);
@@ -200,15 +200,41 @@ function useQueryMode(api, trackedCall, options) {
200
200
  );
201
201
  const mountedRef = useRef(true);
202
202
  const fetchRef = useRef(null);
203
+ const pollingTimeoutRef = useRef(null);
204
+ const pollingIntervalRef = useRef(pollingInterval);
205
+ pollingIntervalRef.current = pollingInterval;
203
206
  useEffect(() => {
204
207
  mountedRef.current = true;
205
208
  if (!enabled) {
206
209
  dispatch({ type: "RESET" });
210
+ if (pollingTimeoutRef.current) {
211
+ clearTimeout(pollingTimeoutRef.current);
212
+ pollingTimeoutRef.current = null;
213
+ }
207
214
  return () => {
208
215
  mountedRef.current = false;
209
216
  };
210
217
  }
211
218
  dispatch({ type: "RESET", state: getCacheState(true) });
219
+ const scheduleNextPoll = () => {
220
+ const currentPollingInterval = pollingIntervalRef.current;
221
+ if (!mountedRef.current || !enabled || currentPollingInterval === void 0) {
222
+ return;
223
+ }
224
+ const cached2 = getCache(queryKey);
225
+ const interval = typeof currentPollingInterval === "function" ? currentPollingInterval(cached2?.data, cached2?.error) : currentPollingInterval;
226
+ if (interval === false || interval <= 0) {
227
+ return;
228
+ }
229
+ if (pollingTimeoutRef.current) {
230
+ clearTimeout(pollingTimeoutRef.current);
231
+ }
232
+ pollingTimeoutRef.current = setTimeout(() => {
233
+ if (mountedRef.current && enabled && fetchRef.current) {
234
+ fetchRef.current();
235
+ }
236
+ }, interval);
237
+ };
212
238
  const doFetch = () => {
213
239
  const cached2 = getCache(queryKey);
214
240
  if (cached2?.promise) {
@@ -234,6 +260,8 @@ function useQueryMode(api, trackedCall, options) {
234
260
  timestamp: Date.now(),
235
261
  tags: queryTags
236
262
  });
263
+ }).finally(() => {
264
+ scheduleNextPoll();
237
265
  });
238
266
  setCache(queryKey, {
239
267
  promise: fetchPromise,
@@ -244,6 +272,7 @@ function useQueryMode(api, trackedCall, options) {
244
272
  const cached = getCache(queryKey);
245
273
  if (cached?.data !== void 0 && !isStale(queryKey, staleTime)) {
246
274
  dispatch({ type: "SYNC_CACHE", state: getCacheState() });
275
+ scheduleNextPoll();
247
276
  } else {
248
277
  doFetch();
249
278
  }
@@ -255,6 +284,10 @@ function useQueryMode(api, trackedCall, options) {
255
284
  return () => {
256
285
  mountedRef.current = false;
257
286
  fetchRef.current = null;
287
+ if (pollingTimeoutRef.current) {
288
+ clearTimeout(pollingTimeoutRef.current);
289
+ pollingTimeoutRef.current = null;
290
+ }
258
291
  unsubscribe();
259
292
  };
260
293
  }, [queryKey, enabled]);
@@ -369,8 +402,8 @@ function useSelectorMode(config) {
369
402
  };
370
403
  }
371
404
 
372
- // src/react/createEnlaceHookReact.ts
373
- function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
405
+ // src/react/enlaceHookReact.ts
406
+ function enlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
374
407
  const {
375
408
  autoGenerateTags = true,
376
409
  autoRevalidateTags = true,
@@ -378,7 +411,7 @@ function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
378
411
  onSuccess,
379
412
  onError
380
413
  } = hookOptions;
381
- const api = createEnlace(baseUrl, defaultOptions, {
414
+ const api = enlace(baseUrl, defaultOptions, {
382
415
  onSuccess,
383
416
  onError
384
417
  });
@@ -410,7 +443,12 @@ function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
410
443
  return useQueryMode(
411
444
  api,
412
445
  trackingResult.trackedCall,
413
- { autoGenerateTags, staleTime, enabled: queryOptions?.enabled ?? true }
446
+ {
447
+ autoGenerateTags,
448
+ staleTime,
449
+ enabled: queryOptions?.enabled ?? true,
450
+ pollingInterval: queryOptions?.pollingInterval
451
+ }
414
452
  );
415
453
  }
416
454
  return useEnlaceHook;
@@ -471,7 +509,7 @@ async function executeNextFetch(baseUrl, path, method, combinedOptions, requestO
471
509
  }
472
510
 
473
511
  // src/next/index.ts
474
- function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
512
+ function enlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
475
513
  const combinedOptions = { ...defaultOptions, ...nextOptions };
476
514
  return createProxyHandler(
477
515
  baseUrl,
@@ -481,15 +519,15 @@ function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
481
519
  );
482
520
  }
483
521
 
484
- // src/next/createEnlaceHookNext.ts
485
- function createEnlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
522
+ // src/next/enlaceHookNext.ts
523
+ function enlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
486
524
  const {
487
525
  autoGenerateTags = true,
488
526
  autoRevalidateTags = true,
489
527
  staleTime = 0,
490
528
  ...nextOptions
491
529
  } = hookOptions;
492
- const api = createEnlaceNext(
530
+ const api = enlaceNext(
493
531
  baseUrl,
494
532
  defaultOptions,
495
533
  {
@@ -526,13 +564,18 @@ function createEnlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
526
564
  return useQueryMode(
527
565
  api,
528
566
  trackedCall,
529
- { autoGenerateTags, staleTime, enabled: queryOptions?.enabled ?? true }
567
+ {
568
+ autoGenerateTags,
569
+ staleTime,
570
+ enabled: queryOptions?.enabled ?? true,
571
+ pollingInterval: queryOptions?.pollingInterval
572
+ }
530
573
  );
531
574
  }
532
575
  return useEnlaceHook;
533
576
  }
534
577
  export {
535
578
  HTTP_METHODS,
536
- createEnlaceHookNext,
537
- createEnlaceHookReact
579
+ enlaceHookNext,
580
+ enlaceHookReact
538
581
  };
package/dist/index.d.mts CHANGED
@@ -20,7 +20,7 @@ type ReactRequestOptionsBase = {
20
20
  */
21
21
  params?: Record<string, string | number>;
22
22
  };
23
- /** Options for createEnlaceHookReact factory */
23
+ /** Options for enlaceHookReact factory */
24
24
  type EnlaceHookOptions = {
25
25
  /**
26
26
  * Auto-generate cache tags from URL path for GET requests.
@@ -44,14 +44,14 @@ type EnlaceHookOptions = {
44
44
  * @param paths - URL paths to revalidate
45
45
  */
46
46
  type ServerRevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
47
- /** Next.js-specific options (third argument for createEnlaceNext) */
47
+ /** Next.js-specific options (third argument for enlaceNext) */
48
48
  type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
49
49
  /**
50
50
  * Handler called after successful mutations to trigger server-side revalidation.
51
51
  * Receives auto-generated or manually specified tags and paths.
52
52
  * @example
53
53
  * ```ts
54
- * createEnlaceNext("http://localhost:3000/api/", {}, {
54
+ * enlaceNext("http://localhost:3000/api/", {}, {
55
55
  * serverRevalidator: (tags, paths) => revalidateServerAction(tags, paths)
56
56
  * });
57
57
  * ```
@@ -83,6 +83,6 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
83
83
  serverRevalidate?: boolean;
84
84
  };
85
85
 
86
- declare function createEnlaceNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions | null, nextOptions?: NextOptions): unknown extends TSchema ? WildcardClient<NextRequestOptionsBase> : EnlaceClient<TSchema, TDefaultError, NextRequestOptionsBase>;
86
+ declare function enlaceNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions | null, nextOptions?: NextOptions): unknown extends TSchema ? WildcardClient<NextRequestOptionsBase> : EnlaceClient<TSchema, TDefaultError, NextRequestOptionsBase>;
87
87
 
88
- export { type NextOptions, type NextRequestOptionsBase, createEnlaceNext };
88
+ export { type NextOptions, type NextRequestOptionsBase, enlaceNext };
package/dist/index.d.ts CHANGED
@@ -20,7 +20,7 @@ type ReactRequestOptionsBase = {
20
20
  */
21
21
  params?: Record<string, string | number>;
22
22
  };
23
- /** Options for createEnlaceHookReact factory */
23
+ /** Options for enlaceHookReact factory */
24
24
  type EnlaceHookOptions = {
25
25
  /**
26
26
  * Auto-generate cache tags from URL path for GET requests.
@@ -44,14 +44,14 @@ type EnlaceHookOptions = {
44
44
  * @param paths - URL paths to revalidate
45
45
  */
46
46
  type ServerRevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
47
- /** Next.js-specific options (third argument for createEnlaceNext) */
47
+ /** Next.js-specific options (third argument for enlaceNext) */
48
48
  type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
49
49
  /**
50
50
  * Handler called after successful mutations to trigger server-side revalidation.
51
51
  * Receives auto-generated or manually specified tags and paths.
52
52
  * @example
53
53
  * ```ts
54
- * createEnlaceNext("http://localhost:3000/api/", {}, {
54
+ * enlaceNext("http://localhost:3000/api/", {}, {
55
55
  * serverRevalidator: (tags, paths) => revalidateServerAction(tags, paths)
56
56
  * });
57
57
  * ```
@@ -83,6 +83,6 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
83
83
  serverRevalidate?: boolean;
84
84
  };
85
85
 
86
- declare function createEnlaceNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions | null, nextOptions?: NextOptions): unknown extends TSchema ? WildcardClient<NextRequestOptionsBase> : EnlaceClient<TSchema, TDefaultError, NextRequestOptionsBase>;
86
+ declare function enlaceNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions | null, nextOptions?: NextOptions): unknown extends TSchema ? WildcardClient<NextRequestOptionsBase> : EnlaceClient<TSchema, TDefaultError, NextRequestOptionsBase>;
87
87
 
88
- export { type NextOptions, type NextRequestOptionsBase, createEnlaceNext };
88
+ export { type NextOptions, type NextRequestOptionsBase, enlaceNext };
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/index.ts
22
22
  var src_exports = {};
23
23
  __export(src_exports, {
24
- createEnlaceNext: () => createEnlaceNext
24
+ enlaceNext: () => enlaceNext
25
25
  });
26
26
  module.exports = __toCommonJS(src_exports);
27
27
  __reExport(src_exports, require("enlace-core"), module.exports);
@@ -84,7 +84,7 @@ async function executeNextFetch(baseUrl, path, method, combinedOptions, requestO
84
84
  }
85
85
 
86
86
  // src/next/index.ts
87
- function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
87
+ function enlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
88
88
  const combinedOptions = { ...defaultOptions, ...nextOptions };
89
89
  return (0, import_enlace_core2.createProxyHandler)(
90
90
  baseUrl,
package/dist/index.mjs CHANGED
@@ -63,7 +63,7 @@ async function executeNextFetch(baseUrl, path, method, combinedOptions, requestO
63
63
  }
64
64
 
65
65
  // src/next/index.ts
66
- function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
66
+ function enlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
67
67
  const combinedOptions = { ...defaultOptions, ...nextOptions };
68
68
  return createProxyHandler(
69
69
  baseUrl,
@@ -73,5 +73,5 @@ function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
73
73
  );
74
74
  }
75
75
  export {
76
- createEnlaceNext
76
+ enlaceNext
77
77
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "enlace",
3
- "version": "0.0.1-beta.13",
3
+ "version": "0.0.1-beta.14",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "dist"
@@ -18,7 +18,7 @@
18
18
  }
19
19
  },
20
20
  "dependencies": {
21
- "enlace-core": "0.0.1-beta.8"
21
+ "enlace-core": "0.0.1-beta.9"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "react": "^19"