@gusnips/react 0.9.16 → 0.9.18

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/dist/query.d.ts CHANGED
@@ -66,8 +66,8 @@ export interface QueryDefaultsOptions {
66
66
  */
67
67
  export declare function shouldRetry(error: unknown, durableLimitCodes?: readonly string[], maxRetryWaitSecs?: number): boolean;
68
68
  /**
69
- * How long before the next attempt: the server's stated wait when there is one, react-query's
70
- * exponential backoff otherwise, and never less than the backoff — a `Retry-After: 0` is a
69
+ * How long before the next attempt: the server's stated wait when there is one, an exponential
70
+ * backoff with jitter otherwise, and never less than the backoff — a `Retry-After: 0` is a
71
71
  * server saying "immediately", which for a client that just got refused is still too soon.
72
72
  */
73
73
  export declare function retryDelayMs(attemptIndex: number, error: unknown): number;
package/dist/query.js CHANGED
@@ -15,8 +15,8 @@ export function shouldRetry(error, durableLimitCodes = [], maxRetryWaitSecs) {
15
15
  });
16
16
  }
17
17
  /**
18
- * How long before the next attempt: the server's stated wait when there is one, react-query's
19
- * exponential backoff otherwise, and never less than the backoff — a `Retry-After: 0` is a
18
+ * How long before the next attempt: the server's stated wait when there is one, an exponential
19
+ * backoff with jitter otherwise, and never less than the backoff — a `Retry-After: 0` is a
20
20
  * server saying "immediately", which for a client that just got refused is still too soon.
21
21
  */
22
22
  export function retryDelayMs(attemptIndex, error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gusnips/react",
3
- "version": "0.9.16",
3
+ "version": "0.9.18",
4
4
  "description": "The headless runtime under a Vite + React SPA: typed fetch client with single-flight refresh, auth store, query defaults, route guards, error boundary, stale-tab recovery, i18n bootstrap.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -80,7 +80,7 @@
80
80
  "release:major": "bun pm version major && bun publish --access public"
81
81
  },
82
82
  "dependencies": {
83
- "@gusnips/http": "0.1.3",
83
+ "@gusnips/http": "0.1.5",
84
84
  "clsx": "^2.1.1",
85
85
  "tailwind-merge": "^3.6.0"
86
86
  },
package/src/query.test.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { QueryClient, QueryObserver, type QueryObserverResult } from "@tanstack/react-query";
2
- import { describe, expect, it } from "vitest";
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
3
  import { ApiError } from "./api-error.ts";
4
4
  import { queryView, retryDelayMs, shouldRetry } from "./query.ts";
5
5
 
@@ -32,9 +32,10 @@ describe("shouldRetry", () => {
32
32
  it("reads only its own ApiError as an answer", () => {
33
33
  const vendor = Object.assign(new Error("Invalid login credentials"), { status: 400 });
34
34
  expect(shouldRetry(vendor)).toBe(true);
35
- expect(retryDelayMs(0, Object.assign(new Error("x"), { status: 429, retryAfterSecs: 5 }))).toBe(
36
- 1000,
37
- );
35
+ // The first backoff is at most 1.5 s, so 5 s would be the vendor's wait read as the server's.
36
+ expect(
37
+ retryDelayMs(0, Object.assign(new Error("x"), { status: 429, retryAfterSecs: 5 })),
38
+ ).toBeLessThan(5000);
38
39
  });
39
40
 
40
41
  it("retries 5xx", () => {
@@ -135,6 +136,14 @@ describe("shouldRetry", () => {
135
136
  });
136
137
 
137
138
  describe("retryDelayMs", () => {
139
+ // The middle of the jitter, so the numbers below are the backoff itself.
140
+ beforeEach(() => {
141
+ vi.spyOn(Math, "random").mockReturnValue(0.5);
142
+ });
143
+ afterEach(() => {
144
+ vi.restoreAllMocks();
145
+ });
146
+
138
147
  it("backs off exponentially when nothing said how long", () => {
139
148
  expect(retryDelayMs(0, refusal(500))).toBe(1000);
140
149
  expect(retryDelayMs(1, refusal(500))).toBe(2000);
package/src/query.ts CHANGED
@@ -83,8 +83,8 @@ export function shouldRetry(
83
83
  }
84
84
 
85
85
  /**
86
- * How long before the next attempt: the server's stated wait when there is one, react-query's
87
- * exponential backoff otherwise, and never less than the backoff — a `Retry-After: 0` is a
86
+ * How long before the next attempt: the server's stated wait when there is one, an exponential
87
+ * backoff with jitter otherwise, and never less than the backoff — a `Retry-After: 0` is a
88
88
  * server saying "immediately", which for a client that just got refused is still too soon.
89
89
  */
90
90
  export function retryDelayMs(attemptIndex: number, error: unknown): number {