enlace 0.0.1-beta.5 → 0.0.1-beta.7
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 +26 -21
- package/dist/{next/hook → hook}/index.d.mts +43 -9
- package/dist/{next/hook → hook}/index.d.ts +43 -9
- package/dist/{next/hook → hook}/index.js +141 -103
- package/dist/{next/hook → hook}/index.mjs +142 -121
- package/dist/index.d.mts +41 -78
- package/dist/index.d.ts +41 -78
- package/dist/index.js +48 -391
- package/dist/index.mjs +52 -391
- package/package.json +6 -11
- package/dist/next/index.d.mts +0 -133
- package/dist/next/index.d.ts +0 -133
- package/dist/next/index.js +0 -89
- package/dist/next/index.mjs +0 -71
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
|
|
@@ -367,17 +368,17 @@ Headers can be provided as a static value, sync function, or async function. Thi
|
|
|
367
368
|
|
|
368
369
|
```typescript
|
|
369
370
|
// Static headers
|
|
370
|
-
const useAPI =
|
|
371
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
|
|
371
372
|
headers: { Authorization: "Bearer token" },
|
|
372
373
|
});
|
|
373
374
|
|
|
374
375
|
// Sync function
|
|
375
|
-
const useAPI =
|
|
376
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
|
|
376
377
|
headers: () => ({ Authorization: `Bearer ${getToken()}` }),
|
|
377
378
|
});
|
|
378
379
|
|
|
379
380
|
// Async function
|
|
380
|
-
const useAPI =
|
|
381
|
+
const useAPI = createEnlaceHookReact<ApiSchema>("https://api.example.com", {
|
|
381
382
|
headers: async () => {
|
|
382
383
|
const token = await getTokenFromStorage();
|
|
383
384
|
return { Authorization: `Bearer ${token}` };
|
|
@@ -403,7 +404,7 @@ const { data } = useAPI((api) =>
|
|
|
403
404
|
You can set up global `onSuccess` and `onError` callbacks that are called for every request:
|
|
404
405
|
|
|
405
406
|
```typescript
|
|
406
|
-
const useAPI =
|
|
407
|
+
const useAPI = createEnlaceHookReact<ApiSchema>(
|
|
407
408
|
"https://api.example.com",
|
|
408
409
|
{
|
|
409
410
|
headers: { Authorization: "Bearer token" },
|
|
@@ -502,12 +503,12 @@ type RequestOptions = {
|
|
|
502
503
|
|
|
503
504
|
### Server Components
|
|
504
505
|
|
|
505
|
-
Use `
|
|
506
|
+
Use `createEnlaceNext` from `enlace` for server components:
|
|
506
507
|
|
|
507
508
|
```typescript
|
|
508
|
-
import {
|
|
509
|
+
import { createEnlaceNext } from "enlace";
|
|
509
510
|
|
|
510
|
-
const api =
|
|
511
|
+
const api = createEnlaceNext<ApiSchema>("https://api.example.com", {}, {
|
|
511
512
|
autoGenerateTags: true,
|
|
512
513
|
});
|
|
513
514
|
|
|
@@ -522,14 +523,14 @@ export default async function Page() {
|
|
|
522
523
|
|
|
523
524
|
### Client Components
|
|
524
525
|
|
|
525
|
-
Use `
|
|
526
|
+
Use `createEnlaceHookNext` from `enlace/hook` for client components:
|
|
526
527
|
|
|
527
528
|
```typescript
|
|
528
529
|
"use client";
|
|
529
530
|
|
|
530
|
-
import {
|
|
531
|
+
import { createEnlaceHookNext } from "enlace/hook";
|
|
531
532
|
|
|
532
|
-
const useAPI =
|
|
533
|
+
const useAPI = createEnlaceHookNext<ApiSchema>("https://api.example.com");
|
|
533
534
|
```
|
|
534
535
|
|
|
535
536
|
### Server-Side Revalidation
|
|
@@ -554,10 +555,10 @@ export async function revalidateAction(tags: string[], paths: string[]) {
|
|
|
554
555
|
|
|
555
556
|
```typescript
|
|
556
557
|
// useAPI.ts
|
|
557
|
-
import {
|
|
558
|
+
import { createEnlaceHookNext } from "enlace/hook";
|
|
558
559
|
import { revalidateAction } from "./actions";
|
|
559
560
|
|
|
560
|
-
const useAPI =
|
|
561
|
+
const useAPI = createEnlaceHookNext<ApiSchema>("/api", {}, {
|
|
561
562
|
revalidator: revalidateAction,
|
|
562
563
|
});
|
|
563
564
|
```
|
|
@@ -596,17 +597,21 @@ Works with Next.js API routes:
|
|
|
596
597
|
|
|
597
598
|
```typescript
|
|
598
599
|
// Client component calling /api/posts
|
|
599
|
-
const useAPI =
|
|
600
|
+
const useAPI = createEnlaceHookNext<ApiSchema>("/api");
|
|
600
601
|
```
|
|
601
602
|
|
|
602
603
|
---
|
|
603
604
|
|
|
604
605
|
## API Reference
|
|
605
606
|
|
|
606
|
-
### `
|
|
607
|
+
### `createEnlaceHookReact<TSchema>(baseUrl, options?, hookOptions?)`
|
|
607
608
|
|
|
608
609
|
Creates a React hook for making API calls.
|
|
609
610
|
|
|
611
|
+
### `createEnlaceHookNext<TSchema>(baseUrl, options?, hookOptions?)`
|
|
612
|
+
|
|
613
|
+
Creates a Next.js hook with server revalidation support.
|
|
614
|
+
|
|
610
615
|
**Parameters:**
|
|
611
616
|
- `baseUrl` — Base URL for requests
|
|
612
617
|
- `options` — Default fetch options (headers, cache, etc.)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EnlaceCallbackPayload, EnlaceErrorCallbackPayload, WildcardClient, EnlaceClient,
|
|
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
|
-
/** Options for
|
|
74
|
+
/** Options for createEnlaceHookReact factory */
|
|
62
75
|
type EnlaceHookOptions = {
|
|
63
76
|
/**
|
|
64
77
|
* Auto-generate cache tags from URL path for GET requests.
|
|
@@ -75,6 +88,27 @@ type EnlaceHookOptions = {
|
|
|
75
88
|
/** Callback called on error responses (HTTP errors or network failures) */
|
|
76
89
|
onError?: (payload: EnlaceErrorCallbackPayload<unknown>) => void;
|
|
77
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>;
|
|
95
|
+
};
|
|
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>;
|
|
78
112
|
|
|
79
113
|
/**
|
|
80
114
|
* Handler function called after successful mutations to trigger server-side revalidation.
|
|
@@ -82,21 +116,21 @@ type EnlaceHookOptions = {
|
|
|
82
116
|
* @param paths - URL paths to revalidate
|
|
83
117
|
*/
|
|
84
118
|
type RevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
|
|
85
|
-
/** Next.js-specific options (third argument for
|
|
119
|
+
/** Next.js-specific options (third argument for createEnlaceNext) */
|
|
86
120
|
type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
|
|
87
121
|
/**
|
|
88
122
|
* Handler called after successful mutations to trigger server-side revalidation.
|
|
89
123
|
* Receives auto-generated or manually specified tags and paths.
|
|
90
124
|
* @example
|
|
91
125
|
* ```ts
|
|
92
|
-
*
|
|
126
|
+
* createEnlaceNext("http://localhost:3000/api/", {}, {
|
|
93
127
|
* revalidator: (tags, paths) => revalidateServerAction(tags, paths)
|
|
94
128
|
* });
|
|
95
129
|
* ```
|
|
96
130
|
*/
|
|
97
131
|
revalidator?: RevalidateHandler;
|
|
98
132
|
};
|
|
99
|
-
/** Next.js hook options (third argument for
|
|
133
|
+
/** Next.js hook options (third argument for createEnlaceHookNext) - extends React's EnlaceHookOptions */
|
|
100
134
|
type NextHookOptions = EnlaceHookOptions & Pick<NextOptions, "revalidator">;
|
|
101
135
|
/** Per-request options for Next.js fetch - extends React's base options */
|
|
102
136
|
type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
@@ -119,7 +153,7 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
|
119
153
|
};
|
|
120
154
|
type NextQueryFn<TSchema, TData, TError> = QueryFn<TSchema, TData, TError, NextRequestOptionsBase>;
|
|
121
155
|
type NextSelectorFn<TSchema, TMethod> = SelectorFn<TSchema, TMethod, NextRequestOptionsBase>;
|
|
122
|
-
/** Hook type returned by
|
|
156
|
+
/** Hook type returned by createEnlaceHookNext */
|
|
123
157
|
type NextEnlaceHook<TSchema> = {
|
|
124
158
|
<TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: NextSelectorFn<TSchema, TMethod>): UseEnlaceSelectorResult<TMethod>;
|
|
125
159
|
<TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
|
|
@@ -130,7 +164,7 @@ type NextEnlaceHook<TSchema> = {
|
|
|
130
164
|
* Uses Next.js-specific features like revalidator for server-side cache invalidation.
|
|
131
165
|
*
|
|
132
166
|
* @example
|
|
133
|
-
* const useAPI =
|
|
167
|
+
* const useAPI = createEnlaceHookNext<ApiSchema>('https://api.com', {}, {
|
|
134
168
|
* revalidator: (tags) => revalidateTagsAction(tags),
|
|
135
169
|
* staleTime: 5000,
|
|
136
170
|
* });
|
|
@@ -141,6 +175,6 @@ type NextEnlaceHook<TSchema> = {
|
|
|
141
175
|
* // Selector mode - trigger for mutations
|
|
142
176
|
* const { trigger } = useAPI((api) => api.posts.delete);
|
|
143
177
|
*/
|
|
144
|
-
declare function
|
|
178
|
+
declare function createEnlaceHookNext<TSchema = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema>;
|
|
145
179
|
|
|
146
|
-
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 { EnlaceCallbackPayload, EnlaceErrorCallbackPayload, WildcardClient, EnlaceClient,
|
|
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
|
-
/** Options for
|
|
74
|
+
/** Options for createEnlaceHookReact factory */
|
|
62
75
|
type EnlaceHookOptions = {
|
|
63
76
|
/**
|
|
64
77
|
* Auto-generate cache tags from URL path for GET requests.
|
|
@@ -75,6 +88,27 @@ type EnlaceHookOptions = {
|
|
|
75
88
|
/** Callback called on error responses (HTTP errors or network failures) */
|
|
76
89
|
onError?: (payload: EnlaceErrorCallbackPayload<unknown>) => void;
|
|
77
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>;
|
|
95
|
+
};
|
|
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>;
|
|
78
112
|
|
|
79
113
|
/**
|
|
80
114
|
* Handler function called after successful mutations to trigger server-side revalidation.
|
|
@@ -82,21 +116,21 @@ type EnlaceHookOptions = {
|
|
|
82
116
|
* @param paths - URL paths to revalidate
|
|
83
117
|
*/
|
|
84
118
|
type RevalidateHandler = (tags: string[], paths: string[]) => void | Promise<void>;
|
|
85
|
-
/** Next.js-specific options (third argument for
|
|
119
|
+
/** Next.js-specific options (third argument for createEnlaceNext) */
|
|
86
120
|
type NextOptions = Pick<EnlaceHookOptions, "autoGenerateTags" | "autoRevalidateTags"> & EnlaceCallbacks & {
|
|
87
121
|
/**
|
|
88
122
|
* Handler called after successful mutations to trigger server-side revalidation.
|
|
89
123
|
* Receives auto-generated or manually specified tags and paths.
|
|
90
124
|
* @example
|
|
91
125
|
* ```ts
|
|
92
|
-
*
|
|
126
|
+
* createEnlaceNext("http://localhost:3000/api/", {}, {
|
|
93
127
|
* revalidator: (tags, paths) => revalidateServerAction(tags, paths)
|
|
94
128
|
* });
|
|
95
129
|
* ```
|
|
96
130
|
*/
|
|
97
131
|
revalidator?: RevalidateHandler;
|
|
98
132
|
};
|
|
99
|
-
/** Next.js hook options (third argument for
|
|
133
|
+
/** Next.js hook options (third argument for createEnlaceHookNext) - extends React's EnlaceHookOptions */
|
|
100
134
|
type NextHookOptions = EnlaceHookOptions & Pick<NextOptions, "revalidator">;
|
|
101
135
|
/** Per-request options for Next.js fetch - extends React's base options */
|
|
102
136
|
type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
@@ -119,7 +153,7 @@ type NextRequestOptionsBase = ReactRequestOptionsBase & {
|
|
|
119
153
|
};
|
|
120
154
|
type NextQueryFn<TSchema, TData, TError> = QueryFn<TSchema, TData, TError, NextRequestOptionsBase>;
|
|
121
155
|
type NextSelectorFn<TSchema, TMethod> = SelectorFn<TSchema, TMethod, NextRequestOptionsBase>;
|
|
122
|
-
/** Hook type returned by
|
|
156
|
+
/** Hook type returned by createEnlaceHookNext */
|
|
123
157
|
type NextEnlaceHook<TSchema> = {
|
|
124
158
|
<TMethod extends (...args: any[]) => Promise<EnlaceResponse<unknown, unknown>>>(selector: NextSelectorFn<TSchema, TMethod>): UseEnlaceSelectorResult<TMethod>;
|
|
125
159
|
<TData, TError>(queryFn: NextQueryFn<TSchema, TData, TError>, options?: UseEnlaceQueryOptions): UseEnlaceQueryResult<TData, TError>;
|
|
@@ -130,7 +164,7 @@ type NextEnlaceHook<TSchema> = {
|
|
|
130
164
|
* Uses Next.js-specific features like revalidator for server-side cache invalidation.
|
|
131
165
|
*
|
|
132
166
|
* @example
|
|
133
|
-
* const useAPI =
|
|
167
|
+
* const useAPI = createEnlaceHookNext<ApiSchema>('https://api.com', {}, {
|
|
134
168
|
* revalidator: (tags) => revalidateTagsAction(tags),
|
|
135
169
|
* staleTime: 5000,
|
|
136
170
|
* });
|
|
@@ -141,6 +175,6 @@ type NextEnlaceHook<TSchema> = {
|
|
|
141
175
|
* // Selector mode - trigger for mutations
|
|
142
176
|
* const { trigger } = useAPI((api) => api.posts.delete);
|
|
143
177
|
*/
|
|
144
|
-
declare function
|
|
178
|
+
declare function createEnlaceHookNext<TSchema = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema>;
|
|
145
179
|
|
|
146
|
-
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 };
|
|
@@ -17,85 +17,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
}
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
|
-
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
21
20
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
21
|
|
|
23
|
-
// src/
|
|
24
|
-
var
|
|
25
|
-
__export(
|
|
26
|
-
|
|
22
|
+
// src/hook/index.ts
|
|
23
|
+
var hook_exports = {};
|
|
24
|
+
__export(hook_exports, {
|
|
25
|
+
HTTP_METHODS: () => HTTP_METHODS,
|
|
26
|
+
createEnlaceHookNext: () => createEnlaceHookNext,
|
|
27
|
+
createEnlaceHookReact: () => createEnlaceHookReact
|
|
27
28
|
});
|
|
28
|
-
module.exports = __toCommonJS(
|
|
29
|
+
module.exports = __toCommonJS(hook_exports);
|
|
29
30
|
|
|
30
|
-
// src/
|
|
31
|
-
var next_exports = {};
|
|
32
|
-
__export(next_exports, {
|
|
33
|
-
createEnlace: () => createEnlace
|
|
34
|
-
});
|
|
35
|
-
var import_enlace_core2 = require("enlace-core");
|
|
36
|
-
|
|
37
|
-
// src/next/fetch.ts
|
|
31
|
+
// src/react/createEnlaceHookReact.ts
|
|
38
32
|
var import_enlace_core = require("enlace-core");
|
|
39
33
|
|
|
40
|
-
// src/utils/generateTags.ts
|
|
41
|
-
function generateTags(path) {
|
|
42
|
-
return path.map((_, i) => path.slice(0, i + 1).join("/"));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// src/next/fetch.ts
|
|
46
|
-
async function executeNextFetch(baseUrl, path, method, combinedOptions, requestOptions) {
|
|
47
|
-
const {
|
|
48
|
-
autoGenerateTags = true,
|
|
49
|
-
autoRevalidateTags = true,
|
|
50
|
-
revalidator,
|
|
51
|
-
onSuccess,
|
|
52
|
-
...coreOptions
|
|
53
|
-
} = combinedOptions;
|
|
54
|
-
const isGet = method === "GET";
|
|
55
|
-
const autoTags = generateTags(path);
|
|
56
|
-
const nextOnSuccess = (payload) => {
|
|
57
|
-
if (!isGet && !requestOptions?.skipRevalidator) {
|
|
58
|
-
const revalidateTags = requestOptions?.revalidateTags ?? (autoRevalidateTags ? autoTags : []);
|
|
59
|
-
const revalidatePaths = requestOptions?.revalidatePaths ?? [];
|
|
60
|
-
if (revalidateTags.length || revalidatePaths.length) {
|
|
61
|
-
revalidator?.(revalidateTags, revalidatePaths);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
onSuccess?.(payload);
|
|
65
|
-
};
|
|
66
|
-
const nextRequestOptions = { ...requestOptions };
|
|
67
|
-
if (isGet) {
|
|
68
|
-
const tags = requestOptions?.tags ?? (autoGenerateTags ? autoTags : void 0);
|
|
69
|
-
const nextFetchOptions = {};
|
|
70
|
-
if (tags) {
|
|
71
|
-
nextFetchOptions.tags = tags;
|
|
72
|
-
}
|
|
73
|
-
if (requestOptions?.revalidate !== void 0) {
|
|
74
|
-
nextFetchOptions.revalidate = requestOptions.revalidate;
|
|
75
|
-
}
|
|
76
|
-
nextRequestOptions.next = nextFetchOptions;
|
|
77
|
-
}
|
|
78
|
-
return (0, import_enlace_core.executeFetch)(
|
|
79
|
-
baseUrl,
|
|
80
|
-
path,
|
|
81
|
-
method,
|
|
82
|
-
{ ...coreOptions, onSuccess: nextOnSuccess },
|
|
83
|
-
nextRequestOptions
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/next/index.ts
|
|
88
|
-
__reExport(next_exports, require("enlace-core"));
|
|
89
|
-
function createEnlace(baseUrl, defaultOptions = {}, nextOptions = {}) {
|
|
90
|
-
const combinedOptions = { ...defaultOptions, ...nextOptions };
|
|
91
|
-
return (0, import_enlace_core2.createProxyHandler)(
|
|
92
|
-
baseUrl,
|
|
93
|
-
combinedOptions,
|
|
94
|
-
[],
|
|
95
|
-
executeNextFetch
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
34
|
// src/react/useQueryMode.ts
|
|
100
35
|
var import_react = require("react");
|
|
101
36
|
|
|
@@ -140,6 +75,11 @@ function hookReducer(state, action) {
|
|
|
140
75
|
}
|
|
141
76
|
}
|
|
142
77
|
|
|
78
|
+
// src/utils/generateTags.ts
|
|
79
|
+
function generateTags(path) {
|
|
80
|
+
return path.map((_, i) => path.slice(0, i + 1).join("/"));
|
|
81
|
+
}
|
|
82
|
+
|
|
143
83
|
// src/utils/sortObjectKeys.ts
|
|
144
84
|
function sortObjectKeys(obj) {
|
|
145
85
|
if (obj === null || typeof obj !== "object") return obj;
|
|
@@ -344,6 +284,38 @@ function useQueryMode(api, trackedCall, options) {
|
|
|
344
284
|
return state;
|
|
345
285
|
}
|
|
346
286
|
|
|
287
|
+
// src/react/types.ts
|
|
288
|
+
var HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
|
|
289
|
+
|
|
290
|
+
// src/react/trackingProxy.ts
|
|
291
|
+
function createTrackingProxy(onTrack) {
|
|
292
|
+
const createProxy = (path = []) => {
|
|
293
|
+
return new Proxy(() => {
|
|
294
|
+
}, {
|
|
295
|
+
get(_, prop) {
|
|
296
|
+
if (HTTP_METHODS.includes(prop)) {
|
|
297
|
+
const methodFn = (options) => {
|
|
298
|
+
onTrack({
|
|
299
|
+
trackedCall: { path, method: prop, options },
|
|
300
|
+
selectorPath: null,
|
|
301
|
+
selectorMethod: null
|
|
302
|
+
});
|
|
303
|
+
return Promise.resolve({ ok: true, data: void 0 });
|
|
304
|
+
};
|
|
305
|
+
onTrack({
|
|
306
|
+
trackedCall: null,
|
|
307
|
+
selectorPath: path,
|
|
308
|
+
selectorMethod: prop
|
|
309
|
+
});
|
|
310
|
+
return methodFn;
|
|
311
|
+
}
|
|
312
|
+
return createProxy([...path, prop]);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
};
|
|
316
|
+
return createProxy();
|
|
317
|
+
}
|
|
318
|
+
|
|
347
319
|
// src/react/useSelectorMode.ts
|
|
348
320
|
var import_react2 = require("react");
|
|
349
321
|
function resolvePath2(path, pathParams) {
|
|
@@ -411,47 +383,113 @@ function useSelectorMode(config) {
|
|
|
411
383
|
};
|
|
412
384
|
}
|
|
413
385
|
|
|
414
|
-
// src/react/
|
|
415
|
-
|
|
386
|
+
// src/react/createEnlaceHookReact.ts
|
|
387
|
+
function createEnlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
|
|
388
|
+
const {
|
|
389
|
+
autoGenerateTags = true,
|
|
390
|
+
autoRevalidateTags = true,
|
|
391
|
+
staleTime = 0,
|
|
392
|
+
onSuccess,
|
|
393
|
+
onError
|
|
394
|
+
} = hookOptions;
|
|
395
|
+
const api = (0, import_enlace_core.createEnlace)(baseUrl, defaultOptions, { onSuccess, onError });
|
|
396
|
+
function useEnlaceHook(selectorOrQuery, queryOptions) {
|
|
397
|
+
let trackingResult = {
|
|
398
|
+
trackedCall: null,
|
|
399
|
+
selectorPath: null,
|
|
400
|
+
selectorMethod: null
|
|
401
|
+
};
|
|
402
|
+
const trackingProxy = createTrackingProxy((result2) => {
|
|
403
|
+
trackingResult = result2;
|
|
404
|
+
});
|
|
405
|
+
const result = selectorOrQuery(
|
|
406
|
+
trackingProxy
|
|
407
|
+
);
|
|
408
|
+
if (typeof result === "function") {
|
|
409
|
+
const actualResult = selectorOrQuery(api);
|
|
410
|
+
return useSelectorMode({
|
|
411
|
+
method: actualResult,
|
|
412
|
+
api,
|
|
413
|
+
path: trackingResult.selectorPath ?? [],
|
|
414
|
+
methodName: trackingResult.selectorMethod ?? "",
|
|
415
|
+
autoRevalidateTags
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
return useQueryMode(
|
|
419
|
+
api,
|
|
420
|
+
trackingResult.trackedCall,
|
|
421
|
+
{ autoGenerateTags, staleTime, enabled: queryOptions?.enabled ?? true }
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
return useEnlaceHook;
|
|
425
|
+
}
|
|
416
426
|
|
|
417
|
-
// src/
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
return createProxy([...path, prop]);
|
|
427
|
+
// src/next/index.ts
|
|
428
|
+
var import_enlace_core3 = require("enlace-core");
|
|
429
|
+
|
|
430
|
+
// src/next/fetch.ts
|
|
431
|
+
var import_enlace_core2 = require("enlace-core");
|
|
432
|
+
async function executeNextFetch(baseUrl, path, method, combinedOptions, requestOptions) {
|
|
433
|
+
const {
|
|
434
|
+
autoGenerateTags = true,
|
|
435
|
+
autoRevalidateTags = true,
|
|
436
|
+
revalidator,
|
|
437
|
+
onSuccess,
|
|
438
|
+
...coreOptions
|
|
439
|
+
} = combinedOptions;
|
|
440
|
+
const isGet = method === "GET";
|
|
441
|
+
const autoTags = generateTags(path);
|
|
442
|
+
const nextOnSuccess = (payload) => {
|
|
443
|
+
if (!isGet && !requestOptions?.skipRevalidator) {
|
|
444
|
+
const revalidateTags = requestOptions?.revalidateTags ?? (autoRevalidateTags ? autoTags : []);
|
|
445
|
+
const revalidatePaths = requestOptions?.revalidatePaths ?? [];
|
|
446
|
+
if (revalidateTags.length || revalidatePaths.length) {
|
|
447
|
+
revalidator?.(revalidateTags, revalidatePaths);
|
|
440
448
|
}
|
|
441
|
-
}
|
|
449
|
+
}
|
|
450
|
+
onSuccess?.(payload);
|
|
442
451
|
};
|
|
443
|
-
|
|
452
|
+
const nextRequestOptions = { ...requestOptions };
|
|
453
|
+
if (isGet) {
|
|
454
|
+
const tags = requestOptions?.tags ?? (autoGenerateTags ? autoTags : void 0);
|
|
455
|
+
const nextFetchOptions = {};
|
|
456
|
+
if (tags) {
|
|
457
|
+
nextFetchOptions.tags = tags;
|
|
458
|
+
}
|
|
459
|
+
if (requestOptions?.revalidate !== void 0) {
|
|
460
|
+
nextFetchOptions.revalidate = requestOptions.revalidate;
|
|
461
|
+
}
|
|
462
|
+
nextRequestOptions.next = nextFetchOptions;
|
|
463
|
+
}
|
|
464
|
+
return (0, import_enlace_core2.executeFetch)(
|
|
465
|
+
baseUrl,
|
|
466
|
+
path,
|
|
467
|
+
method,
|
|
468
|
+
{ ...coreOptions, onSuccess: nextOnSuccess },
|
|
469
|
+
nextRequestOptions
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/next/index.ts
|
|
474
|
+
function createEnlaceNext(baseUrl, defaultOptions = {}, nextOptions = {}) {
|
|
475
|
+
const combinedOptions = { ...defaultOptions, ...nextOptions };
|
|
476
|
+
return (0, import_enlace_core3.createProxyHandler)(
|
|
477
|
+
baseUrl,
|
|
478
|
+
combinedOptions,
|
|
479
|
+
[],
|
|
480
|
+
executeNextFetch
|
|
481
|
+
);
|
|
444
482
|
}
|
|
445
483
|
|
|
446
|
-
// src/next/
|
|
447
|
-
function
|
|
484
|
+
// src/next/createEnlaceHookNext.ts
|
|
485
|
+
function createEnlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
|
|
448
486
|
const {
|
|
449
487
|
autoGenerateTags = true,
|
|
450
488
|
autoRevalidateTags = true,
|
|
451
489
|
staleTime = 0,
|
|
452
490
|
...nextOptions
|
|
453
491
|
} = hookOptions;
|
|
454
|
-
const api =
|
|
492
|
+
const api = createEnlaceNext(baseUrl, defaultOptions, {
|
|
455
493
|
autoGenerateTags,
|
|
456
494
|
autoRevalidateTags,
|
|
457
495
|
...nextOptions
|