@spoosh/plugin-invalidation 0.3.0 → 0.4.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 +42 -26
- package/dist/index.d.mts +46 -17
- package/dist/index.d.ts +46 -17
- package/dist/index.js +35 -40
- package/dist/index.mjs +35 -44
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -53,41 +53,58 @@ await trigger({ body: { title: "New Post" } });
|
|
|
53
53
|
|
|
54
54
|
```typescript
|
|
55
55
|
// Default: invalidate all related tags (full hierarchy)
|
|
56
|
-
invalidationPlugin(); // same as {
|
|
56
|
+
invalidationPlugin(); // same as { defaultMode: "all" }
|
|
57
57
|
|
|
58
58
|
// Only invalidate the exact endpoint by default
|
|
59
|
-
invalidationPlugin({
|
|
59
|
+
invalidationPlugin({ defaultMode: "self" });
|
|
60
60
|
|
|
61
61
|
// Disable auto-invalidation by default (manual only)
|
|
62
|
-
invalidationPlugin({
|
|
62
|
+
invalidationPlugin({ defaultMode: "none" });
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
## Per-Request
|
|
65
|
+
## Per-Request Invalidation
|
|
66
66
|
|
|
67
67
|
```typescript
|
|
68
|
-
//
|
|
68
|
+
// Mode only (string)
|
|
69
69
|
await trigger({
|
|
70
70
|
body: { title: "New Post" },
|
|
71
|
-
|
|
71
|
+
invalidate: "all", // Invalidate entire path hierarchy
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
// Override to only invalidate the exact endpoint
|
|
75
74
|
await trigger({
|
|
76
75
|
body: { title: "New Post" },
|
|
77
|
-
|
|
76
|
+
invalidate: "self", // Only invalidate the exact endpoint
|
|
78
77
|
});
|
|
79
78
|
|
|
80
|
-
// Disable auto-invalidation and specify custom targets
|
|
81
79
|
await trigger({
|
|
82
80
|
body: { title: "New Post" },
|
|
83
|
-
|
|
84
|
-
invalidate: (api) => [api("posts").GET, api("stats").GET, "dashboard-data"],
|
|
81
|
+
invalidate: "none", // No invalidation
|
|
85
82
|
});
|
|
86
83
|
|
|
87
|
-
//
|
|
84
|
+
// Tags only (array without mode keyword)
|
|
88
85
|
await trigger({
|
|
89
86
|
body: { title: "New Post" },
|
|
90
|
-
invalidate: ["posts", "
|
|
87
|
+
invalidate: ["posts", "users", "custom-tag"],
|
|
88
|
+
// → Default mode: 'none' (only explicit tags are invalidated)
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Mode + Tags (array with mode keyword at any position)
|
|
92
|
+
await trigger({
|
|
93
|
+
body: { title: "New Post" },
|
|
94
|
+
invalidate: ["all", "dashboard", "stats"],
|
|
95
|
+
// → 'all' mode + explicit tags
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await trigger({
|
|
99
|
+
body: { title: "New Post" },
|
|
100
|
+
invalidate: ["posts", "self", "users"],
|
|
101
|
+
// → 'self' mode + explicit tags
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await trigger({
|
|
105
|
+
body: { title: "New Post" },
|
|
106
|
+
invalidate: ["dashboard", "stats", "all"],
|
|
107
|
+
// → 'all' mode + explicit tags (mode can be anywhere)
|
|
91
108
|
});
|
|
92
109
|
```
|
|
93
110
|
|
|
@@ -95,18 +112,17 @@ await trigger({
|
|
|
95
112
|
|
|
96
113
|
### Plugin Config
|
|
97
114
|
|
|
98
|
-
| Option
|
|
99
|
-
|
|
|
100
|
-
| `
|
|
115
|
+
| Option | Type | Default | Description |
|
|
116
|
+
| ------------- | --------------------------- | ------- | ---------------------------------------------------- |
|
|
117
|
+
| `defaultMode` | `"all" \| "self" \| "none"` | `"all"` | Default invalidation mode when option not specified |
|
|
101
118
|
|
|
102
119
|
### Per-Request Options
|
|
103
120
|
|
|
104
|
-
| Option
|
|
105
|
-
|
|
|
106
|
-
| `
|
|
107
|
-
| `invalidate` | `string[] \| ((api) => [...])` | Specific tags or endpoints to invalidate |
|
|
121
|
+
| Option | Type | Description |
|
|
122
|
+
| ------------ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
123
|
+
| `invalidate` | `"all" \| "self" \| "none" \| string[]` | Mode only (string), tags only (array), or mode + tags (array with 'all'/'self' keyword at any position) |
|
|
108
124
|
|
|
109
|
-
###
|
|
125
|
+
### Invalidation Modes
|
|
110
126
|
|
|
111
127
|
| Mode | Description | Example |
|
|
112
128
|
| -------- | --------------------------------------- | ----------------------------------------------------------- |
|
|
@@ -126,8 +142,8 @@ const { useRead, invalidate } = createReactSpoosh(client);
|
|
|
126
142
|
// Invalidate with string array
|
|
127
143
|
invalidate(["users", "posts"]);
|
|
128
144
|
|
|
129
|
-
// Invalidate with
|
|
130
|
-
invalidate(
|
|
145
|
+
// Invalidate with single string
|
|
146
|
+
invalidate("users");
|
|
131
147
|
|
|
132
148
|
// Useful for external events like WebSocket messages
|
|
133
149
|
socket.on("data-changed", (tags) => {
|
|
@@ -135,6 +151,6 @@ socket.on("data-changed", (tags) => {
|
|
|
135
151
|
});
|
|
136
152
|
```
|
|
137
153
|
|
|
138
|
-
| Method | Description
|
|
139
|
-
| ------------ |
|
|
140
|
-
| `invalidate` | Manually invalidate cache entries by tags
|
|
154
|
+
| Method | Description |
|
|
155
|
+
| ------------ | ------------------------------------------- |
|
|
156
|
+
| `invalidate` | Manually invalidate cache entries by tags |
|
package/dist/index.d.mts
CHANGED
|
@@ -1,30 +1,52 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SpooshPlugin } from '@spoosh/core';
|
|
2
2
|
|
|
3
|
-
type
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
type InvalidationMode = "all" | "self" | "none";
|
|
4
|
+
/**
|
|
5
|
+
* Extract paths that have GET methods (eligible for invalidation)
|
|
6
|
+
*/
|
|
7
|
+
type ReadPaths<TSchema> = {
|
|
8
|
+
[K in keyof TSchema & string]: "GET" extends keyof TSchema[K] ? K : never;
|
|
9
|
+
}[keyof TSchema & string];
|
|
10
|
+
/**
|
|
11
|
+
* Unified invalidate option
|
|
12
|
+
* - String: mode only ('all' | 'self' | 'none')
|
|
13
|
+
* - Array: tags only OR [mode keyword mixed with tags]
|
|
14
|
+
* - If array contains 'all' or 'self' at ANY position, it's treated as mode + tags
|
|
15
|
+
* - Otherwise, it's tags only with mode defaulting to 'none'
|
|
16
|
+
* - 'none' keyword should NOT be used in arrays (use string 'none' instead)
|
|
17
|
+
*/
|
|
18
|
+
type InvalidateOption<TSchema = unknown> = InvalidationMode | (ReadPaths<TSchema> | "all" | "self" | (string & {}))[];
|
|
6
19
|
interface InvalidationPluginConfig {
|
|
7
|
-
/**
|
|
8
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Default invalidation mode when invalidate option is not specified
|
|
22
|
+
* @default "all"
|
|
23
|
+
*/
|
|
24
|
+
defaultMode?: InvalidationMode;
|
|
9
25
|
}
|
|
10
26
|
interface InvalidationWriteOptions<TSchema = unknown> {
|
|
11
|
-
/**
|
|
12
|
-
autoInvalidate?: AutoInvalidate;
|
|
13
|
-
/** Specific tags or endpoints to invalidate after mutation. */
|
|
27
|
+
/** Unified invalidation configuration */
|
|
14
28
|
invalidate?: InvalidateOption<TSchema>;
|
|
15
29
|
}
|
|
16
30
|
type InvalidationReadOptions = object;
|
|
17
31
|
type InvalidationInfiniteReadOptions = object;
|
|
18
32
|
type InvalidationReadResult = object;
|
|
19
33
|
type InvalidationWriteResult = object;
|
|
20
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Manual invalidation - tags only
|
|
36
|
+
*/
|
|
37
|
+
type InvalidateFn<TSchema> = {
|
|
38
|
+
(tag: ReadPaths<TSchema>): void;
|
|
39
|
+
(tags: ReadPaths<TSchema>[]): void;
|
|
40
|
+
(tag: string): void;
|
|
41
|
+
(tags: string[]): void;
|
|
42
|
+
};
|
|
21
43
|
interface InvalidationInstanceApi {
|
|
22
44
|
/** Manually invalidate cache entries by tags. Useful for external events like WebSocket messages. */
|
|
23
45
|
invalidate: InvalidateFn<unknown>;
|
|
24
46
|
}
|
|
25
47
|
interface InvalidationPluginExports {
|
|
26
|
-
/** Set the default
|
|
27
|
-
|
|
48
|
+
/** Set the default invalidation mode for this mutation */
|
|
49
|
+
setDefaultMode: (value: InvalidationMode) => void;
|
|
28
50
|
}
|
|
29
51
|
declare module "@spoosh/core" {
|
|
30
52
|
interface PluginExportsRegistry {
|
|
@@ -54,13 +76,20 @@ declare module "@spoosh/core" {
|
|
|
54
76
|
*
|
|
55
77
|
* const client = new Spoosh<ApiSchema, Error>("/api")
|
|
56
78
|
* .use([
|
|
57
|
-
* invalidationPlugin({
|
|
79
|
+
* invalidationPlugin({ defaultMode: "all" }),
|
|
58
80
|
* ]);
|
|
59
81
|
*
|
|
60
|
-
* // Per-mutation
|
|
82
|
+
* // Per-mutation invalidation
|
|
83
|
+
* trigger({
|
|
84
|
+
* invalidate: "self", // Mode only
|
|
85
|
+
* });
|
|
86
|
+
*
|
|
87
|
+
* trigger({
|
|
88
|
+
* invalidate: ["posts", "users"], // Tags only
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
61
91
|
* trigger({
|
|
62
|
-
*
|
|
63
|
-
* invalidate: ["posts"], // Or explicit tags
|
|
92
|
+
* invalidate: ["all", "posts", "custom-tag"], // Mode + tags
|
|
64
93
|
* });
|
|
65
94
|
* ```
|
|
66
95
|
*/
|
|
@@ -73,4 +102,4 @@ declare function invalidationPlugin(config?: InvalidationPluginConfig): SpooshPl
|
|
|
73
102
|
instanceApi: InvalidationInstanceApi;
|
|
74
103
|
}>;
|
|
75
104
|
|
|
76
|
-
export { type
|
|
105
|
+
export { type InvalidateOption, type InvalidationInfiniteReadOptions, type InvalidationMode, type InvalidationPluginConfig, type InvalidationPluginExports, type InvalidationReadOptions, type InvalidationReadResult, type InvalidationWriteOptions, type InvalidationWriteResult, invalidationPlugin };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,30 +1,52 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SpooshPlugin } from '@spoosh/core';
|
|
2
2
|
|
|
3
|
-
type
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
type InvalidationMode = "all" | "self" | "none";
|
|
4
|
+
/**
|
|
5
|
+
* Extract paths that have GET methods (eligible for invalidation)
|
|
6
|
+
*/
|
|
7
|
+
type ReadPaths<TSchema> = {
|
|
8
|
+
[K in keyof TSchema & string]: "GET" extends keyof TSchema[K] ? K : never;
|
|
9
|
+
}[keyof TSchema & string];
|
|
10
|
+
/**
|
|
11
|
+
* Unified invalidate option
|
|
12
|
+
* - String: mode only ('all' | 'self' | 'none')
|
|
13
|
+
* - Array: tags only OR [mode keyword mixed with tags]
|
|
14
|
+
* - If array contains 'all' or 'self' at ANY position, it's treated as mode + tags
|
|
15
|
+
* - Otherwise, it's tags only with mode defaulting to 'none'
|
|
16
|
+
* - 'none' keyword should NOT be used in arrays (use string 'none' instead)
|
|
17
|
+
*/
|
|
18
|
+
type InvalidateOption<TSchema = unknown> = InvalidationMode | (ReadPaths<TSchema> | "all" | "self" | (string & {}))[];
|
|
6
19
|
interface InvalidationPluginConfig {
|
|
7
|
-
/**
|
|
8
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Default invalidation mode when invalidate option is not specified
|
|
22
|
+
* @default "all"
|
|
23
|
+
*/
|
|
24
|
+
defaultMode?: InvalidationMode;
|
|
9
25
|
}
|
|
10
26
|
interface InvalidationWriteOptions<TSchema = unknown> {
|
|
11
|
-
/**
|
|
12
|
-
autoInvalidate?: AutoInvalidate;
|
|
13
|
-
/** Specific tags or endpoints to invalidate after mutation. */
|
|
27
|
+
/** Unified invalidation configuration */
|
|
14
28
|
invalidate?: InvalidateOption<TSchema>;
|
|
15
29
|
}
|
|
16
30
|
type InvalidationReadOptions = object;
|
|
17
31
|
type InvalidationInfiniteReadOptions = object;
|
|
18
32
|
type InvalidationReadResult = object;
|
|
19
33
|
type InvalidationWriteResult = object;
|
|
20
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Manual invalidation - tags only
|
|
36
|
+
*/
|
|
37
|
+
type InvalidateFn<TSchema> = {
|
|
38
|
+
(tag: ReadPaths<TSchema>): void;
|
|
39
|
+
(tags: ReadPaths<TSchema>[]): void;
|
|
40
|
+
(tag: string): void;
|
|
41
|
+
(tags: string[]): void;
|
|
42
|
+
};
|
|
21
43
|
interface InvalidationInstanceApi {
|
|
22
44
|
/** Manually invalidate cache entries by tags. Useful for external events like WebSocket messages. */
|
|
23
45
|
invalidate: InvalidateFn<unknown>;
|
|
24
46
|
}
|
|
25
47
|
interface InvalidationPluginExports {
|
|
26
|
-
/** Set the default
|
|
27
|
-
|
|
48
|
+
/** Set the default invalidation mode for this mutation */
|
|
49
|
+
setDefaultMode: (value: InvalidationMode) => void;
|
|
28
50
|
}
|
|
29
51
|
declare module "@spoosh/core" {
|
|
30
52
|
interface PluginExportsRegistry {
|
|
@@ -54,13 +76,20 @@ declare module "@spoosh/core" {
|
|
|
54
76
|
*
|
|
55
77
|
* const client = new Spoosh<ApiSchema, Error>("/api")
|
|
56
78
|
* .use([
|
|
57
|
-
* invalidationPlugin({
|
|
79
|
+
* invalidationPlugin({ defaultMode: "all" }),
|
|
58
80
|
* ]);
|
|
59
81
|
*
|
|
60
|
-
* // Per-mutation
|
|
82
|
+
* // Per-mutation invalidation
|
|
83
|
+
* trigger({
|
|
84
|
+
* invalidate: "self", // Mode only
|
|
85
|
+
* });
|
|
86
|
+
*
|
|
87
|
+
* trigger({
|
|
88
|
+
* invalidate: ["posts", "users"], // Tags only
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
61
91
|
* trigger({
|
|
62
|
-
*
|
|
63
|
-
* invalidate: ["posts"], // Or explicit tags
|
|
92
|
+
* invalidate: ["all", "posts", "custom-tag"], // Mode + tags
|
|
64
93
|
* });
|
|
65
94
|
* ```
|
|
66
95
|
*/
|
|
@@ -73,4 +102,4 @@ declare function invalidationPlugin(config?: InvalidationPluginConfig): SpooshPl
|
|
|
73
102
|
instanceApi: InvalidationInstanceApi;
|
|
74
103
|
}>;
|
|
75
104
|
|
|
76
|
-
export { type
|
|
105
|
+
export { type InvalidateOption, type InvalidationInfiniteReadOptions, type InvalidationMode, type InvalidationPluginConfig, type InvalidationPluginExports, type InvalidationReadOptions, type InvalidationReadResult, type InvalidationWriteOptions, type InvalidationWriteResult, invalidationPlugin };
|
package/dist/index.js
CHANGED
|
@@ -25,63 +25,58 @@ __export(src_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(src_exports);
|
|
26
26
|
|
|
27
27
|
// src/plugin.ts
|
|
28
|
-
var
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
for (const target of invalidationTargets) {
|
|
38
|
-
if (typeof target === "string") {
|
|
39
|
-
tags.push(target);
|
|
40
|
-
} else {
|
|
41
|
-
const path = (0, import_core.extractPathFromSelector)(target);
|
|
42
|
-
const pathSegments = path.split("/").filter(Boolean);
|
|
43
|
-
const derivedTags = (0, import_core.generateTags)(pathSegments);
|
|
44
|
-
const exactTag = derivedTags[derivedTags.length - 1];
|
|
45
|
-
if (exactTag) {
|
|
46
|
-
tags.push(exactTag);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
28
|
+
var INVALIDATION_DEFAULT_KEY = "invalidation:defaultMode";
|
|
29
|
+
function resolveModeTags(context, mode) {
|
|
30
|
+
switch (mode) {
|
|
31
|
+
case "all":
|
|
32
|
+
return context.tags;
|
|
33
|
+
case "self":
|
|
34
|
+
return [context.path.join("/")];
|
|
35
|
+
case "none":
|
|
36
|
+
return [];
|
|
50
37
|
}
|
|
51
|
-
return tags;
|
|
52
38
|
}
|
|
53
|
-
function resolveInvalidateTags(context,
|
|
39
|
+
function resolveInvalidateTags(context, defaultMode) {
|
|
54
40
|
const pluginOptions = context.pluginOptions;
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
|
|
41
|
+
const invalidateOption = pluginOptions?.invalidate;
|
|
42
|
+
if (!invalidateOption) {
|
|
43
|
+
const overrideDefault = context.metadata.get(INVALIDATION_DEFAULT_KEY);
|
|
44
|
+
const effectiveDefault = overrideDefault ?? defaultMode;
|
|
45
|
+
return resolveModeTags(context, effectiveDefault);
|
|
58
46
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
tags
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
47
|
+
if (typeof invalidateOption === "string") {
|
|
48
|
+
return resolveModeTags(context, invalidateOption);
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(invalidateOption)) {
|
|
51
|
+
const tags = [];
|
|
52
|
+
let mode = "none";
|
|
53
|
+
for (const item of invalidateOption) {
|
|
54
|
+
if (item === "all" || item === "self") {
|
|
55
|
+
mode = item;
|
|
56
|
+
} else if (typeof item === "string") {
|
|
57
|
+
tags.push(item);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
tags.push(...resolveModeTags(context, mode));
|
|
61
|
+
return [...new Set(tags)];
|
|
67
62
|
}
|
|
68
|
-
return [
|
|
63
|
+
return [];
|
|
69
64
|
}
|
|
70
65
|
function invalidationPlugin(config = {}) {
|
|
71
|
-
const {
|
|
66
|
+
const { defaultMode = "all" } = config;
|
|
72
67
|
return {
|
|
73
68
|
name: "spoosh:invalidation",
|
|
74
69
|
operations: ["write"],
|
|
75
70
|
exports(context) {
|
|
76
71
|
return {
|
|
77
|
-
|
|
72
|
+
setDefaultMode(value) {
|
|
78
73
|
context.metadata.set(INVALIDATION_DEFAULT_KEY, value);
|
|
79
74
|
}
|
|
80
75
|
};
|
|
81
76
|
},
|
|
82
77
|
onResponse(context, response) {
|
|
83
78
|
if (!response.error) {
|
|
84
|
-
const tags = resolveInvalidateTags(context,
|
|
79
|
+
const tags = resolveInvalidateTags(context, defaultMode);
|
|
85
80
|
if (tags.length > 0) {
|
|
86
81
|
context.stateManager.markStale(tags);
|
|
87
82
|
context.eventEmitter.emit("invalidate", tags);
|
|
@@ -91,7 +86,7 @@ function invalidationPlugin(config = {}) {
|
|
|
91
86
|
instanceApi(context) {
|
|
92
87
|
const { stateManager, eventEmitter } = context;
|
|
93
88
|
const invalidate = (input) => {
|
|
94
|
-
const tags =
|
|
89
|
+
const tags = Array.isArray(input) ? input : [input];
|
|
95
90
|
if (tags.length > 0) {
|
|
96
91
|
stateManager.markStale(tags);
|
|
97
92
|
eventEmitter.emit("invalidate", tags);
|
package/dist/index.mjs
CHANGED
|
@@ -1,65 +1,56 @@
|
|
|
1
1
|
// src/plugin.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
tags.push(...invalidate);
|
|
12
|
-
} else {
|
|
13
|
-
const proxy = createSelectorProxy();
|
|
14
|
-
const invalidationTargets = invalidate(proxy);
|
|
15
|
-
for (const target of invalidationTargets) {
|
|
16
|
-
if (typeof target === "string") {
|
|
17
|
-
tags.push(target);
|
|
18
|
-
} else {
|
|
19
|
-
const path = extractPathFromSelector(target);
|
|
20
|
-
const pathSegments = path.split("/").filter(Boolean);
|
|
21
|
-
const derivedTags = generateTags(pathSegments);
|
|
22
|
-
const exactTag = derivedTags[derivedTags.length - 1];
|
|
23
|
-
if (exactTag) {
|
|
24
|
-
tags.push(exactTag);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
2
|
+
var INVALIDATION_DEFAULT_KEY = "invalidation:defaultMode";
|
|
3
|
+
function resolveModeTags(context, mode) {
|
|
4
|
+
switch (mode) {
|
|
5
|
+
case "all":
|
|
6
|
+
return context.tags;
|
|
7
|
+
case "self":
|
|
8
|
+
return [context.path.join("/")];
|
|
9
|
+
case "none":
|
|
10
|
+
return [];
|
|
28
11
|
}
|
|
29
|
-
return tags;
|
|
30
12
|
}
|
|
31
|
-
function resolveInvalidateTags(context,
|
|
13
|
+
function resolveInvalidateTags(context, defaultMode) {
|
|
32
14
|
const pluginOptions = context.pluginOptions;
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
|
|
15
|
+
const invalidateOption = pluginOptions?.invalidate;
|
|
16
|
+
if (!invalidateOption) {
|
|
17
|
+
const overrideDefault = context.metadata.get(INVALIDATION_DEFAULT_KEY);
|
|
18
|
+
const effectiveDefault = overrideDefault ?? defaultMode;
|
|
19
|
+
return resolveModeTags(context, effectiveDefault);
|
|
36
20
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
tags
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
21
|
+
if (typeof invalidateOption === "string") {
|
|
22
|
+
return resolveModeTags(context, invalidateOption);
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(invalidateOption)) {
|
|
25
|
+
const tags = [];
|
|
26
|
+
let mode = "none";
|
|
27
|
+
for (const item of invalidateOption) {
|
|
28
|
+
if (item === "all" || item === "self") {
|
|
29
|
+
mode = item;
|
|
30
|
+
} else if (typeof item === "string") {
|
|
31
|
+
tags.push(item);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
tags.push(...resolveModeTags(context, mode));
|
|
35
|
+
return [...new Set(tags)];
|
|
45
36
|
}
|
|
46
|
-
return [
|
|
37
|
+
return [];
|
|
47
38
|
}
|
|
48
39
|
function invalidationPlugin(config = {}) {
|
|
49
|
-
const {
|
|
40
|
+
const { defaultMode = "all" } = config;
|
|
50
41
|
return {
|
|
51
42
|
name: "spoosh:invalidation",
|
|
52
43
|
operations: ["write"],
|
|
53
44
|
exports(context) {
|
|
54
45
|
return {
|
|
55
|
-
|
|
46
|
+
setDefaultMode(value) {
|
|
56
47
|
context.metadata.set(INVALIDATION_DEFAULT_KEY, value);
|
|
57
48
|
}
|
|
58
49
|
};
|
|
59
50
|
},
|
|
60
51
|
onResponse(context, response) {
|
|
61
52
|
if (!response.error) {
|
|
62
|
-
const tags = resolveInvalidateTags(context,
|
|
53
|
+
const tags = resolveInvalidateTags(context, defaultMode);
|
|
63
54
|
if (tags.length > 0) {
|
|
64
55
|
context.stateManager.markStale(tags);
|
|
65
56
|
context.eventEmitter.emit("invalidate", tags);
|
|
@@ -69,7 +60,7 @@ function invalidationPlugin(config = {}) {
|
|
|
69
60
|
instanceApi(context) {
|
|
70
61
|
const { stateManager, eventEmitter } = context;
|
|
71
62
|
const invalidate = (input) => {
|
|
72
|
-
const tags =
|
|
63
|
+
const tags = Array.isArray(input) ? input : [input];
|
|
73
64
|
if (tags.length > 0) {
|
|
74
65
|
stateManager.markStale(tags);
|
|
75
66
|
eventEmitter.emit("invalidate", tags);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spoosh/plugin-invalidation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Cache invalidation plugin for Spoosh - auto-invalidates after mutations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"@spoosh/core": ">=0.6.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@spoosh/
|
|
40
|
-
"@spoosh/
|
|
39
|
+
"@spoosh/core": "0.6.0",
|
|
40
|
+
"@spoosh/test-utils": "0.1.5"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"dev": "tsup --watch",
|