@spoosh/plugin-debounce 0.2.5 → 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 CHANGED
@@ -16,7 +16,7 @@ npm install @spoosh/plugin-debounce
16
16
  import { Spoosh } from "@spoosh/core";
17
17
  import { debouncePlugin } from "@spoosh/plugin-debounce";
18
18
 
19
- const client = new Spoosh<ApiSchema, Error>("/api").use([debouncePlugin()]);
19
+ const spoosh = new Spoosh<ApiSchema, Error>("/api").use([debouncePlugin()]);
20
20
 
21
21
  // Wait 300ms after typing stops before fetching
22
22
  const { data } = useRead(
package/dist/index.d.mts CHANGED
@@ -39,7 +39,7 @@ declare module "@spoosh/core" {
39
39
  * ```ts
40
40
  * import { Spoosh } from "@spoosh/core";
41
41
  *
42
- * const client = new Spoosh<ApiSchema, Error>("/api")
42
+ * const spoosh = new Spoosh<ApiSchema, Error>("/api")
43
43
  * .use([
44
44
  * // ... other plugins
45
45
  * debouncePlugin(),
package/dist/index.d.ts CHANGED
@@ -39,7 +39,7 @@ declare module "@spoosh/core" {
39
39
  * ```ts
40
40
  * import { Spoosh } from "@spoosh/core";
41
41
  *
42
- * const client = new Spoosh<ApiSchema, Error>("/api")
42
+ * const spoosh = new Spoosh<ApiSchema, Error>("/api")
43
43
  * .use([
44
44
  * // ... other plugins
45
45
  * debouncePlugin(),
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ __export(src_exports, {
25
25
  module.exports = __toCommonJS(src_exports);
26
26
 
27
27
  // src/plugin.ts
28
+ var PLUGIN_NAME = "spoosh:debounce";
28
29
  function resolveDebounceMs(debounce, context) {
29
30
  if (debounce === void 0) return 0;
30
31
  if (typeof debounce === "number") return debounce;
@@ -34,8 +35,9 @@ function debouncePlugin() {
34
35
  const timers = /* @__PURE__ */ new Map();
35
36
  const latestQueryKeys = /* @__PURE__ */ new Map();
36
37
  const prevRequests = /* @__PURE__ */ new Map();
38
+ const eventTracers = /* @__PURE__ */ new Map();
37
39
  return {
38
- name: "spoosh:debounce",
40
+ name: PLUGIN_NAME,
39
41
  operations: ["read", "infiniteRead"],
40
42
  lifecycle: {
41
43
  onUnmount: (context) => {
@@ -51,9 +53,12 @@ function debouncePlugin() {
51
53
  }
52
54
  },
53
55
  middleware: async (context, next) => {
56
+ const t = context.tracer?.(PLUGIN_NAME);
57
+ const et = context.eventTracer?.(PLUGIN_NAME);
54
58
  const pluginOptions = context.pluginOptions;
55
59
  const debounceOption = pluginOptions?.debounce;
56
60
  if (debounceOption === void 0 || context.forceRefetch) {
61
+ t?.skip("No debounce configured");
57
62
  return next();
58
63
  }
59
64
  const { queryKey, request, path, method } = context;
@@ -74,26 +79,47 @@ function debouncePlugin() {
74
79
  const debounceMs = resolveDebounceMs(debounceOption, prevContext);
75
80
  prevRequests.set(stableKey, currentRequest);
76
81
  if (!debounceMs || debounceMs <= 0) {
82
+ t?.skip("Debounce resolved to 0");
77
83
  return next();
78
84
  }
79
85
  const existingQueryKey = latestQueryKeys.get(stableKey);
80
86
  if (existingQueryKey === queryKey) {
81
87
  const cached2 = context.stateManager.getCache(queryKey);
82
88
  if (cached2?.state?.data !== void 0) {
89
+ t?.return("Already debouncing, returning cached", { color: "muted" });
83
90
  return { data: cached2.state.data, status: 200 };
84
91
  }
92
+ t?.return("Already debouncing", { color: "muted" });
85
93
  return { data: void 0, status: 0 };
86
94
  }
87
95
  const existingTimer = timers.get(stableKey);
88
96
  if (existingTimer) {
89
97
  clearTimeout(existingTimer);
98
+ const prevEventTracer = eventTracers.get(stableKey);
99
+ prevEventTracer?.emit("Request cancelled (new input)", {
100
+ queryKey: existingQueryKey,
101
+ color: "warning"
102
+ });
90
103
  }
91
104
  latestQueryKeys.set(stableKey, queryKey);
105
+ if (et) {
106
+ eventTracers.set(stableKey, et);
107
+ }
108
+ et?.emit(`Request debounced (${debounceMs}ms)`, {
109
+ queryKey,
110
+ color: "info",
111
+ meta: { delay: debounceMs }
112
+ });
92
113
  const cached = context.stateManager.getCache(queryKey);
93
114
  const timer = setTimeout(() => {
94
115
  timers.delete(stableKey);
95
116
  const latestKey = latestQueryKeys.get(stableKey);
96
117
  if (latestKey) {
118
+ const storedEventTracer = eventTracers.get(stableKey);
119
+ storedEventTracer?.emit("Debounce complete, triggering request", {
120
+ queryKey: latestKey,
121
+ color: "success"
122
+ });
97
123
  context.eventEmitter.emit("refetch", {
98
124
  queryKey: latestKey,
99
125
  reason: "invalidate"
@@ -102,8 +128,10 @@ function debouncePlugin() {
102
128
  }, debounceMs);
103
129
  timers.set(stableKey, timer);
104
130
  if (cached?.state?.data !== void 0) {
131
+ t?.return("Debounced, returning cached", { color: "info" });
105
132
  return { data: cached.state.data, status: 200 };
106
133
  }
134
+ t?.return("Debounced, no cached data", { color: "info" });
107
135
  return { data: void 0, status: 0 };
108
136
  }
109
137
  };
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/plugin.ts
2
+ var PLUGIN_NAME = "spoosh:debounce";
2
3
  function resolveDebounceMs(debounce, context) {
3
4
  if (debounce === void 0) return 0;
4
5
  if (typeof debounce === "number") return debounce;
@@ -8,8 +9,9 @@ function debouncePlugin() {
8
9
  const timers = /* @__PURE__ */ new Map();
9
10
  const latestQueryKeys = /* @__PURE__ */ new Map();
10
11
  const prevRequests = /* @__PURE__ */ new Map();
12
+ const eventTracers = /* @__PURE__ */ new Map();
11
13
  return {
12
- name: "spoosh:debounce",
14
+ name: PLUGIN_NAME,
13
15
  operations: ["read", "infiniteRead"],
14
16
  lifecycle: {
15
17
  onUnmount: (context) => {
@@ -25,9 +27,12 @@ function debouncePlugin() {
25
27
  }
26
28
  },
27
29
  middleware: async (context, next) => {
30
+ const t = context.tracer?.(PLUGIN_NAME);
31
+ const et = context.eventTracer?.(PLUGIN_NAME);
28
32
  const pluginOptions = context.pluginOptions;
29
33
  const debounceOption = pluginOptions?.debounce;
30
34
  if (debounceOption === void 0 || context.forceRefetch) {
35
+ t?.skip("No debounce configured");
31
36
  return next();
32
37
  }
33
38
  const { queryKey, request, path, method } = context;
@@ -48,26 +53,47 @@ function debouncePlugin() {
48
53
  const debounceMs = resolveDebounceMs(debounceOption, prevContext);
49
54
  prevRequests.set(stableKey, currentRequest);
50
55
  if (!debounceMs || debounceMs <= 0) {
56
+ t?.skip("Debounce resolved to 0");
51
57
  return next();
52
58
  }
53
59
  const existingQueryKey = latestQueryKeys.get(stableKey);
54
60
  if (existingQueryKey === queryKey) {
55
61
  const cached2 = context.stateManager.getCache(queryKey);
56
62
  if (cached2?.state?.data !== void 0) {
63
+ t?.return("Already debouncing, returning cached", { color: "muted" });
57
64
  return { data: cached2.state.data, status: 200 };
58
65
  }
66
+ t?.return("Already debouncing", { color: "muted" });
59
67
  return { data: void 0, status: 0 };
60
68
  }
61
69
  const existingTimer = timers.get(stableKey);
62
70
  if (existingTimer) {
63
71
  clearTimeout(existingTimer);
72
+ const prevEventTracer = eventTracers.get(stableKey);
73
+ prevEventTracer?.emit("Request cancelled (new input)", {
74
+ queryKey: existingQueryKey,
75
+ color: "warning"
76
+ });
64
77
  }
65
78
  latestQueryKeys.set(stableKey, queryKey);
79
+ if (et) {
80
+ eventTracers.set(stableKey, et);
81
+ }
82
+ et?.emit(`Request debounced (${debounceMs}ms)`, {
83
+ queryKey,
84
+ color: "info",
85
+ meta: { delay: debounceMs }
86
+ });
66
87
  const cached = context.stateManager.getCache(queryKey);
67
88
  const timer = setTimeout(() => {
68
89
  timers.delete(stableKey);
69
90
  const latestKey = latestQueryKeys.get(stableKey);
70
91
  if (latestKey) {
92
+ const storedEventTracer = eventTracers.get(stableKey);
93
+ storedEventTracer?.emit("Debounce complete, triggering request", {
94
+ queryKey: latestKey,
95
+ color: "success"
96
+ });
71
97
  context.eventEmitter.emit("refetch", {
72
98
  queryKey: latestKey,
73
99
  reason: "invalidate"
@@ -76,8 +102,10 @@ function debouncePlugin() {
76
102
  }, debounceMs);
77
103
  timers.set(stableKey, timer);
78
104
  if (cached?.state?.data !== void 0) {
105
+ t?.return("Debounced, returning cached", { color: "info" });
79
106
  return { data: cached.state.data, status: 200 };
80
107
  }
108
+ t?.return("Debounced, no cached data", { color: "info" });
81
109
  return { data: void 0, status: 0 };
82
110
  }
83
111
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spoosh/plugin-debounce",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "Request debouncing plugin for Spoosh - waits for inactivity before fetching",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,11 +33,11 @@
33
33
  }
34
34
  },
35
35
  "peerDependencies": {
36
- "@spoosh/core": ">=0.12.0"
36
+ "@spoosh/core": ">=0.13.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@spoosh/core": "0.12.0",
40
- "@spoosh/test-utils": "0.1.8"
39
+ "@spoosh/core": "0.13.0",
40
+ "@spoosh/test-utils": "0.2.0"
41
41
  },
42
42
  "scripts": {
43
43
  "dev": "tsup --watch",