swr-catalyst 0.2.2 → 0.3.0
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 +1 -0
- package/dist/__tests__/integration/errors/index.d.ts +12 -0
- package/dist/__tests__/integration/helpers/fetchers.d.ts +12 -0
- package/dist/__tests__/integration/helpers/index.d.ts +4 -0
- package/dist/__tests__/integration/helpers/testHelpers.d.ts +17 -0
- package/dist/__tests__/integration/hooks/concurrent.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/hooks/useSWRCreate.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/hooks/useSWRDelete.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/hooks/useSWRUpdate.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/scenarios/cacheConsistency.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/scenarios/errorRecovery.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/setup/basic.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/setup/server.d.ts +3 -0
- package/dist/__tests__/integration/setup/vitest.setup.d.ts +1 -0
- package/dist/__tests__/integration/types/index.d.ts +10 -0
- package/dist/__tests__/integration/utilities/mutateByGroup.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/utilities/mutateById.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/utilities/resetCache.integration.test.d.ts +1 -0
- package/dist/errors/index.d.ts +1 -1
- package/dist/hooks/shared/helpers/createMutationError/index.d.ts +1 -1
- package/dist/hooks/useSWRCreate/index.d.ts +2 -2
- package/dist/hooks/useSWRCreate/types.d.ts +3 -4
- package/dist/hooks/useSWRDelete/index.d.ts +2 -2
- package/dist/hooks/useSWRDelete/types.d.ts +5 -7
- package/dist/hooks/useSWRUpdate/index.d.ts +2 -2
- package/dist/hooks/useSWRUpdate/types.d.ts +4 -5
- package/dist/index.d.ts +1 -1
- package/dist/swr-catalyst.js +50 -50
- package/dist/swr-catalyst.umd.cjs +1 -1
- package/package.json +10 -7
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
[](https://www.npmjs.com/package/swr-catalyst)
|
|
12
12
|
[](https://github.com/pedroab0/swr-catalyst/actions/workflows/ci.yml)
|
|
13
13
|
[](https://codecov.io/github/pedroab0/swr-catalyst)
|
|
14
|
+
[](https://codescene.io/projects/73545)
|
|
14
15
|
|
|
15
16
|
[Features](#features) • [Installation](#installation) • [Quick Start](#quick-start) • [API Reference](#api-reference)
|
|
16
17
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ValidationErrorResponse } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Custom error class for API errors with status code and response body
|
|
4
|
+
*/
|
|
5
|
+
export declare class ApiError extends Error {
|
|
6
|
+
status: number;
|
|
7
|
+
code?: string;
|
|
8
|
+
details?: Record<string, string>;
|
|
9
|
+
constructor(message: string, status: number, body?: ValidationErrorResponse);
|
|
10
|
+
isValidationError(): boolean;
|
|
11
|
+
isNotFound(): boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Todo } from '../types';
|
|
2
|
+
export declare function fetchTodos(): Promise<Todo[]>;
|
|
3
|
+
export declare function fetchTodoById(id: number): Promise<Todo>;
|
|
4
|
+
export declare function createTodo(todo: Todo): Promise<Todo>;
|
|
5
|
+
export declare function updateTodo(id: string | number, data: Partial<{
|
|
6
|
+
title: string;
|
|
7
|
+
completed: boolean;
|
|
8
|
+
}>): Promise<Todo>;
|
|
9
|
+
export declare function deleteTodo(id: string | number): Promise<{
|
|
10
|
+
success: boolean;
|
|
11
|
+
id: number;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { Todo, ValidationErrorResponse } from '../types';
|
|
2
|
+
export { ApiError } from '../errors';
|
|
3
|
+
export { createTodo, deleteTodo, fetchTodoById, fetchTodos, updateTodo, } from './fetchers';
|
|
4
|
+
export { createMockTodo, renderHookWithGlobalCache, renderHookWithSWR, uniqueKeyId, } from './testHelpers';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Todo } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Renders a hook with an isolated SWR cache.
|
|
4
|
+
* Use for hook tests where all hooks share the same wrapper context.
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderHookWithSWR<T>(hook: () => T): import('@testing-library/react').RenderHookResult<T, unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* Renders a hook using the global SWR cache.
|
|
9
|
+
* Use for utility tests (mutateById, mutateByGroup, resetCache)
|
|
10
|
+
* where utilities operate on the global cache via `import { mutate } from 'swr'`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function renderHookWithGlobalCache<T>(hook: () => T): import('@testing-library/react').RenderHookResult<T, unknown>;
|
|
13
|
+
/**
|
|
14
|
+
* Generates a unique key ID to prevent cache collisions in global cache tests.
|
|
15
|
+
*/
|
|
16
|
+
export declare function uniqueKeyId(prefix: string): string;
|
|
17
|
+
export declare function createMockTodo(overrides?: Partial<Todo>): Todo;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/errors/index.d.ts
CHANGED
|
@@ -82,8 +82,8 @@ import { CreateFunction } from './types';
|
|
|
82
82
|
*
|
|
83
83
|
* // Later, you can use mutateByGroup('user-data') to revalidate all related caches
|
|
84
84
|
*/
|
|
85
|
-
export declare function useSWRCreate<TData = unknown, TCache = unknown, TError = Error>(key: SWRKey<TData>, createFunction: CreateFunction<TData
|
|
86
|
-
trigger: (data: TData) => Promise<
|
|
85
|
+
export declare function useSWRCreate<TData = unknown, TCache = unknown, TError = Error>(key: SWRKey<TData>, createFunction: CreateFunction<TData>, options?: MutateOptions<TCache, TData>): {
|
|
86
|
+
trigger: (data: TData) => Promise<unknown>;
|
|
87
87
|
isMutating: boolean;
|
|
88
88
|
error: TError | null;
|
|
89
89
|
};
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
* Function type for creating a new resource via API.
|
|
3
3
|
*
|
|
4
4
|
* @template TData - The type of data being sent to create the resource
|
|
5
|
-
* @template TResult - The type of data returned from the API
|
|
6
5
|
*
|
|
7
6
|
* @param data - The data for the new resource
|
|
8
7
|
* @returns Promise resolving to the created resource from the server
|
|
9
8
|
*
|
|
10
9
|
* @example
|
|
11
10
|
* // Basic create function
|
|
12
|
-
* const createTodo: CreateFunction<TodoInput
|
|
11
|
+
* const createTodo: CreateFunction<TodoInput> = async (data) => {
|
|
13
12
|
* const response = await fetch('/api/todos', {
|
|
14
13
|
* method: 'POST',
|
|
15
14
|
* body: JSON.stringify(data),
|
|
@@ -19,9 +18,9 @@
|
|
|
19
18
|
*
|
|
20
19
|
* @example
|
|
21
20
|
* // With axios
|
|
22
|
-
* const createUser: CreateFunction<UserInput
|
|
21
|
+
* const createUser: CreateFunction<UserInput> = async (data) => {
|
|
23
22
|
* const { data: user } = await axios.post('/api/users', data);
|
|
24
23
|
* return user;
|
|
25
24
|
* };
|
|
26
25
|
*/
|
|
27
|
-
export type CreateFunction<TData
|
|
26
|
+
export type CreateFunction<TData> = (data: TData) => Promise<unknown>;
|
|
@@ -96,8 +96,8 @@ import { DeleteFunction } from './types';
|
|
|
96
96
|
*
|
|
97
97
|
* // Later, you can use mutateByGroup('user-data') to revalidate all related caches
|
|
98
98
|
*/
|
|
99
|
-
export declare function useSWRDelete<TCache = unknown,
|
|
100
|
-
trigger: (id: string | number) => Promise<
|
|
99
|
+
export declare function useSWRDelete<TCache = unknown, TError = Error>(key: SWRKey, deleteFunction: DeleteFunction, options?: MutateOptions<TCache, string | number>): {
|
|
100
|
+
trigger: (id: string | number) => Promise<unknown>;
|
|
101
101
|
isMutating: boolean;
|
|
102
102
|
error: TError | null;
|
|
103
103
|
};
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Function type for deleting a resource via API.
|
|
3
3
|
*
|
|
4
|
-
* @template TResult - The type of data returned from the API (e.g., confirmation message, deleted item)
|
|
5
|
-
*
|
|
6
4
|
* @param id - The unique identifier of the resource to delete
|
|
7
5
|
* @returns Promise resolving to the API response (often a success message or the deleted item)
|
|
8
6
|
*
|
|
9
7
|
* @example
|
|
10
8
|
* // Basic delete function
|
|
11
|
-
* const deleteTodo: DeleteFunction
|
|
9
|
+
* const deleteTodo: DeleteFunction = async (id) => {
|
|
12
10
|
* const response = await fetch(`/api/todos/${id}`, {
|
|
13
11
|
* method: 'DELETE',
|
|
14
12
|
* });
|
|
@@ -17,14 +15,14 @@
|
|
|
17
15
|
*
|
|
18
16
|
* @example
|
|
19
17
|
* // With axios, returning deleted item
|
|
20
|
-
* const deleteUser: DeleteFunction
|
|
18
|
+
* const deleteUser: DeleteFunction = async (id) => {
|
|
21
19
|
* const { data } = await axios.delete(`/api/users/${id}`);
|
|
22
20
|
* return data;
|
|
23
21
|
* };
|
|
24
22
|
*
|
|
25
23
|
* @example
|
|
26
24
|
* // With error handling
|
|
27
|
-
* const deletePost: DeleteFunction
|
|
25
|
+
* const deletePost: DeleteFunction = async (id) => {
|
|
28
26
|
* const response = await fetch(`/api/posts/${id}`, {
|
|
29
27
|
* method: 'DELETE',
|
|
30
28
|
* });
|
|
@@ -35,11 +33,11 @@
|
|
|
35
33
|
*
|
|
36
34
|
* @example
|
|
37
35
|
* // Returning just status code
|
|
38
|
-
* const deleteComment: DeleteFunction
|
|
36
|
+
* const deleteComment: DeleteFunction = async (id) => {
|
|
39
37
|
* const response = await fetch(`/api/comments/${id}`, {
|
|
40
38
|
* method: 'DELETE',
|
|
41
39
|
* });
|
|
42
40
|
* return response.status;
|
|
43
41
|
* };
|
|
44
42
|
*/
|
|
45
|
-
export type DeleteFunction
|
|
43
|
+
export type DeleteFunction = (id: string | number) => Promise<unknown>;
|
|
@@ -111,11 +111,11 @@ import { UpdateFunction } from './types';
|
|
|
111
111
|
*
|
|
112
112
|
* // Later, you can use mutateByGroup('user-data') to revalidate all related caches
|
|
113
113
|
*/
|
|
114
|
-
export declare function useSWRUpdate<TData = unknown, TCache = unknown, TError = Error>(key: SWRKey, updateFunction: UpdateFunction<TData
|
|
114
|
+
export declare function useSWRUpdate<TData = unknown, TCache = unknown, TError = Error>(key: SWRKey, updateFunction: UpdateFunction<TData>, options?: MutateOptions<TCache, {
|
|
115
115
|
id: string | number;
|
|
116
116
|
data: TData;
|
|
117
117
|
}>): {
|
|
118
|
-
trigger: (id: string | number, data: TData) => Promise<
|
|
118
|
+
trigger: (id: string | number, data: TData) => Promise<unknown>;
|
|
119
119
|
isMutating: boolean;
|
|
120
120
|
error: TError | null;
|
|
121
121
|
};
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Function type for updating an existing resource via API.
|
|
3
3
|
*
|
|
4
4
|
* @template TData - The type of data being sent to update the resource
|
|
5
|
-
* @template TResult - The type of data returned from the API
|
|
6
5
|
*
|
|
7
6
|
* @param id - The unique identifier of the resource to update
|
|
8
7
|
* @param data - The partial or complete data to update the resource with
|
|
@@ -10,7 +9,7 @@
|
|
|
10
9
|
*
|
|
11
10
|
* @example
|
|
12
11
|
* // Basic update function with PATCH
|
|
13
|
-
* const updateTodo: UpdateFunction<TodoUpdate
|
|
12
|
+
* const updateTodo: UpdateFunction<TodoUpdate> = async (id, data) => {
|
|
14
13
|
* const response = await fetch(`/api/todos/${id}`, {
|
|
15
14
|
* method: 'PATCH',
|
|
16
15
|
* body: JSON.stringify(data),
|
|
@@ -20,14 +19,14 @@
|
|
|
20
19
|
*
|
|
21
20
|
* @example
|
|
22
21
|
* // With axios and PUT
|
|
23
|
-
* const updateUser: UpdateFunction<UserUpdate
|
|
22
|
+
* const updateUser: UpdateFunction<UserUpdate> = async (id, data) => {
|
|
24
23
|
* const { data: user } = await axios.put(`/api/users/${id}`, data);
|
|
25
24
|
* return user;
|
|
26
25
|
* };
|
|
27
26
|
*
|
|
28
27
|
* @example
|
|
29
28
|
* // With error handling
|
|
30
|
-
* const updatePost: UpdateFunction<PostUpdate
|
|
29
|
+
* const updatePost: UpdateFunction<PostUpdate> = async (id, data) => {
|
|
31
30
|
* const response = await fetch(`/api/posts/${id}`, {
|
|
32
31
|
* method: 'PATCH',
|
|
33
32
|
* body: JSON.stringify(data),
|
|
@@ -38,4 +37,4 @@
|
|
|
38
37
|
* return response.json();
|
|
39
38
|
* };
|
|
40
39
|
*/
|
|
41
|
-
export type UpdateFunction<TData
|
|
40
|
+
export type UpdateFunction<TData> = (id: string | number, data: TData) => Promise<unknown>;
|
package/dist/index.d.ts
CHANGED
package/dist/swr-catalyst.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { mutate as $, useSWRConfig as k } from "swr";
|
|
2
|
+
import { useRef as S, useState as p, useEffect as R, useCallback as U } from "react";
|
|
3
3
|
class h extends Error {
|
|
4
4
|
name = "MutationError";
|
|
5
5
|
context;
|
|
@@ -141,44 +141,24 @@ class h extends Error {
|
|
|
141
141
|
return !1;
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
|
|
145
|
-
if (r === t)
|
|
146
|
-
return !0;
|
|
147
|
-
if (r == null || t == null)
|
|
148
|
-
return r === t;
|
|
149
|
-
if (typeof r != "object" || typeof t != "object")
|
|
150
|
-
return !1;
|
|
151
|
-
try {
|
|
152
|
-
return JSON.stringify(r) === JSON.stringify(t);
|
|
153
|
-
} catch {
|
|
154
|
-
return !1;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
function x(r) {
|
|
158
|
-
const t = r?.id, e = r?.group, i = r?.data, n = S(null);
|
|
159
|
-
if (!r || !(t && i))
|
|
160
|
-
return n.current = null, n.current;
|
|
161
|
-
const a = n.current;
|
|
162
|
-
return (!a || a.id !== t || a.group !== e || !v(a.data, i)) && (n.current = { id: t, group: e, data: i }), n.current;
|
|
163
|
-
}
|
|
164
|
-
const A = /#id:"((?:[^"\\]|\\.)*)"/, j = /group:"((?:[^"\\]|\\.)*)"/, I = /data:"((?:[^"\\]|\\.)*)"/;
|
|
144
|
+
const v = /#id:"((?:[^"\\]|\\.)*)"/, A = /group:"((?:[^"\\]|\\.)*)"/, j = /data:"((?:[^"\\]|\\.)*)"/;
|
|
165
145
|
function M(r) {
|
|
166
146
|
return r.replace(/\\(.)/g, "$1");
|
|
167
147
|
}
|
|
168
|
-
function
|
|
148
|
+
function I(r) {
|
|
169
149
|
if (!r.startsWith("#id:"))
|
|
170
150
|
return null;
|
|
171
|
-
const t = r.match(
|
|
151
|
+
const t = r.match(v);
|
|
172
152
|
if (!t)
|
|
173
153
|
return null;
|
|
174
|
-
const e = r.match(
|
|
154
|
+
const e = r.match(A), i = r.match(j);
|
|
175
155
|
return {
|
|
176
156
|
id: M(t[1]),
|
|
177
157
|
group: e ? M(e[1]) : void 0,
|
|
178
158
|
data: i ? M(i[1]) : void 0
|
|
179
159
|
};
|
|
180
160
|
}
|
|
181
|
-
function
|
|
161
|
+
function C(r) {
|
|
182
162
|
try {
|
|
183
163
|
const t = JSON.parse(r);
|
|
184
164
|
if (t && typeof t == "object" && "id" in t)
|
|
@@ -187,23 +167,23 @@ function P(r) {
|
|
|
187
167
|
}
|
|
188
168
|
return null;
|
|
189
169
|
}
|
|
190
|
-
function
|
|
170
|
+
function x(r) {
|
|
191
171
|
if (typeof r == "object" && r !== null && "id" in r)
|
|
192
172
|
return r;
|
|
193
173
|
if (typeof r != "string")
|
|
194
174
|
return null;
|
|
195
|
-
const t =
|
|
175
|
+
const t = I(r);
|
|
196
176
|
if (t)
|
|
197
177
|
return t;
|
|
198
|
-
const e =
|
|
178
|
+
const e = C(r);
|
|
199
179
|
return e || null;
|
|
200
180
|
}
|
|
201
181
|
async function L(r, t, e) {
|
|
202
182
|
const i = Array.isArray(r) ? r : [r];
|
|
203
183
|
try {
|
|
204
|
-
await
|
|
184
|
+
await $(
|
|
205
185
|
(n) => {
|
|
206
|
-
const a =
|
|
186
|
+
const a = x(n);
|
|
207
187
|
return a?.group ? i.includes(a.group) : !1;
|
|
208
188
|
},
|
|
209
189
|
t ? () => t : void 0,
|
|
@@ -228,9 +208,9 @@ async function L(r, t, e) {
|
|
|
228
208
|
async function q(r, t, e) {
|
|
229
209
|
const i = typeof r == "string" ? [r] : r;
|
|
230
210
|
try {
|
|
231
|
-
await
|
|
211
|
+
await $(
|
|
232
212
|
(n) => {
|
|
233
|
-
const a =
|
|
213
|
+
const a = x(n);
|
|
234
214
|
return a ? i.includes(a?.id) : !1;
|
|
235
215
|
},
|
|
236
216
|
t ? () => t : void 0,
|
|
@@ -256,11 +236,11 @@ const B = async (r = []) => {
|
|
|
256
236
|
let t;
|
|
257
237
|
Array.isArray(r) ? t = r : r ? t = [r] : t = null;
|
|
258
238
|
try {
|
|
259
|
-
await
|
|
239
|
+
await $(
|
|
260
240
|
(e) => {
|
|
261
241
|
if (!t)
|
|
262
242
|
return !0;
|
|
263
|
-
const i =
|
|
243
|
+
const i = x(e);
|
|
264
244
|
return i ? !t.includes(i.id) : !0;
|
|
265
245
|
},
|
|
266
246
|
void 0,
|
|
@@ -278,7 +258,7 @@ const B = async (r = []) => {
|
|
|
278
258
|
);
|
|
279
259
|
}
|
|
280
260
|
};
|
|
281
|
-
function
|
|
261
|
+
function P(r, t) {
|
|
282
262
|
if (t)
|
|
283
263
|
return r.get(t);
|
|
284
264
|
}
|
|
@@ -296,8 +276,28 @@ async function _(r) {
|
|
|
296
276
|
return [null, t];
|
|
297
277
|
}
|
|
298
278
|
}
|
|
279
|
+
function W(r, t) {
|
|
280
|
+
if (r === t)
|
|
281
|
+
return !0;
|
|
282
|
+
if (r == null || t == null)
|
|
283
|
+
return r === t;
|
|
284
|
+
if (typeof r != "object" || typeof t != "object")
|
|
285
|
+
return !1;
|
|
286
|
+
try {
|
|
287
|
+
return JSON.stringify(r) === JSON.stringify(t);
|
|
288
|
+
} catch {
|
|
289
|
+
return !1;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function O(r) {
|
|
293
|
+
const t = r?.id, e = r?.group, i = r?.data, n = S(null);
|
|
294
|
+
if (!r || !(t && i))
|
|
295
|
+
return n.current = null, n.current;
|
|
296
|
+
const a = n.current;
|
|
297
|
+
return (!a || a.id !== t || a.group !== e || !W(a.data, i)) && (n.current = { id: t, group: e, data: i }), n.current;
|
|
298
|
+
}
|
|
299
299
|
async function T(r, t, e, i) {
|
|
300
|
-
const n =
|
|
300
|
+
const n = P(r, e)?.data, a = i.optimisticUpdateFn(n, i.data);
|
|
301
301
|
return await y(t, e, a, !1), n;
|
|
302
302
|
}
|
|
303
303
|
function b(r, t, e, i) {
|
|
@@ -317,14 +317,14 @@ async function D(r, t, e) {
|
|
|
317
317
|
await y(r, t, e, !1);
|
|
318
318
|
}
|
|
319
319
|
function V(r, t, e = {}) {
|
|
320
|
-
const { cache: i, mutate: n } =
|
|
321
|
-
return
|
|
320
|
+
const { cache: i, mutate: n } = k(), { optimisticUpdate: a, rollbackOnError: l = !0 } = e, [E, d] = p(!1), [w, m] = p(null), o = S(!0), s = O(r);
|
|
321
|
+
return R(
|
|
322
322
|
() => () => {
|
|
323
323
|
o.current = !1;
|
|
324
324
|
},
|
|
325
325
|
[]
|
|
326
326
|
), {
|
|
327
|
-
trigger:
|
|
327
|
+
trigger: U(
|
|
328
328
|
async (u) => {
|
|
329
329
|
if (!o.current)
|
|
330
330
|
return;
|
|
@@ -361,14 +361,14 @@ function V(r, t, e = {}) {
|
|
|
361
361
|
};
|
|
362
362
|
}
|
|
363
363
|
function z(r, t, e = {}) {
|
|
364
|
-
const { cache: i, mutate: n } =
|
|
365
|
-
return
|
|
364
|
+
const { cache: i, mutate: n } = k(), { optimisticUpdate: a, rollbackOnError: l = !0 } = e, [E, d] = p(!1), [w, m] = p(null), o = S(!0), s = O(r);
|
|
365
|
+
return R(
|
|
366
366
|
() => () => {
|
|
367
367
|
o.current = !1;
|
|
368
368
|
},
|
|
369
369
|
[]
|
|
370
370
|
), {
|
|
371
|
-
trigger:
|
|
371
|
+
trigger: U(
|
|
372
372
|
async (u) => {
|
|
373
373
|
if (!o.current)
|
|
374
374
|
return;
|
|
@@ -405,14 +405,14 @@ function z(r, t, e = {}) {
|
|
|
405
405
|
};
|
|
406
406
|
}
|
|
407
407
|
function H(r, t, e = {}) {
|
|
408
|
-
const { cache: i, mutate: n } =
|
|
409
|
-
return
|
|
408
|
+
const { cache: i, mutate: n } = k(), { optimisticUpdate: a, rollbackOnError: l = !0 } = e, [E, d] = p(!1), [w, m] = p(null), o = S(!0), s = O(r);
|
|
409
|
+
return R(
|
|
410
410
|
() => () => {
|
|
411
411
|
o.current = !1;
|
|
412
412
|
},
|
|
413
413
|
[]
|
|
414
414
|
), {
|
|
415
|
-
trigger:
|
|
415
|
+
trigger: U(
|
|
416
416
|
async (u, g) => {
|
|
417
417
|
if (!o.current)
|
|
418
418
|
return;
|
|
@@ -451,15 +451,15 @@ function H(r, t, e = {}) {
|
|
|
451
451
|
}
|
|
452
452
|
export {
|
|
453
453
|
h as MutationError,
|
|
454
|
-
|
|
454
|
+
x as extractSWRKey,
|
|
455
455
|
L as mutateByGroup,
|
|
456
456
|
q as mutateById,
|
|
457
457
|
B as resetCache,
|
|
458
|
-
|
|
458
|
+
P as swrGetCache,
|
|
459
459
|
y as swrMutate,
|
|
460
460
|
_ as to,
|
|
461
461
|
V as useSWRCreate,
|
|
462
462
|
z as useSWRDelete,
|
|
463
463
|
H as useSWRUpdate,
|
|
464
|
-
|
|
464
|
+
O as useStableKey
|
|
465
465
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(o,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("swr"),require("react")):typeof define=="function"&&define.amd?define(["exports","swr","react"],d):(o=typeof globalThis<"u"?globalThis:o||self,d(o["swr-catalyst"]={},o.SWR,o.React))})(this,(function(o,d,c){"use strict";class E extends Error{name="MutationError";context;originalError;constructor(t,e,i){super(t),this.context=e,this.originalError=i,"captureStackTrace"in Error&&Error.captureStackTrace(this,E)}getUserMessage(){const{operation:t,key:e}=this.context,i=e?.id||"resource";return`Failed to ${{create:"add",update:"update",delete:"delete"}[t]} ${i}. Please try again.`}toJSON(){return{name:this.name,message:this.message,context:this.context,originalError:this.originalError instanceof Error?{name:this.originalError.name,message:this.originalError.message,stack:this.originalError.stack}:String(this.originalError),stack:this.stack}}isNetworkError(){if(this.originalError instanceof Error){const t=this.originalError.message.toLowerCase();return this.originalError.name==="NetworkError"||t.includes("fetch")||t.includes("network")||t.includes("timeout")}return!1}isValidationError(){if(this.originalError instanceof Error){const t=this.originalError.message.toLowerCase();return t.includes("validation")||t.includes("invalid")||t.includes("required")}return!1}}const D=/#id:"((?:[^"\\]|\\.)*)"/,j=/group:"((?:[^"\\]|\\.)*)"/,v=/data:"((?:[^"\\]|\\.)*)"/;function $(r){return r.replace(/\\(.)/g,"$1")}function F(r){if(!r.startsWith("#id:"))return null;const t=r.match(D);if(!t)return null;const e=r.match(j),i=r.match(v);return{id:$(t[1]),group:e?$(e[1]):void 0,data:i?$(i[1]):void 0}}function N(r){try{const t=JSON.parse(r);if(t&&typeof t=="object"&&"id"in t)return t}catch{}return null}function M(r){if(typeof r=="object"&&r!==null&&"id"in r)return r;if(typeof r!="string")return null;const t=F(r);if(t)return t;const e=N(r);return e||null}async function A(r,t,e){const i=Array.isArray(r)?r:[r];try{await d.mutate(n=>{const a=M(n);return a?.group?i.includes(a.group):!1},t?()=>t:void 0,{revalidate:e?.revalidate??!t,...e})}catch(n){throw new E(`Failed to mutate cache by group(s): ${i.join(", ")}. ${n instanceof Error?n.message:String(n)}`,{operation:"update",key:null,data:t,timestamp:Date.now()},n)}}async function I(r,t,e){const i=typeof r=="string"?[r]:r;try{await d.mutate(n=>{const a=M(n);return a?i.includes(a?.id):!1},t?()=>t:void 0,{revalidate:e?.revalidate??!t,...e})}catch(n){throw new E(`Failed to mutate cache by ID(s): ${i.join(", ")}. ${n instanceof Error?n.message:String(n)}`,{operation:"update",key:null,data:t,timestamp:Date.now()},n)}}const P=async(r=[])=>{let t;Array.isArray(r)?t=r:r?t=[r]:t=null;try{await d.mutate(e=>{if(!t)return!0;const i=M(e);return i?!t.includes(i.id):!0},void 0,!1)}catch(e){throw new E(`Failed to reset cache${t?` (preserving: ${t.join(", ")})`:""}. ${e instanceof Error?e.message:String(e)}`,{operation:"delete",key:null,timestamp:Date.now()},e)}};function U(r,t){if(t)return r.get(t)}function w(r,t,e,i){return r(t,e,i)}async function G(r){try{return[await r,null]}catch(t){return[null,t]}}function J(r,t){if(r===t)return!0;if(r==null||t==null)return r===t;if(typeof r!="object"||typeof t!="object")return!1;try{return JSON.stringify(r)===JSON.stringify(t)}catch{return!1}}function k(r){const t=r?.id,e=r?.group,i=r?.data,n=c.useRef(null);if(!r||!(t&&i))return n.current=null,n.current;const a=n.current;return(!a||a.id!==t||a.group!==e||!J(a.data,i))&&(n.current={id:t,group:e,data:i}),n.current}async function b(r,t,e,i){const n=U(r,e)?.data,a=i.optimisticUpdateFn(n,i.data);return await w(t,e,a,!1),n}function T(r,t,e,i){const n=t?.id||"unknown",a=i?.id?` with ID ${i.id}`:"",g=`Failed to ${r} resource "${n}"${a}. ${e instanceof Error?e.message:String(e)}`;return new E(g,{operation:r,key:t,...i,timestamp:Date.now()},e)}async function C(r,t,e){await w(r,t,e,!1)}function q(r,t,e={}){const{cache:i,mutate:n}=d.useSWRConfig(),{optimisticUpdate:a,rollbackOnError:g=!0}=e,[S,h]=c.useState(!1),[R,y]=c.useState(null),s=c.useRef(!0),u=k(r);return c.useEffect(()=>()=>{s.current=!1},[]),{trigger:c.useCallback(async f=>{if(!s.current)return;h(!0),y(null);let p;a&&(p=await b(i,n,u,{data:f,optimisticUpdateFn:a}));try{const l=await t(f);return s.current&&await w(n,u),l}catch(l){g&&a&&await C(n,u,p);const m=T("create",u,l,{data:f});throw s.current&&y(m),m}finally{s.current&&h(!1)}},[u,t,n,i,a,g]),isMutating:S,error:R}}function B(r,t,e={}){const{cache:i,mutate:n}=d.useSWRConfig(),{optimisticUpdate:a,rollbackOnError:g=!0}=e,[S,h]=c.useState(!1),[R,y]=c.useState(null),s=c.useRef(!0),u=k(r);return c.useEffect(()=>()=>{s.current=!1},[]),{trigger:c.useCallback(async f=>{if(!s.current)return;h(!0),y(null);let p;a&&(p=await b(i,n,u,{data:f,optimisticUpdateFn:a}));try{const l=await t(f);return s.current&&await w(n,u),l}catch(l){g&&a&&await C(n,u,p);const m=T("delete",u,l,{id:f});throw s.current&&y(m),m}finally{s.current&&h(!1)}},[u,t,n,i,a,g]),isMutating:S,error:R}}function L(r,t,e={}){const{cache:i,mutate:n}=d.useSWRConfig(),{optimisticUpdate:a,rollbackOnError:g=!0}=e,[S,h]=c.useState(!1),[R,y]=c.useState(null),s=c.useRef(!0),u=k(r);return c.useEffect(()=>()=>{s.current=!1},[]),{trigger:c.useCallback(async(f,p)=>{if(!s.current)return;h(!0),y(null);let l;a&&(l=await b(i,n,u,{data:{id:f,data:p},optimisticUpdateFn:a}));try{const m=await t(f,p);return s.current&&await w(n,u),m}catch(m){g&&a&&await C(n,u,l);const O=T("update",u,m,{data:p,id:f});throw s.current&&y(O),O}finally{s.current&&h(!1)}},[u,t,n,i,a,g]),isMutating:S,error:R}}o.MutationError=E,o.extractSWRKey=M,o.mutateByGroup=A,o.mutateById=I,o.resetCache=P,o.swrGetCache=U,o.swrMutate=w,o.to=G,o.useSWRCreate=q,o.useSWRDelete=B,o.useSWRUpdate=L,o.useStableKey=k,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swr-catalyst",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A lightweight, declarative library to simplify data mutations with SWR.",
|
|
5
5
|
"author": "Pedro Barbosa (https://github.com/pedroab0)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "vite build",
|
|
35
35
|
"test": "vitest",
|
|
36
|
+
"test:unit": "vitest run --exclude 'src/__tests__/**'",
|
|
37
|
+
"test:integration": "vitest run src/__tests__/integration",
|
|
36
38
|
"test:coverage": "vitest run --coverage",
|
|
37
39
|
"lint": "biome check .",
|
|
38
40
|
"lint:fix": "biome check --write .",
|
|
@@ -48,19 +50,20 @@
|
|
|
48
50
|
"swr": "^2.0.0"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
|
-
"@biomejs/biome": "^2.3.
|
|
53
|
+
"@biomejs/biome": "^2.3.7",
|
|
52
54
|
"@size-limit/preset-small-lib": "^11.2.0",
|
|
53
55
|
"@testing-library/react": "^16.3.0",
|
|
54
|
-
"@types/node": "^24.10.
|
|
55
|
-
"@vitest/coverage-v8": "^4.0.
|
|
56
|
-
"jsdom": "^27.
|
|
56
|
+
"@types/node": "^24.10.1",
|
|
57
|
+
"@vitest/coverage-v8": "^4.0.13",
|
|
58
|
+
"jsdom": "^27.2.0",
|
|
59
|
+
"msw": "^2.12.2",
|
|
57
60
|
"react": "^19.2.0",
|
|
58
61
|
"react-dom": "^19.2.0",
|
|
59
62
|
"size-limit": "^11.2.0",
|
|
60
63
|
"swr": "^2.3.6",
|
|
61
64
|
"typescript": "^5.9.3",
|
|
62
|
-
"ultracite": "^6.3.
|
|
63
|
-
"vite": "^7.2.
|
|
65
|
+
"ultracite": "^6.3.6",
|
|
66
|
+
"vite": "^7.2.4",
|
|
64
67
|
"vite-plugin-dts": "^4.5.4",
|
|
65
68
|
"vitest": "^4.0.7"
|
|
66
69
|
}
|