enlace 0.0.1-beta.4 → 0.0.1-beta.6
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 +111 -17
- package/dist/{next/hook → hook}/index.d.mts +49 -10
- package/dist/{next/hook → hook}/index.d.ts +49 -10
- package/dist/{next/hook → hook}/index.js +158 -138
- package/dist/{next/hook → hook}/index.mjs +159 -158
- package/dist/index.d.mts +46 -77
- package/dist/index.d.ts +46 -77
- package/dist/index.js +48 -385
- package/dist/index.mjs +50 -385
- package/package.json +6 -11
- package/dist/next/index.d.mts +0 -82
- package/dist/next/index.d.ts +0 -82
- package/dist/next/index.js +0 -111
- package/dist/next/index.mjs +0 -95
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ npm install enlace
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import {
|
|
14
|
+
import { createEnlaceHookReact } from "enlace/hook";
|
|
15
|
+
import { Endpoint } from "enlace";
|
|
15
16
|
|
|
16
17
|
type ApiSchema = {
|
|
17
18
|
posts: {
|
|
@@ -24,7 +25,7 @@ type ApiSchema = {
|
|
|
24
25
|
};
|
|
25
26
|
};
|
|
26
27
|
|
|
27
|
-
const useAPI =
|
|
28
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com");
|
|
28
29
|
```
|
|
29
30
|
|
|
30
31
|
## Schema Conventions
|
|
@@ -33,13 +34,13 @@ Defining a schema is **recommended** for full type safety, but **optional**. You
|
|
|
33
34
|
|
|
34
35
|
```typescript
|
|
35
36
|
// Without schema (untyped, but still works!)
|
|
36
|
-
const useAPI =
|
|
37
|
+
const useAPI = createEnlaceHookReact("https://api.example.com");
|
|
37
38
|
const { data } = useAPI((api) => api.any.path.you.want.get());
|
|
38
39
|
```
|
|
39
40
|
|
|
40
41
|
```typescript
|
|
41
42
|
// With schema (recommended for type safety)
|
|
42
|
-
const useAPI =
|
|
43
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com");
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
### Schema Structure
|
|
@@ -310,7 +311,7 @@ trigger({ body: { title: "New" } });
|
|
|
310
311
|
Control how long cached data is considered fresh:
|
|
311
312
|
|
|
312
313
|
```typescript
|
|
313
|
-
const useAPI =
|
|
314
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {}, {
|
|
314
315
|
staleTime: 5000, // 5 seconds
|
|
315
316
|
});
|
|
316
317
|
```
|
|
@@ -337,7 +338,7 @@ trigger({
|
|
|
337
338
|
### Disable Auto-Revalidation
|
|
338
339
|
|
|
339
340
|
```typescript
|
|
340
|
-
const useAPI =
|
|
341
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {}, {
|
|
341
342
|
autoGenerateTags: false, // Disable auto tag generation
|
|
342
343
|
autoRevalidateTags: false, // Disable auto revalidation
|
|
343
344
|
});
|
|
@@ -346,7 +347,7 @@ const useAPI = createEnlaceHook<ApiSchema>("https://api.example.com", {}, {
|
|
|
346
347
|
## Hook Options
|
|
347
348
|
|
|
348
349
|
```typescript
|
|
349
|
-
const useAPI =
|
|
350
|
+
const useAPI = createEnlaceHookReact<ApiSchema>(
|
|
350
351
|
"https://api.example.com",
|
|
351
352
|
{
|
|
352
353
|
// Default fetch options
|
|
@@ -361,6 +362,92 @@ const useAPI = createEnlaceHook<ApiSchema>(
|
|
|
361
362
|
);
|
|
362
363
|
```
|
|
363
364
|
|
|
365
|
+
### Async Headers
|
|
366
|
+
|
|
367
|
+
Headers can be provided as a static value, sync function, or async function. This is useful when you need to fetch headers dynamically (e.g., auth tokens from async storage):
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
// Static headers
|
|
371
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
|
|
372
|
+
headers: { Authorization: "Bearer token" },
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Sync function
|
|
376
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
|
|
377
|
+
headers: () => ({ Authorization: `Bearer ${getToken()}` }),
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// Async function
|
|
381
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
|
|
382
|
+
headers: async () => {
|
|
383
|
+
const token = await getTokenFromStorage();
|
|
384
|
+
return { Authorization: `Bearer ${token}` };
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
This also works for per-request headers:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const { data } = useAPI((api) =>
|
|
393
|
+
api.posts.get({
|
|
394
|
+
headers: async () => {
|
|
395
|
+
const token = await refreshToken();
|
|
396
|
+
return { Authorization: `Bearer ${token}` };
|
|
397
|
+
},
|
|
398
|
+
})
|
|
399
|
+
);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Global Callbacks
|
|
403
|
+
|
|
404
|
+
You can set up global `onSuccess` and `onError` callbacks that are called for every request:
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
const useAPI = createEnlaceHookReact<ApiSchema>(
|
|
408
|
+
"https://api.example.com",
|
|
409
|
+
{
|
|
410
|
+
headers: { Authorization: "Bearer token" },
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
onSuccess: (payload) => {
|
|
414
|
+
console.log("Request succeeded:", payload.status, payload.data);
|
|
415
|
+
},
|
|
416
|
+
onError: (payload) => {
|
|
417
|
+
if (payload.status === 0) {
|
|
418
|
+
// Network error
|
|
419
|
+
console.error("Network error:", payload.error.message);
|
|
420
|
+
} else {
|
|
421
|
+
// HTTP error (4xx, 5xx)
|
|
422
|
+
console.error("HTTP error:", payload.status, payload.error);
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
}
|
|
426
|
+
);
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Callback Payloads:**
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// onSuccess payload
|
|
433
|
+
type EnlaceCallbackPayload<T> = {
|
|
434
|
+
status: number;
|
|
435
|
+
data: T;
|
|
436
|
+
headers: Headers;
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// onError payload (HTTP error or network error)
|
|
440
|
+
type EnlaceErrorCallbackPayload<T> =
|
|
441
|
+
| { status: number; error: T; headers: Headers } // HTTP error
|
|
442
|
+
| { status: 0; error: Error; headers: null }; // Network error
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Use cases:**
|
|
446
|
+
- Global error logging/reporting
|
|
447
|
+
- Toast notifications for all API errors
|
|
448
|
+
- Authentication refresh on 401 errors
|
|
449
|
+
- Analytics tracking
|
|
450
|
+
|
|
364
451
|
## Return Types
|
|
365
452
|
|
|
366
453
|
### Query Mode
|
|
@@ -403,6 +490,7 @@ type UseEnlaceSelectorResult<TMethod> = {
|
|
|
403
490
|
type RequestOptions = {
|
|
404
491
|
query?: Record<string, unknown>; // Query parameters
|
|
405
492
|
body?: TBody; // Request body
|
|
493
|
+
headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>); // Request headers
|
|
406
494
|
tags?: string[]; // Cache tags (GET only)
|
|
407
495
|
revalidateTags?: string[]; // Tags to invalidate after mutation
|
|
408
496
|
pathParams?: Record<string, string | number>; // Dynamic path parameters
|
|
@@ -415,12 +503,12 @@ type RequestOptions = {
|
|
|
415
503
|
|
|
416
504
|
### Server Components
|
|
417
505
|
|
|
418
|
-
Use `
|
|
506
|
+
Use `createEnlaceNext` from `enlace` for server components:
|
|
419
507
|
|
|
420
508
|
```typescript
|
|
421
|
-
import {
|
|
509
|
+
import { createEnlaceNext } from "enlace";
|
|
422
510
|
|
|
423
|
-
const api =
|
|
511
|
+
const api = createEnlaceNext<ApiSchema>("https://api.example.com", {}, {
|
|
424
512
|
autoGenerateTags: true,
|
|
425
513
|
});
|
|
426
514
|
|
|
@@ -435,14 +523,14 @@ export default async function Page() {
|
|
|
435
523
|
|
|
436
524
|
### Client Components
|
|
437
525
|
|
|
438
|
-
Use `
|
|
526
|
+
Use `createEnlaceHookNext` from `enlace/hook` for client components:
|
|
439
527
|
|
|
440
528
|
```typescript
|
|
441
529
|
"use client";
|
|
442
530
|
|
|
443
|
-
import {
|
|
531
|
+
import { createEnlaceHookNext } from "enlace/hook";
|
|
444
532
|
|
|
445
|
-
const useAPI =
|
|
533
|
+
const useAPI = createEnlaceHookNext<ApiSchema>("https://api.example.com");
|
|
446
534
|
```
|
|
447
535
|
|
|
448
536
|
### Server-Side Revalidation
|
|
@@ -467,10 +555,10 @@ export async function revalidateAction(tags: string[], paths: string[]) {
|
|
|
467
555
|
|
|
468
556
|
```typescript
|
|
469
557
|
// useAPI.ts
|
|
470
|
-
import {
|
|
558
|
+
import { createEnlaceHookNext } from "enlace/hook";
|
|
471
559
|
import { revalidateAction } from "./actions";
|
|
472
560
|
|
|
473
|
-
const useAPI =
|
|
561
|
+
const useAPI = createEnlaceHookNext<ApiSchema>("/api", {}, {
|
|
474
562
|
revalidator: revalidateAction,
|
|
475
563
|
});
|
|
476
564
|
```
|
|
@@ -509,17 +597,21 @@ Works with Next.js API routes:
|
|
|
509
597
|
|
|
510
598
|
```typescript
|
|
511
599
|
// Client component calling /api/posts
|
|
512
|
-
const useAPI =
|
|
600
|
+
const useAPI = createEnlaceHookNext<ApiSchema>("/api");
|
|
513
601
|
```
|
|
514
602
|
|
|
515
603
|
---
|
|
516
604
|
|
|
517
605
|
## API Reference
|
|
518
606
|
|
|
519
|
-
### `
|
|
607
|
+
### `createEnlaceHookReact<TSchema>(baseUrl, options?, hookOptions?)`
|
|
520
608
|
|
|
521
609
|
Creates a React hook for making API calls.
|
|
522
610
|
|
|
611
|
+
### `createEnlaceHookNext<TSchema>(baseUrl, options?, hookOptions?)`
|
|
612
|
+
|
|
613
|
+
Creates a Next.js hook with server revalidation support.
|
|
614
|
+
|
|
523
615
|
**Parameters:**
|
|
524
616
|
- `baseUrl` — Base URL for requests
|
|
525
617
|
- `options` — Default fetch options (headers, cache, etc.)
|
|
@@ -531,6 +623,8 @@ type EnlaceHookOptions = {
|
|
|
531
623
|
autoGenerateTags?: boolean; // default: true
|
|
532
624
|
autoRevalidateTags?: boolean; // default: true
|
|
533
625
|
staleTime?: number; // default: 0
|
|
626
|
+
onSuccess?: (payload: EnlaceCallbackPayload<unknown>) => void;
|
|
627
|
+
onError?: (payload: EnlaceErrorCallbackPayload<unknown>) => void;
|
|
534
628
|
};
|
|
535
629
|
```
|
|
536
630
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EnlaceCallbackPayload, EnlaceErrorCallbackPayload, EnlaceResponse, WildcardClient, EnlaceClient, EnlaceOptions, EnlaceCallbacks } from 'enlace-core';
|
|
2
2
|
|
|
3
3
|
/** Per-request options for React hooks */
|
|
4
4
|
type ReactRequestOptionsBase = {
|
|
@@ -31,6 +31,19 @@ type UseEnlaceQueryOptions = {
|
|
|
31
31
|
type ApiClient<TSchema, TOptions = ReactRequestOptionsBase> = unknown extends TSchema ? WildcardClient<TOptions> : EnlaceClient<TSchema, TOptions>;
|
|
32
32
|
type QueryFn<TSchema, TData, TError, TOptions = ReactRequestOptionsBase> = (api: ApiClient<TSchema, TOptions>) => Promise<EnlaceResponse<TData, TError>>;
|
|
33
33
|
type SelectorFn<TSchema, TMethod, TOptions = ReactRequestOptionsBase> = (api: ApiClient<TSchema, TOptions>) => TMethod;
|
|
34
|
+
type HookState = {
|
|
35
|
+
loading: boolean;
|
|
36
|
+
fetching: boolean;
|
|
37
|
+
ok: boolean | undefined;
|
|
38
|
+
data: unknown;
|
|
39
|
+
error: unknown;
|
|
40
|
+
};
|
|
41
|
+
type TrackedCall = {
|
|
42
|
+
path: string[];
|
|
43
|
+
method: string;
|
|
44
|
+
options: unknown;
|
|
45
|
+
};
|
|
46
|
+
declare const HTTP_METHODS: readonly ["get", "post", "put", "patch", "delete"];
|
|
34
47
|
type ExtractData<T> = T extends (...args: any[]) => Promise<EnlaceResponse<infer D, unknown>> ? D : never;
|
|
35
48
|
type ExtractError<T> = T extends (...args: any[]) => Promise<EnlaceResponse<unknown, infer E>> ? E : never;
|
|
36
49
|
/** Discriminated union for hook response state - enables type narrowing on ok check */
|
|
@@ -58,7 +71,7 @@ type UseEnlaceSelectorResult<TMethod> = {
|
|
|
58
71
|
loading: boolean;
|
|
59
72
|
fetching: boolean;
|
|
60
73
|
} & HookResponseState<ExtractData<TMethod>, ExtractError<TMethod>>;
|
|
61
|
-
|
|
74
|
+
/** Options for createEnlaceHookReact factory */
|
|
62
75
|
type EnlaceHookOptions = {
|
|
63
76
|
/**
|
|
64
77
|
* Auto-generate cache tags from URL path for GET requests.
|
|
@@ -70,29 +83,54 @@ type EnlaceHookOptions = {
|
|
|
70
83
|
autoRevalidateTags?: boolean;
|
|
71
84
|
/** Time in ms before cached data is considered stale. @default 0 (always stale) */
|
|
72
85
|
staleTime?: number;
|
|
86
|
+
/** Callback called on successful API responses */
|
|
87
|
+
onSuccess?: (payload: EnlaceCallbackPayload<unknown>) => void;
|
|
88
|
+
/** Callback called on error responses (HTTP errors or network failures) */
|
|
89
|
+
onError?: (payload: EnlaceErrorCallbackPayload<unknown>) => void;
|
|
90
|
+
};
|
|
91
|
+
/** Hook type returned by createEnlaceHookReact */
|
|
92
|
+
type EnlaceHook<TSchema> = {
|
|
93
|
+
<TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: SelectorFn<TSchema, TMethod>): UseEnlaceSelectorResult<TMethod>;
|
|
94
|
+
<TData, TError>(queryFn: QueryFn<TSchema, TData, TError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
|
|
73
95
|
};
|
|
74
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Creates a React hook for making API calls.
|
|
99
|
+
* Called at module level to create a reusable hook.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* const useAPI = createEnlaceHookReact<ApiSchema>('https://api.com');
|
|
103
|
+
*
|
|
104
|
+
* // Query mode - auto-fetch (auto-tracks changes, no deps array needed)
|
|
105
|
+
* const { loading, data, error } = useAPI((api) => api.posts.get({ query: { userId } }));
|
|
106
|
+
*
|
|
107
|
+
* // Selector mode - typed trigger for lazy calls
|
|
108
|
+
* const { trigger, loading, data, error } = useAPI((api) => api.posts.delete);
|
|
109
|
+
* onClick={() => trigger({ body: { id: 1 } })}
|
|
110
|
+
*/
|
|
111
|
+
declare function createEnlaceHookReact<TSchema = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema>;
|
|
112
|
+
|
|
75
113
|
/**
|
|
76
114
|
* Handler function called after successful mutations to trigger server-side revalidation.
|
|
77
115
|
* @param tags - Cache tags to revalidate
|
|
78
116
|
* @param paths - URL paths to revalidate
|
|
79
117
|
*/
|
|
80
118
|
type RevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
|
|
81
|
-
/** Next.js-specific options (third argument for
|
|
82
|
-
type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & {
|
|
119
|
+
/** Next.js-specific options (third argument for createEnlaceNext) */
|
|
120
|
+
type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
|
|
83
121
|
/**
|
|
84
122
|
* Handler called after successful mutations to trigger server-side revalidation.
|
|
85
123
|
* Receives auto-generated or manually specified tags and paths.
|
|
86
124
|
* @example
|
|
87
125
|
* ```ts
|
|
88
|
-
*
|
|
126
|
+
* createEnlaceNext("http://localhost:3000/api/", {}, {
|
|
89
127
|
* revalidator: (tags, paths) => revalidateServerAction(tags, paths)
|
|
90
128
|
* });
|
|
91
129
|
* ```
|
|
92
130
|
*/
|
|
93
131
|
revalidator?: RevalidateHandler;
|
|
94
132
|
};
|
|
95
|
-
/** Next.js hook options (third argument for
|
|
133
|
+
/** Next.js hook options (third argument for createEnlaceHookNext) - extends React's EnlaceHookOptions */
|
|
96
134
|
type NextHookOptions = EnlaceHookOptions & Pick<NextOptions, "revalidator">;
|
|
97
135
|
/** Per-request options for Next.js fetch - extends React's base options */
|
|
98
136
|
type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
@@ -113,19 +151,20 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
|
113
151
|
*/
|
|
114
152
|
skipRevalidator?: boolean;
|
|
115
153
|
};
|
|
116
|
-
|
|
117
154
|
type NextQueryFn<TSchema, TData, TError> = QueryFn<TSchema, TData, TError, NextRequestOptionsBase>;
|
|
118
155
|
type NextSelectorFn<TSchema, TMethod> = SelectorFn<TSchema, TMethod, NextRequestOptionsBase>;
|
|
156
|
+
/** Hook type returned by createEnlaceHookNext */
|
|
119
157
|
type NextEnlaceHook<TSchema> = {
|
|
120
158
|
<TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: NextSelectorFn<TSchema, TMethod>): UseEnlaceSelectorResult<TMethod>;
|
|
121
159
|
<TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
|
|
122
160
|
};
|
|
161
|
+
|
|
123
162
|
/**
|
|
124
163
|
* Creates a React hook for making API calls in Next.js Client Components.
|
|
125
164
|
* Uses Next.js-specific features like revalidator for server-side cache invalidation.
|
|
126
165
|
*
|
|
127
166
|
* @example
|
|
128
|
-
* const useAPI =
|
|
167
|
+
* const useAPI = createEnlaceHookNext<ApiSchema>('https://api.com', {}, {
|
|
129
168
|
* revalidator: (tags) => revalidateTagsAction(tags),
|
|
130
169
|
* staleTime: 5000,
|
|
131
170
|
* });
|
|
@@ -136,6 +175,6 @@ type NextEnlaceHook<TSchema> = {
|
|
|
136
175
|
* // Selector mode - trigger for mutations
|
|
137
176
|
* const { trigger } = useAPI((api) => api.posts.delete);
|
|
138
177
|
*/
|
|
139
|
-
declare function
|
|
178
|
+
declare function createEnlaceHookNext<TSchema = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema>;
|
|
140
179
|
|
|
141
|
-
export {
|
|
180
|
+
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 };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EnlaceCallbackPayload, EnlaceErrorCallbackPayload, EnlaceResponse, WildcardClient, EnlaceClient, EnlaceOptions, EnlaceCallbacks } from 'enlace-core';
|
|
2
2
|
|
|
3
3
|
/** Per-request options for React hooks */
|
|
4
4
|
type ReactRequestOptionsBase = {
|
|
@@ -31,6 +31,19 @@ type UseEnlaceQueryOptions = {
|
|
|
31
31
|
type ApiClient<TSchema, TOptions = ReactRequestOptionsBase> = unknown extends TSchema ? WildcardClient<TOptions> : EnlaceClient<TSchema, TOptions>;
|
|
32
32
|
type QueryFn<TSchema, TData, TError, TOptions = ReactRequestOptionsBase> = (api: ApiClient<TSchema, TOptions>) => Promise<EnlaceResponse<TData, TError>>;
|
|
33
33
|
type SelectorFn<TSchema, TMethod, TOptions = ReactRequestOptionsBase> = (api: ApiClient<TSchema, TOptions>) => TMethod;
|
|
34
|
+
type HookState = {
|
|
35
|
+
loading: boolean;
|
|
36
|
+
fetching: boolean;
|
|
37
|
+
ok: boolean | undefined;
|
|
38
|
+
data: unknown;
|
|
39
|
+
error: unknown;
|
|
40
|
+
};
|
|
41
|
+
type TrackedCall = {
|
|
42
|
+
path: string[];
|
|
43
|
+
method: string;
|
|
44
|
+
options: unknown;
|
|
45
|
+
};
|
|
46
|
+
declare const HTTP_METHODS: readonly ["get", "post", "put", "patch", "delete"];
|
|
34
47
|
type ExtractData<T> = T extends (...args: any[]) => Promise<EnlaceResponse<infer D, unknown>> ? D : never;
|
|
35
48
|
type ExtractError<T> = T extends (...args: any[]) => Promise<EnlaceResponse<unknown, infer E>> ? E : never;
|
|
36
49
|
/** Discriminated union for hook response state - enables type narrowing on ok check */
|
|
@@ -58,7 +71,7 @@ type UseEnlaceSelectorResult<TMethod> = {
|
|
|
58
71
|
loading: boolean;
|
|
59
72
|
fetching: boolean;
|
|
60
73
|
} & HookResponseState<ExtractData<TMethod>, ExtractError<TMethod>>;
|
|
61
|
-
|
|
74
|
+
/** Options for createEnlaceHookReact factory */
|
|
62
75
|
type EnlaceHookOptions = {
|
|
63
76
|
/**
|
|
64
77
|
* Auto-generate cache tags from URL path for GET requests.
|
|
@@ -70,29 +83,54 @@ type EnlaceHookOptions = {
|
|
|
70
83
|
autoRevalidateTags?: boolean;
|
|
71
84
|
/** Time in ms before cached data is considered stale. @default 0 (always stale) */
|
|
72
85
|
staleTime?: number;
|
|
86
|
+
/** Callback called on successful API responses */
|
|
87
|
+
onSuccess?: (payload: EnlaceCallbackPayload<unknown>) => void;
|
|
88
|
+
/** Callback called on error responses (HTTP errors or network failures) */
|
|
89
|
+
onError?: (payload: EnlaceErrorCallbackPayload<unknown>) => void;
|
|
90
|
+
};
|
|
91
|
+
/** Hook type returned by createEnlaceHookReact */
|
|
92
|
+
type EnlaceHook<TSchema> = {
|
|
93
|
+
<TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: SelectorFn<TSchema, TMethod>): UseEnlaceSelectorResult<TMethod>;
|
|
94
|
+
<TData, TError>(queryFn: QueryFn<TSchema, TData, TError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
|
|
73
95
|
};
|
|
74
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Creates a React hook for making API calls.
|
|
99
|
+
* Called at module level to create a reusable hook.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* const useAPI = createEnlaceHookReact<ApiSchema>('https://api.com');
|
|
103
|
+
*
|
|
104
|
+
* // Query mode - auto-fetch (auto-tracks changes, no deps array needed)
|
|
105
|
+
* const { loading, data, error } = useAPI((api) => api.posts.get({ query: { userId } }));
|
|
106
|
+
*
|
|
107
|
+
* // Selector mode - typed trigger for lazy calls
|
|
108
|
+
* const { trigger, loading, data, error } = useAPI((api) => api.posts.delete);
|
|
109
|
+
* onClick={() => trigger({ body: { id: 1 } })}
|
|
110
|
+
*/
|
|
111
|
+
declare function createEnlaceHookReact<TSchema = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema>;
|
|
112
|
+
|
|
75
113
|
/**
|
|
76
114
|
* Handler function called after successful mutations to trigger server-side revalidation.
|
|
77
115
|
* @param tags - Cache tags to revalidate
|
|
78
116
|
* @param paths - URL paths to revalidate
|
|
79
117
|
*/
|
|
80
118
|
type RevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
|
|
81
|
-
/** Next.js-specific options (third argument for
|
|
82
|
-
type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & {
|
|
119
|
+
/** Next.js-specific options (third argument for createEnlaceNext) */
|
|
120
|
+
type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
|
|
83
121
|
/**
|
|
84
122
|
* Handler called after successful mutations to trigger server-side revalidation.
|
|
85
123
|
* Receives auto-generated or manually specified tags and paths.
|
|
86
124
|
* @example
|
|
87
125
|
* ```ts
|
|
88
|
-
*
|
|
126
|
+
* createEnlaceNext("http://localhost:3000/api/", {}, {
|
|
89
127
|
* revalidator: (tags, paths) => revalidateServerAction(tags, paths)
|
|
90
128
|
* });
|
|
91
129
|
* ```
|
|
92
130
|
*/
|
|
93
131
|
revalidator?: RevalidateHandler;
|
|
94
132
|
};
|
|
95
|
-
/** Next.js hook options (third argument for
|
|
133
|
+
/** Next.js hook options (third argument for createEnlaceHookNext) - extends React's EnlaceHookOptions */
|
|
96
134
|
type NextHookOptions = EnlaceHookOptions & Pick<NextOptions, "revalidator">;
|
|
97
135
|
/** Per-request options for Next.js fetch - extends React's base options */
|
|
98
136
|
type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
@@ -113,19 +151,20 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
|
113
151
|
*/
|
|
114
152
|
skipRevalidator?: boolean;
|
|
115
153
|
};
|
|
116
|
-
|
|
117
154
|
type NextQueryFn<TSchema, TData, TError> = QueryFn<TSchema, TData, TError, NextRequestOptionsBase>;
|
|
118
155
|
type NextSelectorFn<TSchema, TMethod> = SelectorFn<TSchema, TMethod, NextRequestOptionsBase>;
|
|
156
|
+
/** Hook type returned by createEnlaceHookNext */
|
|
119
157
|
type NextEnlaceHook<TSchema> = {
|
|
120
158
|
<TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: NextSelectorFn<TSchema, TMethod>): UseEnlaceSelectorResult<TMethod>;
|
|
121
159
|
<TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
|
|
122
160
|
};
|
|
161
|
+
|
|
123
162
|
/**
|
|
124
163
|
* Creates a React hook for making API calls in Next.js Client Components.
|
|
125
164
|
* Uses Next.js-specific features like revalidator for server-side cache invalidation.
|
|
126
165
|
*
|
|
127
166
|
* @example
|
|
128
|
-
* const useAPI =
|
|
167
|
+
* const useAPI = createEnlaceHookNext<ApiSchema>('https://api.com', {}, {
|
|
129
168
|
* revalidator: (tags) => revalidateTagsAction(tags),
|
|
130
169
|
* staleTime: 5000,
|
|
131
170
|
* });
|
|
@@ -136,6 +175,6 @@ type NextEnlaceHook<TSchema> = {
|
|
|
136
175
|
* // Selector mode - trigger for mutations
|
|
137
176
|
* const { trigger } = useAPI((api) => api.posts.delete);
|
|
138
177
|
*/
|
|
139
|
-
declare function
|
|
178
|
+
declare function createEnlaceHookNext<TSchema = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema>;
|
|
140
179
|
|
|
141
|
-
export {
|
|
180
|
+
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 };
|