@mmstack/resource 19.3.1 → 19.3.2

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.
@@ -62,10 +62,16 @@ export type QueryResourceOptions<TResult, TRaw = TResult> = HttpResourceOptions<
62
62
  */
63
63
  retry?: RetryOptions;
64
64
  /**
65
- * An optional error handler callback. This function will be called whenever the
66
- * underlying HTTP request fails. Useful for displaying toasts or other error messages.
65
+ * Called on every failed attempt, including each retry.
66
+ *
67
+ * @param err - The error from the underlying HTTP request.
68
+ * @param retryCount - The number of retries that already happened before
69
+ * this error (`0` on the original failure, `1` after the first retry, etc.).
70
+ * @param isFinal - `true` when no further retry will be scheduled — either
71
+ * because retries are exhausted or `retry` was unset/0. Branch on this for
72
+ * "user actually needs to know" side effects (toasts, error reporting).
67
73
  */
68
- onError?: (err: unknown) => void;
74
+ onError?: (err: unknown, retryCount: number, isFinal: boolean) => void;
69
75
  /**
70
76
  * Options for configuring a circuit breaker for the resource.
71
77
  */
@@ -80,6 +86,12 @@ export type QueryResourceOptions<TResult, TRaw = TResult> = HttpResourceOptions<
80
86
  */
81
87
  triggerOnSameRequest?: boolean;
82
88
  };
89
+ /**
90
+ * The reason a query resource is currently in the `disabled` state, or `null`
91
+ * if it is enabled. Useful for branching UI on cause (e.g. "offline" vs
92
+ * "circuit tripped" vs "nothing to fetch yet").
93
+ */
94
+ export type DisabledReason = 'offline' | 'circuit-open' | 'no-request';
83
95
  /**
84
96
  * Represents a resource created by `queryResource`. Extends `HttpResourceRef` with additional properties.
85
97
  */
@@ -93,9 +105,14 @@ export type QueryResourceRef<TResult> = Omit<HttpResourceRef<TResult>, 'headers'
93
105
  */
94
106
  readonly statusCode: WritableSignal<number | undefined>;
95
107
  /**
96
- * A signal indicating whether the resource is currently disabled (due to circuit breaker or undefined request).
108
+ * A signal indicating whether the resource is currently disabled (due to circuit breaker, offline, or undefined request).
97
109
  */
98
110
  disabled: Signal<boolean>;
111
+ /**
112
+ * Why the resource is currently disabled, or `null` if it is enabled.
113
+ * Maps to one of: `'offline'`, `'circuit-open'`, `'no-request'`.
114
+ */
115
+ disabledReason: Signal<DisabledReason | null>;
99
116
  /**
100
117
  * Prefetches data for the resource, populating the cache if caching is enabled. This can be
101
118
  * used to proactively load data before it's needed. If a slow connection is detected, prefetching is skipped.
@@ -135,6 +135,24 @@ export declare class Cache<T> {
135
135
  * @param key - The key of the entry to invalidate.
136
136
  */
137
137
  invalidate(key: string): void;
138
+ /**
139
+ * Invalidates every cache entry whose key starts with `prefix`. Common after a
140
+ * list-mutating operation (e.g. invalidate every paginated `GET /api/posts*`
141
+ * after a POST). Returns the number of entries removed.
142
+ *
143
+ * @example
144
+ * cache.invalidatePrefix('GET https://api.example.com/posts');
145
+ */
146
+ invalidatePrefix(prefix: string): number;
147
+ /**
148
+ * Invalidates every cache entry whose key matches the predicate. Use for
149
+ * arbitrary bulk invalidation that doesn't fit prefix matching (e.g.
150
+ * "everything containing `userId=42`"). Returns the number of entries removed.
151
+ *
152
+ * @example
153
+ * cache.invalidateWhere((key) => key.includes('/me/'));
154
+ */
155
+ invalidateWhere(predicate: (key: string) => boolean): number;
138
156
  private invalidateInternal;
139
157
  /** @internal */
140
158
  private cleanup;
@@ -37,6 +37,13 @@ export type CircuitBreaker = {
37
37
  * to test if the underlying issue has been resolved after the circuit breaker has been open.
38
38
  */
39
39
  halfOpen: () => void;
40
+ /**
41
+ * Fully resets the breaker state — clears the failure count, drops the half-open
42
+ * flag, and lifts a permanent open caused by `shouldFailForever`. Use after the
43
+ * underlying condition has been resolved (e.g. user re-authenticated after a
44
+ * 401-triggered permanent open).
45
+ */
46
+ hardReset: () => void;
40
47
  /**
41
48
  * Destroys the circuit breaker & initiates related cleanup
42
49
  */
@@ -50,6 +57,10 @@ type CreateCircuitBreakerOptions = {
50
57
  * The number of failures that will cause the circuit breaker to open.
51
58
  * @default 5
52
59
  */
60
+ threshold?: number;
61
+ /**
62
+ * @deprecated Misspelled — use `threshold` instead. Kept for backwards compatibility; will be removed in a future major.
63
+ */
53
64
  treshold?: number;
54
65
  /**
55
66
  * The time in milliseconds after which the circuit breaker will reset and allow operations to proceed again.
@@ -63,6 +74,7 @@ type CreateCircuitBreakerOptions = {
63
74
  shouldFail?: (err?: Error) => boolean;
64
75
  /**
65
76
  * A function that determines whether an error should cause the circuit breaker to be open forever.
77
+ * `hardReset()` is required to lift this state.
66
78
  * @default Always returns false
67
79
  */
68
80
  shouldFailForever?: (err?: Error) => boolean;
@@ -72,16 +84,39 @@ type CreateCircuitBreakerOptions = {
72
84
  * - `false`: Disables circuit breaker functionality (always open).
73
85
  * - true: Creates a new circuit breaker with default options.
74
86
  * - `CircuitBreaker`: Provides an existing `CircuitBreaker` instance to use.
75
- * - `{ treshold?: number; timeout?: number; }`: Creates a new circuit breaker with the specified options.
87
+ * - `{ threshold?: number; timeout?: number; }`: Creates a new circuit breaker with the specified options.
76
88
  */
77
89
  export type CircuitBreakerOptions = false | CircuitBreaker | CreateCircuitBreakerOptions;
90
+ /**
91
+ * Provides application-wide default options for {@link createCircuitBreaker}.
92
+ * Any `createCircuitBreaker()` call without explicit options (or with only
93
+ * partial options) merges these defaults in, so you can centralize threshold /
94
+ * timeout / failure-classifier behavior in one place.
95
+ *
96
+ * Per-call options always win over the provided defaults.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * bootstrapApplication(AppComponent, {
101
+ * providers: [
102
+ * provideCircuitBreakerDefaultOptions({
103
+ * threshold: 10,
104
+ * timeout: 60_000,
105
+ * shouldFailForever: (err) =>
106
+ * err instanceof HttpErrorResponse && [401, 403].includes(err.status),
107
+ * }),
108
+ * ],
109
+ * });
110
+ * ```
111
+ */
78
112
  export declare function provideCircuitBreakerDefaultOptions(options: CircuitBreakerOptions): Provider;
79
113
  /**
80
114
  * Creates a circuit breaker instance.
81
115
  *
82
116
  * @param options - Configuration options for the circuit breaker. Can be:
83
- * - `undefined`: Creates a "no-op" circuit breaker that is always open (never trips).
84
- * - `true`: Creates a circuit breaker with default settings (threshold: 5, timeout: 30000ms).
117
+ * - `undefined`: Uses defaults (threshold: 5, timeout: 30000ms) or provided defaults via {@link provideCircuitBreakerDefaultOptions}.
118
+ * - `false`: Creates a "no-op" circuit breaker that is always closed (never trips).
119
+ * - `true`: Creates a circuit breaker with default settings.
85
120
  * - `CircuitBreaker`: Reuses an existing `CircuitBreaker` instance.
86
121
  * - `{ threshold?: number; timeout?: number; }`: Creates a circuit breaker with the specified threshold and timeout.
87
122
  *
@@ -3,4 +3,12 @@ export type RetryOptions = number | {
3
3
  max?: number;
4
4
  backoff?: number;
5
5
  };
6
- export declare function retryOnError<T>(res: HttpResourceRef<T>, opt?: RetryOptions): HttpResourceRef<T>;
6
+ /**
7
+ * Callback fired by the retry wrapper for every failed attempt.
8
+ * `retryCount` is the number of retries that already happened before this
9
+ * error (`0` on the original failure, `1` after the first retry, etc.).
10
+ * `isFinal` is `true` when no further retry will be scheduled — either because
11
+ * retries are exhausted or `retry` was unset/0.
12
+ */
13
+ export type RetryErrorCallback<TError = unknown> = (err: TError, retryCount: number, isFinal: boolean) => void;
14
+ export declare function retryOnError<T>(res: HttpResourceRef<T>, opt?: RetryOptions, onError?: RetryErrorCallback): HttpResourceRef<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/resource",
3
- "version": "19.3.1",
3
+ "version": "19.3.2",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",