enlace 0.0.1-beta.14 → 0.0.1-beta.15
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 +32 -32
- package/dist/hook/index.d.mts +4 -4
- package/dist/hook/index.d.ts +4 -4
- package/dist/hook/index.js +2 -2
- package/dist/hook/index.mjs +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ Defining a schema is **recommended** for full type safety, but **optional**. You
|
|
|
42
42
|
```typescript
|
|
43
43
|
// Without schema (untyped, but still works!)
|
|
44
44
|
const useAPI = enlaceHookReact("https://api.example.com");
|
|
45
|
-
const { data } = useAPI((api) => api.any.path.you.want
|
|
45
|
+
const { data } = useAPI((api) => api.any.path.you.want.$get());
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
```typescript
|
|
@@ -80,9 +80,9 @@ type ApiSchema = {
|
|
|
80
80
|
const api = enlace<ApiSchema, ApiError>("https://api.example.com");
|
|
81
81
|
|
|
82
82
|
// Usage
|
|
83
|
-
api.users
|
|
84
|
-
api.users[123]
|
|
85
|
-
api.users[123].profile
|
|
83
|
+
api.users.$get(); // GET /users
|
|
84
|
+
api.users[123].$get(); // GET /users/123
|
|
85
|
+
api.users[123].profile.$get(); // GET /users/123/profile
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
### Endpoint Types
|
|
@@ -124,8 +124,8 @@ type ApiSchema = {
|
|
|
124
124
|
};
|
|
125
125
|
|
|
126
126
|
// Usage - query params are fully typed
|
|
127
|
-
const { data } = useAPI((api) => api.users
|
|
128
|
-
// api.users
|
|
127
|
+
const { data } = useAPI((api) => api.users.$get({ query: { page: 1, limit: 10 } }));
|
|
128
|
+
// api.users.$get({ query: { foo: "bar" } }); // ✗ Error: 'foo' does not exist
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
#### `EndpointWithFormData<TData, TFormData, TError?>`
|
|
@@ -145,7 +145,7 @@ type ApiSchema = {
|
|
|
145
145
|
};
|
|
146
146
|
|
|
147
147
|
// Usage - formData is automatically converted to FormData
|
|
148
|
-
const { trigger } = useAPI((api) => api.uploads
|
|
148
|
+
const { trigger } = useAPI((api) => api.uploads.$post);
|
|
149
149
|
trigger({
|
|
150
150
|
formData: {
|
|
151
151
|
file: selectedFile, // File object
|
|
@@ -211,7 +211,7 @@ For GET requests that fetch data automatically:
|
|
|
211
211
|
```typescript
|
|
212
212
|
function Posts({ page, limit }: { page: number; limit: number }) {
|
|
213
213
|
const { data, loading, error } = useAPI((api) =>
|
|
214
|
-
api.posts
|
|
214
|
+
api.posts.$get({ query: { page, limit, published: true } })
|
|
215
215
|
);
|
|
216
216
|
|
|
217
217
|
if (loading) return <div>Loading...</div>;
|
|
@@ -242,7 +242,7 @@ Skip fetching with the `enabled` option:
|
|
|
242
242
|
function ProductForm({ id }: { id: string | "new" }) {
|
|
243
243
|
// Skip fetching when creating a new product
|
|
244
244
|
const { data, loading } = useAPI(
|
|
245
|
-
(api) => api.products[id]
|
|
245
|
+
(api) => api.products[id].$get(),
|
|
246
246
|
{ enabled: id !== "new" }
|
|
247
247
|
);
|
|
248
248
|
|
|
@@ -255,7 +255,7 @@ function ProductForm({ id }: { id: string | "new" }) {
|
|
|
255
255
|
```typescript
|
|
256
256
|
// Also useful when waiting for a dependency
|
|
257
257
|
function UserPosts({ userId }: { userId: string | undefined }) {
|
|
258
|
-
const { data } = useAPI((api) => api.users[userId!].posts
|
|
258
|
+
const { data } = useAPI((api) => api.users[userId!].posts.$get(), {
|
|
259
259
|
enabled: userId !== undefined,
|
|
260
260
|
});
|
|
261
261
|
}
|
|
@@ -264,7 +264,7 @@ function UserPosts({ userId }: { userId: string | undefined }) {
|
|
|
264
264
|
```typescript
|
|
265
265
|
function Post({ id }: { id: number }) {
|
|
266
266
|
// Automatically re-fetches when `id` or query values change
|
|
267
|
-
const { data } = useAPI((api) => api.posts[id]
|
|
267
|
+
const { data } = useAPI((api) => api.posts[id].$get({ query: { include: "author" } }));
|
|
268
268
|
return <div>{data?.title}</div>;
|
|
269
269
|
}
|
|
270
270
|
```
|
|
@@ -276,7 +276,7 @@ Automatically refetch data at intervals using the `pollingInterval` option. Poll
|
|
|
276
276
|
```typescript
|
|
277
277
|
function Notifications() {
|
|
278
278
|
const { data } = useAPI(
|
|
279
|
-
(api) => api.notifications
|
|
279
|
+
(api) => api.notifications.$get(),
|
|
280
280
|
{ pollingInterval: 5000 } // Refetch every 5 seconds after previous request completes
|
|
281
281
|
);
|
|
282
282
|
|
|
@@ -299,7 +299,7 @@ Use a function to conditionally poll based on the response data or error:
|
|
|
299
299
|
```typescript
|
|
300
300
|
function OrderStatus({ orderId }: { orderId: string }) {
|
|
301
301
|
const { data } = useAPI(
|
|
302
|
-
(api) => api.orders[orderId]
|
|
302
|
+
(api) => api.orders[orderId].$get(),
|
|
303
303
|
{
|
|
304
304
|
// Poll every 2s while pending, stop when completed
|
|
305
305
|
pollingInterval: (order) => order?.status === "pending" ? 2000 : false,
|
|
@@ -327,7 +327,7 @@ The function receives `(data, error)` and should return:
|
|
|
327
327
|
```typescript
|
|
328
328
|
function OrderStatus({ orderId }: { orderId: string | undefined }) {
|
|
329
329
|
const { data } = useAPI(
|
|
330
|
-
(api) => api.orders[orderId!]
|
|
330
|
+
(api) => api.orders[orderId!].$get(),
|
|
331
331
|
{
|
|
332
332
|
enabled: !!orderId,
|
|
333
333
|
pollingInterval: 10000, // Poll every 10 seconds
|
|
@@ -344,12 +344,12 @@ Multiple components requesting the same data will share a single network request
|
|
|
344
344
|
```typescript
|
|
345
345
|
// Both components render at the same time
|
|
346
346
|
function PostTitle({ id }: { id: number }) {
|
|
347
|
-
const { data } = useAPI((api) => api.posts[id]
|
|
347
|
+
const { data } = useAPI((api) => api.posts[id].$get());
|
|
348
348
|
return <h1>{data?.title}</h1>;
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
function PostBody({ id }: { id: number }) {
|
|
352
|
-
const { data } = useAPI((api) => api.posts[id]
|
|
352
|
+
const { data } = useAPI((api) => api.posts[id].$get());
|
|
353
353
|
return <p>{data?.body}</p>;
|
|
354
354
|
}
|
|
355
355
|
|
|
@@ -371,7 +371,7 @@ For mutations or lazy-loaded requests:
|
|
|
371
371
|
|
|
372
372
|
```typescript
|
|
373
373
|
function DeleteButton({ id }: { id: number }) {
|
|
374
|
-
const { trigger, loading } = useAPI((api) => api.posts[id]
|
|
374
|
+
const { trigger, loading } = useAPI((api) => api.posts[id].$delete);
|
|
375
375
|
|
|
376
376
|
return (
|
|
377
377
|
<button onClick={() => trigger()} disabled={loading}>
|
|
@@ -385,7 +385,7 @@ function DeleteButton({ id }: { id: number }) {
|
|
|
385
385
|
|
|
386
386
|
```typescript
|
|
387
387
|
function CreatePost() {
|
|
388
|
-
const { trigger, loading, data } = useAPI((api) => api.posts
|
|
388
|
+
const { trigger, loading, data } = useAPI((api) => api.posts.$post);
|
|
389
389
|
|
|
390
390
|
const handleSubmit = async (title: string) => {
|
|
391
391
|
const result = await trigger({ body: { title } });
|
|
@@ -405,7 +405,7 @@ Use `:paramName` syntax for dynamic IDs passed at trigger time:
|
|
|
405
405
|
```typescript
|
|
406
406
|
function PostList({ posts }: { posts: Post[] }) {
|
|
407
407
|
// Define once with :id placeholder
|
|
408
|
-
const { trigger, loading } = useAPI((api) => api.posts[":id"]
|
|
408
|
+
const { trigger, loading } = useAPI((api) => api.posts[":id"].$delete);
|
|
409
409
|
|
|
410
410
|
const handleDelete = (postId: number) => {
|
|
411
411
|
// Pass the actual ID when triggering
|
|
@@ -431,7 +431,7 @@ function PostList({ posts }: { posts: Post[] }) {
|
|
|
431
431
|
|
|
432
432
|
```typescript
|
|
433
433
|
const { trigger } = useAPI(
|
|
434
|
-
(api) => api.users[":userId"].posts[":postId"]
|
|
434
|
+
(api) => api.users[":userId"].posts[":postId"].$delete
|
|
435
435
|
);
|
|
436
436
|
|
|
437
437
|
trigger({ params: { userId: "1", postId: "42" } });
|
|
@@ -441,7 +441,7 @@ trigger({ params: { userId: "1", postId: "42" } });
|
|
|
441
441
|
**With request body:**
|
|
442
442
|
|
|
443
443
|
```typescript
|
|
444
|
-
const { trigger } = useAPI((api) => api.products[":id"]
|
|
444
|
+
const { trigger } = useAPI((api) => api.products[":id"].$patch);
|
|
445
445
|
|
|
446
446
|
trigger({
|
|
447
447
|
params: { id: "123" },
|
|
@@ -465,7 +465,7 @@ trigger({
|
|
|
465
465
|
**Mutations automatically revalidate matching tags:**
|
|
466
466
|
|
|
467
467
|
```typescript
|
|
468
|
-
const { trigger } = useAPI((api) => api.posts
|
|
468
|
+
const { trigger } = useAPI((api) => api.posts.$post);
|
|
469
469
|
|
|
470
470
|
// POST /posts automatically revalidates 'posts' tag
|
|
471
471
|
// All queries with 'posts' tag will refetch!
|
|
@@ -482,10 +482,10 @@ This means in most cases, **you don't need to specify any tags manually**. The c
|
|
|
482
482
|
|
|
483
483
|
```typescript
|
|
484
484
|
// Component A: fetches posts (cached with tag 'posts')
|
|
485
|
-
const { data } = useAPI((api) => api.posts
|
|
485
|
+
const { data } = useAPI((api) => api.posts.$get());
|
|
486
486
|
|
|
487
487
|
// Component B: creates a post
|
|
488
|
-
const { trigger } = useAPI((api) => api.posts
|
|
488
|
+
const { trigger } = useAPI((api) => api.posts.$post);
|
|
489
489
|
trigger({ body: { title: "New" } });
|
|
490
490
|
// → Automatically revalidates 'posts' tag
|
|
491
491
|
// → Component A refetches automatically!
|
|
@@ -515,7 +515,7 @@ Override auto-generated tags when needed:
|
|
|
515
515
|
|
|
516
516
|
```typescript
|
|
517
517
|
// Custom cache tags
|
|
518
|
-
const { data } = useAPI((api) => api.posts
|
|
518
|
+
const { data } = useAPI((api) => api.posts.$get({ tags: ["my-custom-tag"] }));
|
|
519
519
|
|
|
520
520
|
// Custom revalidation tags
|
|
521
521
|
trigger({
|
|
@@ -583,7 +583,7 @@ This also works for per-request headers:
|
|
|
583
583
|
|
|
584
584
|
```typescript
|
|
585
585
|
const { data } = useAPI((api) =>
|
|
586
|
-
api.posts
|
|
586
|
+
api.posts.$get({
|
|
587
587
|
headers: async () => {
|
|
588
588
|
const token = await refreshToken();
|
|
589
589
|
return { Authorization: `Bearer ${token}` };
|
|
@@ -648,11 +648,11 @@ type EnlaceErrorCallbackPayload<T> =
|
|
|
648
648
|
|
|
649
649
|
```typescript
|
|
650
650
|
// Basic usage
|
|
651
|
-
const result = useAPI((api) => api.posts
|
|
651
|
+
const result = useAPI((api) => api.posts.$get());
|
|
652
652
|
|
|
653
653
|
// With options
|
|
654
654
|
const result = useAPI(
|
|
655
|
-
(api) => api.posts
|
|
655
|
+
(api) => api.posts.$get(),
|
|
656
656
|
{
|
|
657
657
|
enabled: true, // Skip fetching when false
|
|
658
658
|
pollingInterval: 5000 // Refetch every 5s after previous request completes
|
|
@@ -661,7 +661,7 @@ const result = useAPI(
|
|
|
661
661
|
|
|
662
662
|
// With dynamic polling
|
|
663
663
|
const result = useAPI(
|
|
664
|
-
(api) => api.orders[id]
|
|
664
|
+
(api) => api.orders[id].$get(),
|
|
665
665
|
{
|
|
666
666
|
pollingInterval: (order) => order?.status === "pending" ? 2000 : false
|
|
667
667
|
}
|
|
@@ -731,7 +731,7 @@ const api = enlaceNext<ApiSchema, ApiError>("https://api.example.com", {}, {
|
|
|
731
731
|
});
|
|
732
732
|
|
|
733
733
|
export default async function Page() {
|
|
734
|
-
const { data } = await api.posts
|
|
734
|
+
const { data } = await api.posts.$get({
|
|
735
735
|
revalidate: 60, // ISR: revalidate every 60 seconds
|
|
736
736
|
});
|
|
737
737
|
|
|
@@ -795,7 +795,7 @@ const useAPI = enlaceHookNext<ApiSchema, ApiError>(
|
|
|
795
795
|
|
|
796
796
|
```typescript
|
|
797
797
|
function CreatePost() {
|
|
798
|
-
const { trigger } = useAPI((api) => api.posts
|
|
798
|
+
const { trigger } = useAPI((api) => api.posts.$post);
|
|
799
799
|
|
|
800
800
|
const handleCreate = () => {
|
|
801
801
|
trigger({
|
|
@@ -843,7 +843,7 @@ await trigger({ body: data, serverRevalidate: true });
|
|
|
843
843
|
### Next.js Request Options
|
|
844
844
|
|
|
845
845
|
```typescript
|
|
846
|
-
api.posts
|
|
846
|
+
api.posts.$get({
|
|
847
847
|
tags: ["posts"], // Next.js cache tags
|
|
848
848
|
revalidate: 60, // ISR revalidation (seconds)
|
|
849
849
|
revalidateTags: ["posts"], // Tags to invalidate after mutation
|
package/dist/hook/index.d.mts
CHANGED
|
@@ -121,10 +121,10 @@ type EnlaceHook<TSchema, TDefaultError = unknown> = {
|
|
|
121
121
|
* const useAPI = enlaceHookReact<ApiSchema>('https://api.com');
|
|
122
122
|
*
|
|
123
123
|
* // Query mode - auto-fetch (auto-tracks changes, no deps array needed)
|
|
124
|
-
* const { loading, data, error } = useAPI((api) => api.posts
|
|
124
|
+
* const { loading, data, error } = useAPI((api) => api.posts.$get({ query: { userId } }));
|
|
125
125
|
*
|
|
126
126
|
* // Selector mode - typed trigger for lazy calls
|
|
127
|
-
* const { trigger, loading, data, error } = useAPI((api) => api.posts
|
|
127
|
+
* const { trigger, loading, data, error } = useAPI((api) => api.posts.$delete);
|
|
128
128
|
* onClick={() => trigger({ body: { id: 1 } })}
|
|
129
129
|
*/
|
|
130
130
|
declare function enlaceHookReact<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema, TDefaultError>;
|
|
@@ -194,10 +194,10 @@ type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
|
|
|
194
194
|
* });
|
|
195
195
|
*
|
|
196
196
|
* // Query mode - auto-fetch
|
|
197
|
-
* const { loading, data, error } = useAPI((api) => api.posts
|
|
197
|
+
* const { loading, data, error } = useAPI((api) => api.posts.$get());
|
|
198
198
|
*
|
|
199
199
|
* // Selector mode - trigger for mutations
|
|
200
|
-
* const { trigger } = useAPI((api) => api.posts
|
|
200
|
+
* const { trigger } = useAPI((api) => api.posts.$delete);
|
|
201
201
|
*/
|
|
202
202
|
declare function enlaceHookNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema, TDefaultError>;
|
|
203
203
|
|
package/dist/hook/index.d.ts
CHANGED
|
@@ -121,10 +121,10 @@ type EnlaceHook<TSchema, TDefaultError = unknown> = {
|
|
|
121
121
|
* const useAPI = enlaceHookReact<ApiSchema>('https://api.com');
|
|
122
122
|
*
|
|
123
123
|
* // Query mode - auto-fetch (auto-tracks changes, no deps array needed)
|
|
124
|
-
* const { loading, data, error } = useAPI((api) => api.posts
|
|
124
|
+
* const { loading, data, error } = useAPI((api) => api.posts.$get({ query: { userId } }));
|
|
125
125
|
*
|
|
126
126
|
* // Selector mode - typed trigger for lazy calls
|
|
127
|
-
* const { trigger, loading, data, error } = useAPI((api) => api.posts
|
|
127
|
+
* const { trigger, loading, data, error } = useAPI((api) => api.posts.$delete);
|
|
128
128
|
* onClick={() => trigger({ body: { id: 1 } })}
|
|
129
129
|
*/
|
|
130
130
|
declare function enlaceHookReact<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: EnlaceHookOptions): EnlaceHook<TSchema, TDefaultError>;
|
|
@@ -194,10 +194,10 @@ type NextEnlaceHook<TSchema, TDefaultError = unknown> = {
|
|
|
194
194
|
* });
|
|
195
195
|
*
|
|
196
196
|
* // Query mode - auto-fetch
|
|
197
|
-
* const { loading, data, error } = useAPI((api) => api.posts
|
|
197
|
+
* const { loading, data, error } = useAPI((api) => api.posts.$get());
|
|
198
198
|
*
|
|
199
199
|
* // Selector mode - trigger for mutations
|
|
200
|
-
* const { trigger } = useAPI((api) => api.posts
|
|
200
|
+
* const { trigger } = useAPI((api) => api.posts.$delete);
|
|
201
201
|
*/
|
|
202
202
|
declare function enlaceHookNext<TSchema = unknown, TDefaultError = unknown>(baseUrl: string, defaultOptions?: EnlaceOptions, hookOptions?: NextHookOptions): NextEnlaceHook<TSchema, TDefaultError>;
|
|
203
203
|
|
package/dist/hook/index.js
CHANGED
|
@@ -462,7 +462,7 @@ function enlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
|
|
|
462
462
|
}
|
|
463
463
|
if (!trackingResult.trackedCall) {
|
|
464
464
|
throw new Error(
|
|
465
|
-
"useAPI query mode requires calling an HTTP method (get, post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts
|
|
465
|
+
"useAPI query mode requires calling an HTTP method ($get, $post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts.$get())"
|
|
466
466
|
);
|
|
467
467
|
}
|
|
468
468
|
return useQueryMode(
|
|
@@ -579,7 +579,7 @@ function enlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
|
|
|
579
579
|
}
|
|
580
580
|
if (!trackedCall) {
|
|
581
581
|
throw new Error(
|
|
582
|
-
"useAPI query mode requires calling an HTTP method (get, post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts
|
|
582
|
+
"useAPI query mode requires calling an HTTP method ($get, $post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts.$get())"
|
|
583
583
|
);
|
|
584
584
|
}
|
|
585
585
|
return useQueryMode(
|
package/dist/hook/index.mjs
CHANGED
|
@@ -437,7 +437,7 @@ function enlaceHookReact(baseUrl, defaultOptions = {}, hookOptions = {}) {
|
|
|
437
437
|
}
|
|
438
438
|
if (!trackingResult.trackedCall) {
|
|
439
439
|
throw new Error(
|
|
440
|
-
"useAPI query mode requires calling an HTTP method (get, post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts
|
|
440
|
+
"useAPI query mode requires calling an HTTP method ($get, $post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts.$get())"
|
|
441
441
|
);
|
|
442
442
|
}
|
|
443
443
|
return useQueryMode(
|
|
@@ -558,7 +558,7 @@ function enlaceHookNext(baseUrl, defaultOptions = {}, hookOptions = {}) {
|
|
|
558
558
|
}
|
|
559
559
|
if (!trackedCall) {
|
|
560
560
|
throw new Error(
|
|
561
|
-
"useAPI query mode requires calling an HTTP method (get, post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts
|
|
561
|
+
"useAPI query mode requires calling an HTTP method ($get, $post, etc.). Did you mean to use selector mode? Example: useAPI((api) => api.posts.$get())"
|
|
562
562
|
);
|
|
563
563
|
}
|
|
564
564
|
return useQueryMode(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "enlace",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.15",
|
|
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.
|
|
21
|
+
"enlace-core": "0.0.1-beta.10"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"react": "^19"
|