enlace 0.0.1-beta.14 → 0.0.1-beta.16
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 +96 -73
- 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
|
@@ -30,9 +30,7 @@ type ApiSchema = {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
// Pass global error type as second generic
|
|
33
|
-
const useAPI = enlaceHookReact<ApiSchema, ApiError>(
|
|
34
|
-
"https://api.example.com"
|
|
35
|
-
);
|
|
33
|
+
const useAPI = enlaceHookReact<ApiSchema, ApiError>("https://api.example.com");
|
|
36
34
|
```
|
|
37
35
|
|
|
38
36
|
## Schema Conventions
|
|
@@ -42,7 +40,7 @@ Defining a schema is **recommended** for full type safety, but **optional**. You
|
|
|
42
40
|
```typescript
|
|
43
41
|
// Without schema (untyped, but still works!)
|
|
44
42
|
const useAPI = enlaceHookReact("https://api.example.com");
|
|
45
|
-
const { data } = useAPI((api) => api.any.path.you.want
|
|
43
|
+
const { data } = useAPI((api) => api.any.path.you.want.$get());
|
|
46
44
|
```
|
|
47
45
|
|
|
48
46
|
```typescript
|
|
@@ -80,9 +78,9 @@ type ApiSchema = {
|
|
|
80
78
|
const api = enlace<ApiSchema, ApiError>("https://api.example.com");
|
|
81
79
|
|
|
82
80
|
// Usage
|
|
83
|
-
api.users
|
|
84
|
-
api.users[123]
|
|
85
|
-
api.users[123].profile
|
|
81
|
+
api.users.$get(); // GET /users
|
|
82
|
+
api.users[123].$get(); // GET /users/123
|
|
83
|
+
api.users[123].profile.$get(); // GET /users/123/profile
|
|
86
84
|
```
|
|
87
85
|
|
|
88
86
|
### Endpoint Types
|
|
@@ -98,11 +96,11 @@ import { Endpoint } from "enlace";
|
|
|
98
96
|
|
|
99
97
|
type ApiSchema = {
|
|
100
98
|
posts: {
|
|
101
|
-
$get: Post[];
|
|
102
|
-
$post: Endpoint<Post, CreatePost>;
|
|
99
|
+
$get: Post[]; // Direct type (simplest)
|
|
100
|
+
$post: Endpoint<Post, CreatePost>; // Data + Body
|
|
103
101
|
$put: Endpoint<Post, UpdatePost, ValidationError>; // Data + Body + Error
|
|
104
|
-
$delete: void;
|
|
105
|
-
$patch: Endpoint<Post, never, NotFoundError>;
|
|
102
|
+
$delete: void; // void response
|
|
103
|
+
$patch: Endpoint<Post, never, NotFoundError>; // Custom error without body
|
|
106
104
|
};
|
|
107
105
|
};
|
|
108
106
|
```
|
|
@@ -116,16 +114,25 @@ import { EndpointWithQuery } from "enlace";
|
|
|
116
114
|
|
|
117
115
|
type ApiSchema = {
|
|
118
116
|
users: {
|
|
119
|
-
$get: EndpointWithQuery<
|
|
117
|
+
$get: EndpointWithQuery<
|
|
118
|
+
User[],
|
|
119
|
+
{ page: number; limit: number; search?: string }
|
|
120
|
+
>;
|
|
120
121
|
};
|
|
121
122
|
posts: {
|
|
122
|
-
$get: EndpointWithQuery<
|
|
123
|
+
$get: EndpointWithQuery<
|
|
124
|
+
Post[],
|
|
125
|
+
{ status: "draft" | "published" },
|
|
126
|
+
ApiError
|
|
127
|
+
>;
|
|
123
128
|
};
|
|
124
129
|
};
|
|
125
130
|
|
|
126
131
|
// Usage - query params are fully typed
|
|
127
|
-
const { data } = useAPI((api) =>
|
|
128
|
-
|
|
132
|
+
const { data } = useAPI((api) =>
|
|
133
|
+
api.users.$get({ query: { page: 1, limit: 10 } })
|
|
134
|
+
);
|
|
135
|
+
// api.users.$get({ query: { foo: "bar" } }); // ✗ Error: 'foo' does not exist
|
|
129
136
|
```
|
|
130
137
|
|
|
131
138
|
#### `EndpointWithFormData<TData, TFormData, TError?>`
|
|
@@ -145,25 +152,25 @@ type ApiSchema = {
|
|
|
145
152
|
};
|
|
146
153
|
|
|
147
154
|
// Usage - formData is automatically converted to FormData
|
|
148
|
-
const { trigger } = useAPI((api) => api.uploads
|
|
155
|
+
const { trigger } = useAPI((api) => api.uploads.$post);
|
|
149
156
|
trigger({
|
|
150
157
|
formData: {
|
|
151
|
-
file: selectedFile,
|
|
152
|
-
name: "document.pdf",
|
|
153
|
-
}
|
|
158
|
+
file: selectedFile, // File object
|
|
159
|
+
name: "document.pdf", // String - converted automatically
|
|
160
|
+
},
|
|
154
161
|
});
|
|
155
162
|
// → Sends as multipart/form-data
|
|
156
163
|
```
|
|
157
164
|
|
|
158
165
|
**FormData conversion rules:**
|
|
159
166
|
|
|
160
|
-
| Type
|
|
161
|
-
|
|
162
|
-
| `File` / `Blob`
|
|
163
|
-
| `string` / `number` / `boolean` | Converted to string
|
|
164
|
-
| `object` (nested)
|
|
165
|
-
| `array` of primitives
|
|
166
|
-
| `array` of files
|
|
167
|
+
| Type | Conversion |
|
|
168
|
+
| ------------------------------- | -------------------------------- |
|
|
169
|
+
| `File` / `Blob` | Appended directly |
|
|
170
|
+
| `string` / `number` / `boolean` | Converted to string |
|
|
171
|
+
| `object` (nested) | JSON stringified |
|
|
172
|
+
| `array` of primitives | Each item appended separately |
|
|
173
|
+
| `array` of files | Each file appended with same key |
|
|
167
174
|
|
|
168
175
|
#### `EndpointFull<T>`
|
|
169
176
|
|
|
@@ -211,7 +218,7 @@ For GET requests that fetch data automatically:
|
|
|
211
218
|
```typescript
|
|
212
219
|
function Posts({ page, limit }: { page: number; limit: number }) {
|
|
213
220
|
const { data, loading, error } = useAPI((api) =>
|
|
214
|
-
api.posts
|
|
221
|
+
api.posts.$get({ query: { page, limit, published: true } })
|
|
215
222
|
);
|
|
216
223
|
|
|
217
224
|
if (loading) return <div>Loading...</div>;
|
|
@@ -242,7 +249,7 @@ Skip fetching with the `enabled` option:
|
|
|
242
249
|
function ProductForm({ id }: { id: string | "new" }) {
|
|
243
250
|
// Skip fetching when creating a new product
|
|
244
251
|
const { data, loading } = useAPI(
|
|
245
|
-
(api) => api.products[id]
|
|
252
|
+
(api) => api.products[id].$get(),
|
|
246
253
|
{ enabled: id !== "new" }
|
|
247
254
|
);
|
|
248
255
|
|
|
@@ -255,7 +262,7 @@ function ProductForm({ id }: { id: string | "new" }) {
|
|
|
255
262
|
```typescript
|
|
256
263
|
// Also useful when waiting for a dependency
|
|
257
264
|
function UserPosts({ userId }: { userId: string | undefined }) {
|
|
258
|
-
const { data } = useAPI((api) => api.users[userId!].posts
|
|
265
|
+
const { data } = useAPI((api) => api.users[userId!].posts.$get(), {
|
|
259
266
|
enabled: userId !== undefined,
|
|
260
267
|
});
|
|
261
268
|
}
|
|
@@ -264,7 +271,7 @@ function UserPosts({ userId }: { userId: string | undefined }) {
|
|
|
264
271
|
```typescript
|
|
265
272
|
function Post({ id }: { id: number }) {
|
|
266
273
|
// Automatically re-fetches when `id` or query values change
|
|
267
|
-
const { data } = useAPI((api) => api.posts[id]
|
|
274
|
+
const { data } = useAPI((api) => api.posts[id].$get({ query: { include: "author" } }));
|
|
268
275
|
return <div>{data?.title}</div>;
|
|
269
276
|
}
|
|
270
277
|
```
|
|
@@ -276,7 +283,7 @@ Automatically refetch data at intervals using the `pollingInterval` option. Poll
|
|
|
276
283
|
```typescript
|
|
277
284
|
function Notifications() {
|
|
278
285
|
const { data } = useAPI(
|
|
279
|
-
(api) => api.notifications
|
|
286
|
+
(api) => api.notifications.$get(),
|
|
280
287
|
{ pollingInterval: 5000 } // Refetch every 5 seconds after previous request completes
|
|
281
288
|
);
|
|
282
289
|
|
|
@@ -299,7 +306,7 @@ Use a function to conditionally poll based on the response data or error:
|
|
|
299
306
|
```typescript
|
|
300
307
|
function OrderStatus({ orderId }: { orderId: string }) {
|
|
301
308
|
const { data } = useAPI(
|
|
302
|
-
(api) => api.orders[orderId]
|
|
309
|
+
(api) => api.orders[orderId].$get(),
|
|
303
310
|
{
|
|
304
311
|
// Poll every 2s while pending, stop when completed
|
|
305
312
|
pollingInterval: (order) => order?.status === "pending" ? 2000 : false,
|
|
@@ -311,28 +318,30 @@ function OrderStatus({ orderId }: { orderId: string }) {
|
|
|
311
318
|
```
|
|
312
319
|
|
|
313
320
|
The function receives `(data, error)` and should return:
|
|
321
|
+
|
|
314
322
|
- `number`: Interval in milliseconds
|
|
315
323
|
- `false`: Stop polling
|
|
316
324
|
|
|
317
325
|
```typescript
|
|
318
326
|
// Poll faster when there's an error (retry), slower otherwise
|
|
319
|
-
{
|
|
327
|
+
{
|
|
328
|
+
pollingInterval: (data, error) => (error ? 1000 : 10000);
|
|
329
|
+
}
|
|
320
330
|
|
|
321
331
|
// Stop polling once data meets a condition
|
|
322
|
-
{
|
|
332
|
+
{
|
|
333
|
+
pollingInterval: (order) => (order?.status === "completed" ? false : 3000);
|
|
334
|
+
}
|
|
323
335
|
```
|
|
324
336
|
|
|
325
337
|
**Combined with conditional fetching:**
|
|
326
338
|
|
|
327
339
|
```typescript
|
|
328
340
|
function OrderStatus({ orderId }: { orderId: string | undefined }) {
|
|
329
|
-
const { data } = useAPI(
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
pollingInterval: 10000, // Poll every 10 seconds
|
|
334
|
-
}
|
|
335
|
-
);
|
|
341
|
+
const { data } = useAPI((api) => api.orders[orderId!].$get(), {
|
|
342
|
+
enabled: !!orderId,
|
|
343
|
+
pollingInterval: 10000, // Poll every 10 seconds
|
|
344
|
+
});
|
|
336
345
|
// Polling only runs when orderId is defined
|
|
337
346
|
}
|
|
338
347
|
```
|
|
@@ -344,12 +353,12 @@ Multiple components requesting the same data will share a single network request
|
|
|
344
353
|
```typescript
|
|
345
354
|
// Both components render at the same time
|
|
346
355
|
function PostTitle({ id }: { id: number }) {
|
|
347
|
-
const { data } = useAPI((api) => api.posts[id]
|
|
356
|
+
const { data } = useAPI((api) => api.posts[id].$get());
|
|
348
357
|
return <h1>{data?.title}</h1>;
|
|
349
358
|
}
|
|
350
359
|
|
|
351
360
|
function PostBody({ id }: { id: number }) {
|
|
352
|
-
const { data } = useAPI((api) => api.posts[id]
|
|
361
|
+
const { data } = useAPI((api) => api.posts[id].$get());
|
|
353
362
|
return <p>{data?.body}</p>;
|
|
354
363
|
}
|
|
355
364
|
|
|
@@ -371,7 +380,7 @@ For mutations or lazy-loaded requests:
|
|
|
371
380
|
|
|
372
381
|
```typescript
|
|
373
382
|
function DeleteButton({ id }: { id: number }) {
|
|
374
|
-
const { trigger, loading } = useAPI((api) => api.posts[id]
|
|
383
|
+
const { trigger, loading } = useAPI((api) => api.posts[id].$delete);
|
|
375
384
|
|
|
376
385
|
return (
|
|
377
386
|
<button onClick={() => trigger()} disabled={loading}>
|
|
@@ -385,7 +394,7 @@ function DeleteButton({ id }: { id: number }) {
|
|
|
385
394
|
|
|
386
395
|
```typescript
|
|
387
396
|
function CreatePost() {
|
|
388
|
-
const { trigger, loading, data } = useAPI((api) => api.posts
|
|
397
|
+
const { trigger, loading, data } = useAPI((api) => api.posts.$post);
|
|
389
398
|
|
|
390
399
|
const handleSubmit = async (title: string) => {
|
|
391
400
|
const result = await trigger({ body: { title } });
|
|
@@ -405,7 +414,7 @@ Use `:paramName` syntax for dynamic IDs passed at trigger time:
|
|
|
405
414
|
```typescript
|
|
406
415
|
function PostList({ posts }: { posts: Post[] }) {
|
|
407
416
|
// Define once with :id placeholder
|
|
408
|
-
const { trigger, loading } = useAPI((api) => api.posts[":id"]
|
|
417
|
+
const { trigger, loading } = useAPI((api) => api.posts[":id"].$delete);
|
|
409
418
|
|
|
410
419
|
const handleDelete = (postId: number) => {
|
|
411
420
|
// Pass the actual ID when triggering
|
|
@@ -431,7 +440,7 @@ function PostList({ posts }: { posts: Post[] }) {
|
|
|
431
440
|
|
|
432
441
|
```typescript
|
|
433
442
|
const { trigger } = useAPI(
|
|
434
|
-
(api) => api.users[":userId"].posts[":postId"]
|
|
443
|
+
(api) => api.users[":userId"].posts[":postId"].$delete
|
|
435
444
|
);
|
|
436
445
|
|
|
437
446
|
trigger({ params: { userId: "1", postId: "42" } });
|
|
@@ -441,7 +450,7 @@ trigger({ params: { userId: "1", postId: "42" } });
|
|
|
441
450
|
**With request body:**
|
|
442
451
|
|
|
443
452
|
```typescript
|
|
444
|
-
const { trigger } = useAPI((api) => api.products[":id"]
|
|
453
|
+
const { trigger } = useAPI((api) => api.products[":id"].$patch);
|
|
445
454
|
|
|
446
455
|
trigger({
|
|
447
456
|
params: { id: "123" },
|
|
@@ -465,7 +474,7 @@ trigger({
|
|
|
465
474
|
**Mutations automatically revalidate matching tags:**
|
|
466
475
|
|
|
467
476
|
```typescript
|
|
468
|
-
const { trigger } = useAPI((api) => api.posts
|
|
477
|
+
const { trigger } = useAPI((api) => api.posts.$post);
|
|
469
478
|
|
|
470
479
|
// POST /posts automatically revalidates 'posts' tag
|
|
471
480
|
// All queries with 'posts' tag will refetch!
|
|
@@ -482,10 +491,10 @@ This means in most cases, **you don't need to specify any tags manually**. The c
|
|
|
482
491
|
|
|
483
492
|
```typescript
|
|
484
493
|
// Component A: fetches posts (cached with tag 'posts')
|
|
485
|
-
const { data } = useAPI((api) => api.posts
|
|
494
|
+
const { data } = useAPI((api) => api.posts.$get());
|
|
486
495
|
|
|
487
496
|
// Component B: creates a post
|
|
488
|
-
const { trigger } = useAPI((api) => api.posts
|
|
497
|
+
const { trigger } = useAPI((api) => api.posts.$post);
|
|
489
498
|
trigger({ body: { title: "New" } });
|
|
490
499
|
// → Automatically revalidates 'posts' tag
|
|
491
500
|
// → Component A refetches automatically!
|
|
@@ -515,7 +524,7 @@ Override auto-generated tags when needed:
|
|
|
515
524
|
|
|
516
525
|
```typescript
|
|
517
526
|
// Custom cache tags
|
|
518
|
-
const { data } = useAPI((api) => api.posts
|
|
527
|
+
const { data } = useAPI((api) => api.posts.$get({ tags: ["my-custom-tag"] }));
|
|
519
528
|
|
|
520
529
|
// Custom revalidation tags
|
|
521
530
|
trigger({
|
|
@@ -583,7 +592,7 @@ This also works for per-request headers:
|
|
|
583
592
|
|
|
584
593
|
```typescript
|
|
585
594
|
const { data } = useAPI((api) =>
|
|
586
|
-
api.posts
|
|
595
|
+
api.posts.$get({
|
|
587
596
|
headers: async () => {
|
|
588
597
|
const token = await refreshToken();
|
|
589
598
|
return { Authorization: `Bearer ${token}` };
|
|
@@ -648,24 +657,18 @@ type EnlaceErrorCallbackPayload<T> =
|
|
|
648
657
|
|
|
649
658
|
```typescript
|
|
650
659
|
// Basic usage
|
|
651
|
-
const result = useAPI((api) => api.posts
|
|
660
|
+
const result = useAPI((api) => api.posts.$get());
|
|
652
661
|
|
|
653
662
|
// With options
|
|
654
|
-
const result = useAPI(
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
pollingInterval: 5000 // Refetch every 5s after previous request completes
|
|
659
|
-
}
|
|
660
|
-
);
|
|
663
|
+
const result = useAPI((api) => api.posts.$get(), {
|
|
664
|
+
enabled: true, // Skip fetching when false
|
|
665
|
+
pollingInterval: 5000, // Refetch every 5s after previous request completes
|
|
666
|
+
});
|
|
661
667
|
|
|
662
668
|
// With dynamic polling
|
|
663
|
-
const result = useAPI(
|
|
664
|
-
(
|
|
665
|
-
|
|
666
|
-
pollingInterval: (order) => order?.status === "pending" ? 2000 : false
|
|
667
|
-
}
|
|
668
|
-
);
|
|
669
|
+
const result = useAPI((api) => api.orders[id].$get(), {
|
|
670
|
+
pollingInterval: (order) => (order?.status === "pending" ? 2000 : false),
|
|
671
|
+
});
|
|
669
672
|
|
|
670
673
|
type UseEnlaceQueryResult<TData, TError> = {
|
|
671
674
|
loading: boolean; // No cached data and fetching
|
|
@@ -731,7 +734,7 @@ const api = enlaceNext<ApiSchema, ApiError>("https://api.example.com", {}, {
|
|
|
731
734
|
});
|
|
732
735
|
|
|
733
736
|
export default async function Page() {
|
|
734
|
-
const { data } = await api.posts
|
|
737
|
+
const { data } = await api.posts.$get({
|
|
735
738
|
revalidate: 60, // ISR: revalidate every 60 seconds
|
|
736
739
|
});
|
|
737
740
|
|
|
@@ -750,9 +753,7 @@ import { enlaceHookNext } from "enlace/hook";
|
|
|
750
753
|
|
|
751
754
|
type ApiError = { message: string };
|
|
752
755
|
|
|
753
|
-
const useAPI = enlaceHookNext<ApiSchema, ApiError>(
|
|
754
|
-
"https://api.example.com"
|
|
755
|
-
);
|
|
756
|
+
const useAPI = enlaceHookNext<ApiSchema, ApiError>("https://api.example.com");
|
|
756
757
|
```
|
|
757
758
|
|
|
758
759
|
### Server-Side Revalidation
|
|
@@ -795,7 +796,7 @@ const useAPI = enlaceHookNext<ApiSchema, ApiError>(
|
|
|
795
796
|
|
|
796
797
|
```typescript
|
|
797
798
|
function CreatePost() {
|
|
798
|
-
const { trigger } = useAPI((api) => api.posts
|
|
799
|
+
const { trigger } = useAPI((api) => api.posts.$post);
|
|
799
800
|
|
|
800
801
|
const handleCreate = () => {
|
|
801
802
|
trigger({
|
|
@@ -843,7 +844,7 @@ await trigger({ body: data, serverRevalidate: true });
|
|
|
843
844
|
### Next.js Request Options
|
|
844
845
|
|
|
845
846
|
```typescript
|
|
846
|
-
api.posts
|
|
847
|
+
api.posts.$get({
|
|
847
848
|
tags: ["posts"], // Next.js cache tags
|
|
848
849
|
revalidate: 60, // ISR revalidation (seconds)
|
|
849
850
|
revalidateTags: ["posts"], // Tags to invalidate after mutation
|
|
@@ -922,6 +923,28 @@ npm install enlace-openapi
|
|
|
922
923
|
enlace-openapi --schema ./types/APISchema.ts --output ./openapi.json
|
|
923
924
|
```
|
|
924
925
|
|
|
926
|
+
## Framework Adapters
|
|
927
|
+
|
|
928
|
+
### Hono
|
|
929
|
+
|
|
930
|
+
Use [`enlace-hono`](../hono/README.md) to automatically generate Enlace schemas from your Hono app:
|
|
931
|
+
|
|
932
|
+
```typescript
|
|
933
|
+
import { Hono } from "hono";
|
|
934
|
+
import type { HonoToEnlace } from "enlace-hono";
|
|
935
|
+
|
|
936
|
+
const app = new Hono()
|
|
937
|
+
.basePath("/api")
|
|
938
|
+
.get("/posts", (c) => c.json([{ id: 1, title: "Hello" }]))
|
|
939
|
+
.get("/posts/:id", (c) => c.json({ id: c.req.param("id") }));
|
|
940
|
+
|
|
941
|
+
// Auto-generate schema from Hono types
|
|
942
|
+
type ApiSchema = HonoToEnlace<typeof app>;
|
|
943
|
+
|
|
944
|
+
// Use with Enlace
|
|
945
|
+
const client = enlace<ApiSchema["api"]>("http://localhost:3000/api");
|
|
946
|
+
```
|
|
947
|
+
|
|
925
948
|
## License
|
|
926
949
|
|
|
927
950
|
MIT
|
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.16",
|
|
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"
|