@spoosh/plugin-invalidation 0.5.2 → 0.5.4
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 +72 -8
- package/dist/index.d.mts +15 -8
- package/dist/index.d.ts +15 -8
- package/dist/index.js +12 -1
- package/dist/index.mjs +12 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Cache invalidation plugin for Spoosh - auto-invalidates related queries after mutations.
|
|
4
4
|
|
|
5
|
-
**[Documentation](https://spoosh.dev/docs/plugins/invalidation)** · **Requirements:** TypeScript >= 5.0 · **Peer Dependencies:** `@spoosh/core`
|
|
5
|
+
**[Documentation](https://spoosh.dev/docs/react/plugins/invalidation)** · **Requirements:** TypeScript >= 5.0 · **Peer Dependencies:** `@spoosh/core`
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -81,7 +81,13 @@ await trigger({
|
|
|
81
81
|
invalidate: "none", // No invalidation
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
//
|
|
84
|
+
// Single tag (string)
|
|
85
|
+
await trigger({
|
|
86
|
+
body: { title: "New Post" },
|
|
87
|
+
invalidate: "posts", // Invalidate only "posts" tag
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Multiple tags (array without mode keyword)
|
|
85
91
|
await trigger({
|
|
86
92
|
body: { title: "New Post" },
|
|
87
93
|
invalidate: ["posts", "users", "custom-tag"],
|
|
@@ -106,6 +112,18 @@ await trigger({
|
|
|
106
112
|
invalidate: ["dashboard", "stats", "all"],
|
|
107
113
|
// → 'all' mode + explicit tags (mode can be anywhere)
|
|
108
114
|
});
|
|
115
|
+
|
|
116
|
+
// Wildcard - global refetch
|
|
117
|
+
await trigger({
|
|
118
|
+
body: { title: "New Post" },
|
|
119
|
+
invalidate: "*", // Triggers ALL queries to refetch
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Combined with clearCache (from @spoosh/plugin-cache)
|
|
123
|
+
await trigger({
|
|
124
|
+
clearCache: true, // Clear all cached data
|
|
125
|
+
invalidate: "*", // Then refetch all queries
|
|
126
|
+
});
|
|
109
127
|
```
|
|
110
128
|
|
|
111
129
|
## Options
|
|
@@ -118,9 +136,9 @@ await trigger({
|
|
|
118
136
|
|
|
119
137
|
### Per-Request Options
|
|
120
138
|
|
|
121
|
-
| Option | Type
|
|
122
|
-
| ------------ |
|
|
123
|
-
| `invalidate` | `"all" \| "self" \| "none" \| string[]` | Mode
|
|
139
|
+
| Option | Type | Description |
|
|
140
|
+
| ------------ | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
141
|
+
| `invalidate` | `"all" \| "self" \| "none" \| "*" \| string \| string[]` | Mode (`"all"`, `"self"`, `"none"`), wildcard (`"*"` for global refetch), single tag, or array of tags with optional mode keyword |
|
|
124
142
|
|
|
125
143
|
### Invalidation Modes
|
|
126
144
|
|
|
@@ -129,6 +147,25 @@ await trigger({
|
|
|
129
147
|
| `"all"` | Invalidate all tags from path hierarchy | `users/123/posts` → `users`, `users/123`, `users/123/posts` |
|
|
130
148
|
| `"self"` | Only invalidate the exact endpoint tag | `users/123/posts` → `users/123/posts` |
|
|
131
149
|
| `"none"` | Disable auto-invalidation (manual only) | No automatic invalidation |
|
|
150
|
+
| `"*"` | Global refetch - triggers all queries | All active queries refetch |
|
|
151
|
+
|
|
152
|
+
### Understanding `"all"` vs `"*"`
|
|
153
|
+
|
|
154
|
+
These two options serve different purposes:
|
|
155
|
+
|
|
156
|
+
- **`"all"`** - Invalidates all tags **from the current endpoint's path hierarchy**. If you're mutating `users/123/posts`, it invalidates `["users", "users/123", "users/123/posts"]`. It's scoped to the mutation's path.
|
|
157
|
+
|
|
158
|
+
- **`"*"`** - Triggers a **global refetch of every active query** in your app, regardless of tags. Use this sparingly for scenarios like "user logged out" or "full data sync from server".
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// "all" - scoped to this mutation's path hierarchy
|
|
162
|
+
await trigger({ invalidate: "all" });
|
|
163
|
+
// If path is users/123/posts → invalidates: users, users/123, users/123/posts
|
|
164
|
+
|
|
165
|
+
// "*" - refetches ALL queries in the entire app
|
|
166
|
+
await trigger({ invalidate: "*" });
|
|
167
|
+
// Every active useRead/injectRead will refetch
|
|
168
|
+
```
|
|
132
169
|
|
|
133
170
|
## Instance API
|
|
134
171
|
|
|
@@ -145,12 +182,39 @@ invalidate(["users", "posts"]);
|
|
|
145
182
|
// Invalidate with single string
|
|
146
183
|
invalidate("users");
|
|
147
184
|
|
|
185
|
+
// Global refetch - triggers ALL queries to refetch
|
|
186
|
+
invalidate("*");
|
|
187
|
+
|
|
148
188
|
// Useful for external events like WebSocket messages
|
|
149
189
|
socket.on("data-changed", (tags) => {
|
|
150
190
|
invalidate(tags);
|
|
151
191
|
});
|
|
192
|
+
|
|
193
|
+
// WebSocket: trigger global refetch
|
|
194
|
+
socket.on("full-sync", () => {
|
|
195
|
+
invalidate("*");
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
| Method | Description |
|
|
200
|
+
| ------------ | ---------------------------------------------------------------------- |
|
|
201
|
+
| `invalidate` | Manually invalidate cache entries by tags, or use `"*"` to refetch all |
|
|
202
|
+
|
|
203
|
+
## Combining with Cache Plugin
|
|
204
|
+
|
|
205
|
+
For scenarios like logout or user switching, combine `invalidate: "*"` with `clearCache` from `@spoosh/plugin-cache`:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
const { trigger } = useWrite((api) => api("auth/logout").POST);
|
|
209
|
+
|
|
210
|
+
// Clear cache + trigger all queries to refetch
|
|
211
|
+
await trigger({
|
|
212
|
+
clearCache: true, // From cache plugin: clear all cached data
|
|
213
|
+
invalidate: "*", // From invalidation plugin: trigger all queries to refetch
|
|
214
|
+
});
|
|
152
215
|
```
|
|
153
216
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
217
|
+
This ensures both:
|
|
218
|
+
|
|
219
|
+
1. All cached data is cleared (no stale data from previous session)
|
|
220
|
+
2. All active queries refetch with fresh data
|
package/dist/index.d.mts
CHANGED
|
@@ -15,7 +15,7 @@ type ReadPaths<TSchema> = {
|
|
|
15
15
|
* - Otherwise, it's tags only with mode defaulting to 'none'
|
|
16
16
|
* - 'none' keyword should NOT be used in arrays (use string 'none' instead)
|
|
17
17
|
*/
|
|
18
|
-
type InvalidateOption<TSchema = unknown> = InvalidationMode | (ReadPaths<TSchema> | "all" | "self" | (string & {}))[];
|
|
18
|
+
type InvalidateOption<TSchema = unknown> = InvalidationMode | "*" | ReadPaths<TSchema> | (ReadPaths<TSchema> | "all" | "self" | (string & {}))[];
|
|
19
19
|
interface InvalidationPluginConfig {
|
|
20
20
|
/**
|
|
21
21
|
* Default invalidation mode when invalidate option is not specified
|
|
@@ -32,13 +32,12 @@ type InvalidationInfiniteReadOptions = object;
|
|
|
32
32
|
type InvalidationReadResult = object;
|
|
33
33
|
type InvalidationWriteResult = object;
|
|
34
34
|
/**
|
|
35
|
-
* Manual invalidation - tags only
|
|
35
|
+
* Manual invalidation - tags only, or "*" for global refetch
|
|
36
36
|
*/
|
|
37
37
|
type InvalidateFn<TSchema> = {
|
|
38
|
-
(tag:
|
|
39
|
-
(
|
|
40
|
-
(
|
|
41
|
-
(tags: string[]): void;
|
|
38
|
+
(tag: "*"): void;
|
|
39
|
+
(tag: ReadPaths<TSchema> | (string & {})): void;
|
|
40
|
+
(tags: (ReadPaths<TSchema> | (string & {}))[]): void;
|
|
42
41
|
};
|
|
43
42
|
interface InvalidationInstanceApi {
|
|
44
43
|
/** Manually invalidate cache entries by tags. Useful for external events like WebSocket messages. */
|
|
@@ -68,7 +67,7 @@ declare module "@spoosh/core" {
|
|
|
68
67
|
*
|
|
69
68
|
* @param config - Plugin configuration
|
|
70
69
|
*
|
|
71
|
-
* @see {@link https://spoosh.dev/docs/plugins/invalidation | Invalidation Plugin Documentation}
|
|
70
|
+
* @see {@link https://spoosh.dev/docs/react/plugins/invalidation | Invalidation Plugin Documentation}
|
|
72
71
|
*
|
|
73
72
|
* @example
|
|
74
73
|
* ```ts
|
|
@@ -85,12 +84,20 @@ declare module "@spoosh/core" {
|
|
|
85
84
|
* });
|
|
86
85
|
*
|
|
87
86
|
* trigger({
|
|
88
|
-
* invalidate:
|
|
87
|
+
* invalidate: "posts", // Single tag
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* trigger({
|
|
91
|
+
* invalidate: ["posts", "users"], // Multiple tags
|
|
89
92
|
* });
|
|
90
93
|
*
|
|
91
94
|
* trigger({
|
|
92
95
|
* invalidate: ["all", "posts", "custom-tag"], // Mode + tags
|
|
93
96
|
* });
|
|
97
|
+
*
|
|
98
|
+
* trigger({
|
|
99
|
+
* invalidate: "*", // Global refetch - triggers all queries to refetch
|
|
100
|
+
* });
|
|
94
101
|
* ```
|
|
95
102
|
*/
|
|
96
103
|
declare function invalidationPlugin(config?: InvalidationPluginConfig): SpooshPlugin<{
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ type ReadPaths<TSchema> = {
|
|
|
15
15
|
* - Otherwise, it's tags only with mode defaulting to 'none'
|
|
16
16
|
* - 'none' keyword should NOT be used in arrays (use string 'none' instead)
|
|
17
17
|
*/
|
|
18
|
-
type InvalidateOption<TSchema = unknown> = InvalidationMode | (ReadPaths<TSchema> | "all" | "self" | (string & {}))[];
|
|
18
|
+
type InvalidateOption<TSchema = unknown> = InvalidationMode | "*" | ReadPaths<TSchema> | (ReadPaths<TSchema> | "all" | "self" | (string & {}))[];
|
|
19
19
|
interface InvalidationPluginConfig {
|
|
20
20
|
/**
|
|
21
21
|
* Default invalidation mode when invalidate option is not specified
|
|
@@ -32,13 +32,12 @@ type InvalidationInfiniteReadOptions = object;
|
|
|
32
32
|
type InvalidationReadResult = object;
|
|
33
33
|
type InvalidationWriteResult = object;
|
|
34
34
|
/**
|
|
35
|
-
* Manual invalidation - tags only
|
|
35
|
+
* Manual invalidation - tags only, or "*" for global refetch
|
|
36
36
|
*/
|
|
37
37
|
type InvalidateFn<TSchema> = {
|
|
38
|
-
(tag:
|
|
39
|
-
(
|
|
40
|
-
(
|
|
41
|
-
(tags: string[]): void;
|
|
38
|
+
(tag: "*"): void;
|
|
39
|
+
(tag: ReadPaths<TSchema> | (string & {})): void;
|
|
40
|
+
(tags: (ReadPaths<TSchema> | (string & {}))[]): void;
|
|
42
41
|
};
|
|
43
42
|
interface InvalidationInstanceApi {
|
|
44
43
|
/** Manually invalidate cache entries by tags. Useful for external events like WebSocket messages. */
|
|
@@ -68,7 +67,7 @@ declare module "@spoosh/core" {
|
|
|
68
67
|
*
|
|
69
68
|
* @param config - Plugin configuration
|
|
70
69
|
*
|
|
71
|
-
* @see {@link https://spoosh.dev/docs/plugins/invalidation | Invalidation Plugin Documentation}
|
|
70
|
+
* @see {@link https://spoosh.dev/docs/react/plugins/invalidation | Invalidation Plugin Documentation}
|
|
72
71
|
*
|
|
73
72
|
* @example
|
|
74
73
|
* ```ts
|
|
@@ -85,12 +84,20 @@ declare module "@spoosh/core" {
|
|
|
85
84
|
* });
|
|
86
85
|
*
|
|
87
86
|
* trigger({
|
|
88
|
-
* invalidate:
|
|
87
|
+
* invalidate: "posts", // Single tag
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* trigger({
|
|
91
|
+
* invalidate: ["posts", "users"], // Multiple tags
|
|
89
92
|
* });
|
|
90
93
|
*
|
|
91
94
|
* trigger({
|
|
92
95
|
* invalidate: ["all", "posts", "custom-tag"], // Mode + tags
|
|
93
96
|
* });
|
|
97
|
+
*
|
|
98
|
+
* trigger({
|
|
99
|
+
* invalidate: "*", // Global refetch - triggers all queries to refetch
|
|
100
|
+
* });
|
|
94
101
|
* ```
|
|
95
102
|
*/
|
|
96
103
|
declare function invalidationPlugin(config?: InvalidationPluginConfig): SpooshPlugin<{
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,10 @@ function resolveInvalidateTags(context, defaultMode) {
|
|
|
45
45
|
return resolveModeTags(context, effectiveDefault);
|
|
46
46
|
}
|
|
47
47
|
if (typeof invalidateOption === "string") {
|
|
48
|
-
|
|
48
|
+
if (invalidateOption === "all" || invalidateOption === "self" || invalidateOption === "none") {
|
|
49
|
+
return resolveModeTags(context, invalidateOption);
|
|
50
|
+
}
|
|
51
|
+
return [invalidateOption];
|
|
49
52
|
}
|
|
50
53
|
if (Array.isArray(invalidateOption)) {
|
|
51
54
|
const tags = [];
|
|
@@ -77,6 +80,10 @@ function invalidationPlugin(config = {}) {
|
|
|
77
80
|
afterResponse(context, response) {
|
|
78
81
|
if (!response.error) {
|
|
79
82
|
const tags = resolveInvalidateTags(context, defaultMode);
|
|
83
|
+
if (tags.includes("*")) {
|
|
84
|
+
context.eventEmitter.emit("refetchAll", void 0);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
80
87
|
if (tags.length > 0) {
|
|
81
88
|
context.stateManager.markStale(tags);
|
|
82
89
|
context.eventEmitter.emit("invalidate", tags);
|
|
@@ -87,6 +94,10 @@ function invalidationPlugin(config = {}) {
|
|
|
87
94
|
const { stateManager, eventEmitter } = context;
|
|
88
95
|
const invalidate = (input) => {
|
|
89
96
|
const tags = Array.isArray(input) ? input : [input];
|
|
97
|
+
if (tags.includes("*")) {
|
|
98
|
+
eventEmitter.emit("refetchAll", void 0);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
90
101
|
if (tags.length > 0) {
|
|
91
102
|
stateManager.markStale(tags);
|
|
92
103
|
eventEmitter.emit("invalidate", tags);
|
package/dist/index.mjs
CHANGED
|
@@ -19,7 +19,10 @@ function resolveInvalidateTags(context, defaultMode) {
|
|
|
19
19
|
return resolveModeTags(context, effectiveDefault);
|
|
20
20
|
}
|
|
21
21
|
if (typeof invalidateOption === "string") {
|
|
22
|
-
|
|
22
|
+
if (invalidateOption === "all" || invalidateOption === "self" || invalidateOption === "none") {
|
|
23
|
+
return resolveModeTags(context, invalidateOption);
|
|
24
|
+
}
|
|
25
|
+
return [invalidateOption];
|
|
23
26
|
}
|
|
24
27
|
if (Array.isArray(invalidateOption)) {
|
|
25
28
|
const tags = [];
|
|
@@ -51,6 +54,10 @@ function invalidationPlugin(config = {}) {
|
|
|
51
54
|
afterResponse(context, response) {
|
|
52
55
|
if (!response.error) {
|
|
53
56
|
const tags = resolveInvalidateTags(context, defaultMode);
|
|
57
|
+
if (tags.includes("*")) {
|
|
58
|
+
context.eventEmitter.emit("refetchAll", void 0);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
54
61
|
if (tags.length > 0) {
|
|
55
62
|
context.stateManager.markStale(tags);
|
|
56
63
|
context.eventEmitter.emit("invalidate", tags);
|
|
@@ -61,6 +68,10 @@ function invalidationPlugin(config = {}) {
|
|
|
61
68
|
const { stateManager, eventEmitter } = context;
|
|
62
69
|
const invalidate = (input) => {
|
|
63
70
|
const tags = Array.isArray(input) ? input : [input];
|
|
71
|
+
if (tags.includes("*")) {
|
|
72
|
+
eventEmitter.emit("refetchAll", void 0);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
64
75
|
if (tags.length > 0) {
|
|
65
76
|
stateManager.markStale(tags);
|
|
66
77
|
eventEmitter.emit("invalidate", tags);
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spoosh/plugin-invalidation",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Cache invalidation plugin for Spoosh - auto-invalidates after mutations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/
|
|
8
|
+
"url": "git+https://github.com/spooshdev/spoosh.git",
|
|
9
9
|
"directory": "packages/plugin-invalidation"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/
|
|
12
|
+
"url": "https://github.com/spooshdev/spoosh/issues"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://spoosh.dev/react/
|
|
14
|
+
"homepage": "https://spoosh.dev/docs/react/plugins/invalidation",
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"@spoosh/core": ">=0.8.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@spoosh/
|
|
40
|
-
"@spoosh/
|
|
39
|
+
"@spoosh/test-utils": "0.1.5",
|
|
40
|
+
"@spoosh/core": "0.10.0"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"dev": "tsup --watch",
|