@sanity/client 7.20.0 → 7.21.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.
@@ -804,6 +804,32 @@ export declare interface ClientConfig {
804
804
  * Lineage token for recursion control
805
805
  */
806
806
  lineage?: string
807
+ /**
808
+ * A custom request handler that intercepts all HTTP requests made by the client.
809
+ *
810
+ * Useful for logging, adding custom headers, refreshing auth tokens, rate limiting, etc.
811
+ *
812
+ * When using `withConfig()`, the new handler **replaces** the previous one (it does not
813
+ * wrap it). To compose handlers, you can chain them manually:
814
+ *
815
+ * ```ts
816
+ * const parent = createClient({...config, _requestHandler: handlerA})
817
+ * const child = parent.withConfig({
818
+ * _requestHandler: (req, defaultRequester) =>
819
+ * handlerB(req, (opts) => handlerA(opts, defaultRequester)),
820
+ * })
821
+ * ```
822
+ *
823
+ * Setting `_requestHandler` to `undefined` via `withConfig()` removes the handler.
824
+ *
825
+ * Note: This only applies to HTTP requests. Real-time listener connections
826
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
827
+ *
828
+ * @internal
829
+ * @deprecated Don't use outside of Sanity internals
830
+ * @see {@link RequestHandler}
831
+ */
832
+ _requestHandler?: RequestHandler
807
833
  }
808
834
 
809
835
  declare type ClientConfigResource =
@@ -2318,6 +2344,7 @@ export declare class LiveClient {
2318
2344
  events({
2319
2345
  includeDrafts,
2320
2346
  tag: _tag,
2347
+ waitFor,
2321
2348
  }?: {
2322
2349
  includeDrafts?: boolean
2323
2350
  /**
@@ -2326,6 +2353,11 @@ export declare class LiveClient {
2326
2353
  * @defaultValue `undefined`
2327
2354
  */
2328
2355
  tag?: string
2356
+ /**
2357
+ * Delays events until after a Sanity Function has processed them and called the callback endpoint.
2358
+ * When omitted, events are delivered immediately.
2359
+ */
2360
+ waitFor?: 'function'
2329
2361
  }): Observable<LiveEvent>
2330
2362
  }
2331
2363
 
@@ -4951,6 +4983,44 @@ export declare interface ReplaceVersionAction {
4951
4983
  */
4952
4984
  export declare const requester: Requester
4953
4985
 
4986
+ /**
4987
+ * A function that intercepts HTTP requests made by the client.
4988
+ *
4989
+ * Receives the resolved request options, a `defaultRequester` function that
4990
+ * executes the request through the normal pipeline, and a `client` instance
4991
+ * without a `_requestHandler` (to avoid recursive interception).
4992
+ *
4993
+ * The consumer can:
4994
+ * - Modify request options before calling `defaultRequester`
4995
+ * - Transform the response stream (e.g. via `pipe`)
4996
+ * - Skip `defaultRequester` entirely and return a custom Observable
4997
+ * - Use `client` to make additional requests (e.g. refresh an auth token on 401)
4998
+ *
4999
+ * When set via `withConfig()`, the new handler **replaces** (not wraps) the previous one.
5000
+ *
5001
+ * Note: This only applies to HTTP requests. Real-time listener connections
5002
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
5003
+ *
5004
+ * @param request - The resolved request options including `url`
5005
+ * @param defaultRequester - Executes the request through the normal pipeline
5006
+ * @param client - A client instance with the same configuration but without a `_requestHandler`,
5007
+ * useful for making side requests (e.g. token refresh) without triggering the handler recursively
5008
+ *
5009
+ * @internal
5010
+ * @deprecated Don't use outside of Sanity internals
5011
+ */
5012
+ export declare type RequestHandler = (
5013
+ request: RequestOptions & {
5014
+ url: string
5015
+ },
5016
+ defaultRequester: (
5017
+ options: RequestOptions & {
5018
+ url: string
5019
+ },
5020
+ ) => Observable<HttpRequestEvent>,
5021
+ client: SanityClient,
5022
+ ) => Observable<HttpRequestEvent>
5023
+
4954
5024
  /** @internal */
4955
5025
  export declare interface RequestObservableOptions extends Omit<RequestOptions, 'url'> {
4956
5026
  url?: string
@@ -804,6 +804,32 @@ export declare interface ClientConfig {
804
804
  * Lineage token for recursion control
805
805
  */
806
806
  lineage?: string
807
+ /**
808
+ * A custom request handler that intercepts all HTTP requests made by the client.
809
+ *
810
+ * Useful for logging, adding custom headers, refreshing auth tokens, rate limiting, etc.
811
+ *
812
+ * When using `withConfig()`, the new handler **replaces** the previous one (it does not
813
+ * wrap it). To compose handlers, you can chain them manually:
814
+ *
815
+ * ```ts
816
+ * const parent = createClient({...config, _requestHandler: handlerA})
817
+ * const child = parent.withConfig({
818
+ * _requestHandler: (req, defaultRequester) =>
819
+ * handlerB(req, (opts) => handlerA(opts, defaultRequester)),
820
+ * })
821
+ * ```
822
+ *
823
+ * Setting `_requestHandler` to `undefined` via `withConfig()` removes the handler.
824
+ *
825
+ * Note: This only applies to HTTP requests. Real-time listener connections
826
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
827
+ *
828
+ * @internal
829
+ * @deprecated Don't use outside of Sanity internals
830
+ * @see {@link RequestHandler}
831
+ */
832
+ _requestHandler?: RequestHandler
807
833
  }
808
834
 
809
835
  declare type ClientConfigResource =
@@ -2318,6 +2344,7 @@ export declare class LiveClient {
2318
2344
  events({
2319
2345
  includeDrafts,
2320
2346
  tag: _tag,
2347
+ waitFor,
2321
2348
  }?: {
2322
2349
  includeDrafts?: boolean
2323
2350
  /**
@@ -2326,6 +2353,11 @@ export declare class LiveClient {
2326
2353
  * @defaultValue `undefined`
2327
2354
  */
2328
2355
  tag?: string
2356
+ /**
2357
+ * Delays events until after a Sanity Function has processed them and called the callback endpoint.
2358
+ * When omitted, events are delivered immediately.
2359
+ */
2360
+ waitFor?: 'function'
2329
2361
  }): Observable<LiveEvent>
2330
2362
  }
2331
2363
 
@@ -4951,6 +4983,44 @@ export declare interface ReplaceVersionAction {
4951
4983
  */
4952
4984
  export declare const requester: Requester
4953
4985
 
4986
+ /**
4987
+ * A function that intercepts HTTP requests made by the client.
4988
+ *
4989
+ * Receives the resolved request options, a `defaultRequester` function that
4990
+ * executes the request through the normal pipeline, and a `client` instance
4991
+ * without a `_requestHandler` (to avoid recursive interception).
4992
+ *
4993
+ * The consumer can:
4994
+ * - Modify request options before calling `defaultRequester`
4995
+ * - Transform the response stream (e.g. via `pipe`)
4996
+ * - Skip `defaultRequester` entirely and return a custom Observable
4997
+ * - Use `client` to make additional requests (e.g. refresh an auth token on 401)
4998
+ *
4999
+ * When set via `withConfig()`, the new handler **replaces** (not wraps) the previous one.
5000
+ *
5001
+ * Note: This only applies to HTTP requests. Real-time listener connections
5002
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
5003
+ *
5004
+ * @param request - The resolved request options including `url`
5005
+ * @param defaultRequester - Executes the request through the normal pipeline
5006
+ * @param client - A client instance with the same configuration but without a `_requestHandler`,
5007
+ * useful for making side requests (e.g. token refresh) without triggering the handler recursively
5008
+ *
5009
+ * @internal
5010
+ * @deprecated Don't use outside of Sanity internals
5011
+ */
5012
+ export declare type RequestHandler = (
5013
+ request: RequestOptions & {
5014
+ url: string
5015
+ },
5016
+ defaultRequester: (
5017
+ options: RequestOptions & {
5018
+ url: string
5019
+ },
5020
+ ) => Observable<HttpRequestEvent>,
5021
+ client: SanityClient,
5022
+ ) => Observable<HttpRequestEvent>
5023
+
4954
5024
  /** @internal */
4955
5025
  export declare interface RequestObservableOptions extends Omit<RequestOptions, 'url'> {
4956
5026
  url?: string
package/dist/stega.d.cts CHANGED
@@ -804,6 +804,32 @@ export declare interface ClientConfig {
804
804
  * Lineage token for recursion control
805
805
  */
806
806
  lineage?: string
807
+ /**
808
+ * A custom request handler that intercepts all HTTP requests made by the client.
809
+ *
810
+ * Useful for logging, adding custom headers, refreshing auth tokens, rate limiting, etc.
811
+ *
812
+ * When using `withConfig()`, the new handler **replaces** the previous one (it does not
813
+ * wrap it). To compose handlers, you can chain them manually:
814
+ *
815
+ * ```ts
816
+ * const parent = createClient({...config, _requestHandler: handlerA})
817
+ * const child = parent.withConfig({
818
+ * _requestHandler: (req, defaultRequester) =>
819
+ * handlerB(req, (opts) => handlerA(opts, defaultRequester)),
820
+ * })
821
+ * ```
822
+ *
823
+ * Setting `_requestHandler` to `undefined` via `withConfig()` removes the handler.
824
+ *
825
+ * Note: This only applies to HTTP requests. Real-time listener connections
826
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
827
+ *
828
+ * @internal
829
+ * @deprecated Don't use outside of Sanity internals
830
+ * @see {@link RequestHandler}
831
+ */
832
+ _requestHandler?: RequestHandler
807
833
  }
808
834
 
809
835
  declare type ClientConfigResource =
@@ -2318,6 +2344,7 @@ export declare class LiveClient {
2318
2344
  events({
2319
2345
  includeDrafts,
2320
2346
  tag: _tag,
2347
+ waitFor,
2321
2348
  }?: {
2322
2349
  includeDrafts?: boolean
2323
2350
  /**
@@ -2326,6 +2353,11 @@ export declare class LiveClient {
2326
2353
  * @defaultValue `undefined`
2327
2354
  */
2328
2355
  tag?: string
2356
+ /**
2357
+ * Delays events until after a Sanity Function has processed them and called the callback endpoint.
2358
+ * When omitted, events are delivered immediately.
2359
+ */
2360
+ waitFor?: 'function'
2329
2361
  }): Observable<LiveEvent>
2330
2362
  }
2331
2363
 
@@ -4951,6 +4983,44 @@ export declare interface ReplaceVersionAction {
4951
4983
  */
4952
4984
  export declare const requester: Requester
4953
4985
 
4986
+ /**
4987
+ * A function that intercepts HTTP requests made by the client.
4988
+ *
4989
+ * Receives the resolved request options, a `defaultRequester` function that
4990
+ * executes the request through the normal pipeline, and a `client` instance
4991
+ * without a `_requestHandler` (to avoid recursive interception).
4992
+ *
4993
+ * The consumer can:
4994
+ * - Modify request options before calling `defaultRequester`
4995
+ * - Transform the response stream (e.g. via `pipe`)
4996
+ * - Skip `defaultRequester` entirely and return a custom Observable
4997
+ * - Use `client` to make additional requests (e.g. refresh an auth token on 401)
4998
+ *
4999
+ * When set via `withConfig()`, the new handler **replaces** (not wraps) the previous one.
5000
+ *
5001
+ * Note: This only applies to HTTP requests. Real-time listener connections
5002
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
5003
+ *
5004
+ * @param request - The resolved request options including `url`
5005
+ * @param defaultRequester - Executes the request through the normal pipeline
5006
+ * @param client - A client instance with the same configuration but without a `_requestHandler`,
5007
+ * useful for making side requests (e.g. token refresh) without triggering the handler recursively
5008
+ *
5009
+ * @internal
5010
+ * @deprecated Don't use outside of Sanity internals
5011
+ */
5012
+ export declare type RequestHandler = (
5013
+ request: RequestOptions & {
5014
+ url: string
5015
+ },
5016
+ defaultRequester: (
5017
+ options: RequestOptions & {
5018
+ url: string
5019
+ },
5020
+ ) => Observable<HttpRequestEvent>,
5021
+ client: SanityClient,
5022
+ ) => Observable<HttpRequestEvent>
5023
+
4954
5024
  /** @internal */
4955
5025
  export declare interface RequestObservableOptions extends Omit<RequestOptions, 'url'> {
4956
5026
  url?: string
package/dist/stega.d.ts CHANGED
@@ -804,6 +804,32 @@ export declare interface ClientConfig {
804
804
  * Lineage token for recursion control
805
805
  */
806
806
  lineage?: string
807
+ /**
808
+ * A custom request handler that intercepts all HTTP requests made by the client.
809
+ *
810
+ * Useful for logging, adding custom headers, refreshing auth tokens, rate limiting, etc.
811
+ *
812
+ * When using `withConfig()`, the new handler **replaces** the previous one (it does not
813
+ * wrap it). To compose handlers, you can chain them manually:
814
+ *
815
+ * ```ts
816
+ * const parent = createClient({...config, _requestHandler: handlerA})
817
+ * const child = parent.withConfig({
818
+ * _requestHandler: (req, defaultRequester) =>
819
+ * handlerB(req, (opts) => handlerA(opts, defaultRequester)),
820
+ * })
821
+ * ```
822
+ *
823
+ * Setting `_requestHandler` to `undefined` via `withConfig()` removes the handler.
824
+ *
825
+ * Note: This only applies to HTTP requests. Real-time listener connections
826
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
827
+ *
828
+ * @internal
829
+ * @deprecated Don't use outside of Sanity internals
830
+ * @see {@link RequestHandler}
831
+ */
832
+ _requestHandler?: RequestHandler
807
833
  }
808
834
 
809
835
  declare type ClientConfigResource =
@@ -2318,6 +2344,7 @@ export declare class LiveClient {
2318
2344
  events({
2319
2345
  includeDrafts,
2320
2346
  tag: _tag,
2347
+ waitFor,
2321
2348
  }?: {
2322
2349
  includeDrafts?: boolean
2323
2350
  /**
@@ -2326,6 +2353,11 @@ export declare class LiveClient {
2326
2353
  * @defaultValue `undefined`
2327
2354
  */
2328
2355
  tag?: string
2356
+ /**
2357
+ * Delays events until after a Sanity Function has processed them and called the callback endpoint.
2358
+ * When omitted, events are delivered immediately.
2359
+ */
2360
+ waitFor?: 'function'
2329
2361
  }): Observable<LiveEvent>
2330
2362
  }
2331
2363
 
@@ -4951,6 +4983,44 @@ export declare interface ReplaceVersionAction {
4951
4983
  */
4952
4984
  export declare const requester: Requester
4953
4985
 
4986
+ /**
4987
+ * A function that intercepts HTTP requests made by the client.
4988
+ *
4989
+ * Receives the resolved request options, a `defaultRequester` function that
4990
+ * executes the request through the normal pipeline, and a `client` instance
4991
+ * without a `_requestHandler` (to avoid recursive interception).
4992
+ *
4993
+ * The consumer can:
4994
+ * - Modify request options before calling `defaultRequester`
4995
+ * - Transform the response stream (e.g. via `pipe`)
4996
+ * - Skip `defaultRequester` entirely and return a custom Observable
4997
+ * - Use `client` to make additional requests (e.g. refresh an auth token on 401)
4998
+ *
4999
+ * When set via `withConfig()`, the new handler **replaces** (not wraps) the previous one.
5000
+ *
5001
+ * Note: This only applies to HTTP requests. Real-time listener connections
5002
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
5003
+ *
5004
+ * @param request - The resolved request options including `url`
5005
+ * @param defaultRequester - Executes the request through the normal pipeline
5006
+ * @param client - A client instance with the same configuration but without a `_requestHandler`,
5007
+ * useful for making side requests (e.g. token refresh) without triggering the handler recursively
5008
+ *
5009
+ * @internal
5010
+ * @deprecated Don't use outside of Sanity internals
5011
+ */
5012
+ export declare type RequestHandler = (
5013
+ request: RequestOptions & {
5014
+ url: string
5015
+ },
5016
+ defaultRequester: (
5017
+ options: RequestOptions & {
5018
+ url: string
5019
+ },
5020
+ ) => Observable<HttpRequestEvent>,
5021
+ client: SanityClient,
5022
+ ) => Observable<HttpRequestEvent>
5023
+
4954
5024
  /** @internal */
4955
5025
  export declare interface RequestObservableOptions extends Omit<RequestOptions, 'url'> {
4956
5026
  url?: string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/client",
3
- "version": "7.20.0",
3
+ "version": "7.21.0",
4
4
  "description": "Client for retrieving, creating and patching data from Sanity.io",
5
5
  "keywords": [
6
6
  "sanity",
@@ -130,7 +130,7 @@
130
130
  },
131
131
  "dependencies": {
132
132
  "@sanity/eventsource": "^5.0.2",
133
- "get-it": "^8.7.0",
133
+ "get-it": "^8.7.2",
134
134
  "nanoid": "^3.3.11",
135
135
  "rxjs": "^7.0.0"
136
136
  },
@@ -43,6 +43,7 @@ import type {
43
43
  RawQuerylessQueryResponse,
44
44
  RawQueryResponse,
45
45
  RawRequestOptions,
46
+ RequestOptions,
46
47
  SanityDocument,
47
48
  SanityDocumentStub,
48
49
  SingleActionResult,
@@ -87,6 +88,7 @@ export class ObservableSanityClient {
87
88
  * Private properties
88
89
  */
89
90
  #clientConfig: InitializedClientConfig
91
+ #originalHttpRequest: HttpRequest
90
92
  #httpRequest: HttpRequest
91
93
 
92
94
  /**
@@ -97,7 +99,22 @@ export class ObservableSanityClient {
97
99
  constructor(httpRequest: HttpRequest, config: ClientConfig = defaultConfig) {
98
100
  this.config(config)
99
101
 
100
- this.#httpRequest = httpRequest
102
+ this.#originalHttpRequest = httpRequest
103
+ const requestHandler = config._requestHandler
104
+
105
+ this.#httpRequest = requestHandler
106
+ ? (() => {
107
+ let bareClient: SanityClient | undefined
108
+ const wrapped: HttpRequest = (options, requester) => {
109
+ const opts = options as RequestOptions & {url: string}
110
+ if (!bareClient) {
111
+ bareClient = new SanityClient(httpRequest, {...config, _requestHandler: undefined})
112
+ }
113
+ return requestHandler(opts, (o) => httpRequest(o, requester), bareClient)
114
+ }
115
+ return wrapped
116
+ })()
117
+ : httpRequest
101
118
 
102
119
  this.assets = new ObservableAssetsClient(this, this.#httpRequest)
103
120
  this.datasets = new ObservableDatasetsClient(this, this.#httpRequest)
@@ -117,7 +134,7 @@ export class ObservableSanityClient {
117
134
  * Clone the client - returns a new instance
118
135
  */
119
136
  clone(): ObservableSanityClient {
120
- return new ObservableSanityClient(this.#httpRequest, this.config())
137
+ return new ObservableSanityClient(this.#originalHttpRequest, this.config())
121
138
  }
122
139
 
123
140
  /**
@@ -150,7 +167,7 @@ export class ObservableSanityClient {
150
167
  */
151
168
  withConfig(newConfig?: Partial<ClientConfig>): ObservableSanityClient {
152
169
  const thisConfig = this.config()
153
- return new ObservableSanityClient(this.#httpRequest, {
170
+ return new ObservableSanityClient(this.#originalHttpRequest, {
154
171
  ...thisConfig,
155
172
  ...newConfig,
156
173
  stega: {
@@ -1128,6 +1145,7 @@ export class SanityClient {
1128
1145
  * Private properties
1129
1146
  */
1130
1147
  #clientConfig: InitializedClientConfig
1148
+ #originalHttpRequest: HttpRequest
1131
1149
  #httpRequest: HttpRequest
1132
1150
 
1133
1151
  /**
@@ -1138,7 +1156,21 @@ export class SanityClient {
1138
1156
  constructor(httpRequest: HttpRequest, config: ClientConfig = defaultConfig) {
1139
1157
  this.config(config)
1140
1158
 
1141
- this.#httpRequest = httpRequest
1159
+ this.#originalHttpRequest = httpRequest
1160
+ const requestHandler = config._requestHandler
1161
+ this.#httpRequest = requestHandler
1162
+ ? (() => {
1163
+ let bareClient: SanityClient | undefined
1164
+ const wrapped: HttpRequest = (options, requester) => {
1165
+ const opts = options as RequestOptions & {url: string}
1166
+ if (!bareClient) {
1167
+ bareClient = new SanityClient(httpRequest, {...config, _requestHandler: undefined})
1168
+ }
1169
+ return requestHandler(opts, (o) => httpRequest(o, requester), bareClient)
1170
+ }
1171
+ return wrapped
1172
+ })()
1173
+ : httpRequest
1142
1174
 
1143
1175
  this.assets = new AssetsClient(this, this.#httpRequest)
1144
1176
  this.datasets = new DatasetsClient(this, this.#httpRequest)
@@ -1160,7 +1192,7 @@ export class SanityClient {
1160
1192
  * Clone the client - returns a new instance
1161
1193
  */
1162
1194
  clone(): SanityClient {
1163
- return new SanityClient(this.#httpRequest, this.config())
1195
+ return new SanityClient(this.#originalHttpRequest, this.config())
1164
1196
  }
1165
1197
 
1166
1198
  /**
@@ -1197,7 +1229,7 @@ export class SanityClient {
1197
1229
  */
1198
1230
  withConfig(newConfig?: Partial<ClientConfig>): SanityClient {
1199
1231
  const thisConfig = this.config()
1200
- return new SanityClient(this.#httpRequest, {
1232
+ return new SanityClient(this.#originalHttpRequest, {
1201
1233
  ...thisConfig,
1202
1234
  ...newConfig,
1203
1235
  stega: {
package/src/data/live.ts CHANGED
@@ -35,6 +35,7 @@ export class LiveClient {
35
35
  events({
36
36
  includeDrafts = false,
37
37
  tag: _tag,
38
+ waitFor,
38
39
  }: {
39
40
  includeDrafts?: boolean
40
41
  /**
@@ -43,6 +44,11 @@ export class LiveClient {
43
44
  * @defaultValue `undefined`
44
45
  */
45
46
  tag?: string
47
+ /**
48
+ * Delays events until after a Sanity Function has processed them and called the callback endpoint.
49
+ * When omitted, events are delivered immediately.
50
+ */
51
+ waitFor?: 'function'
46
52
  } = {}): Observable<LiveEvent> {
47
53
  const {
48
54
  projectId,
@@ -74,6 +80,9 @@ export class LiveClient {
74
80
  if (includeDrafts) {
75
81
  url.searchParams.set('includeDrafts', 'true')
76
82
  }
83
+ if (waitFor) {
84
+ url.searchParams.set('waitFor', waitFor)
85
+ }
77
86
  const esOptions: EventSourceInit & {headers?: Record<string, string>} = {}
78
87
  if (includeDrafts && withCredentials) {
79
88
  esOptions.withCredentials = true
package/src/types.ts CHANGED
@@ -2,7 +2,9 @@
2
2
  /* eslint-disable @typescript-eslint/no-empty-object-type */
3
3
 
4
4
  import type {Requester} from 'get-it'
5
+ import type {Observable} from 'rxjs'
5
6
 
7
+ import type {SanityClient} from './SanityClient'
6
8
  import type {InitializedStegaConfig, StegaConfig} from './stega/types'
7
9
 
8
10
  /**
@@ -203,6 +205,33 @@ export interface ClientConfig {
203
205
  * Lineage token for recursion control
204
206
  */
205
207
  lineage?: string
208
+
209
+ /**
210
+ * A custom request handler that intercepts all HTTP requests made by the client.
211
+ *
212
+ * Useful for logging, adding custom headers, refreshing auth tokens, rate limiting, etc.
213
+ *
214
+ * When using `withConfig()`, the new handler **replaces** the previous one (it does not
215
+ * wrap it). To compose handlers, you can chain them manually:
216
+ *
217
+ * ```ts
218
+ * const parent = createClient({...config, _requestHandler: handlerA})
219
+ * const child = parent.withConfig({
220
+ * _requestHandler: (req, defaultRequester) =>
221
+ * handlerB(req, (opts) => handlerA(opts, defaultRequester)),
222
+ * })
223
+ * ```
224
+ *
225
+ * Setting `_requestHandler` to `undefined` via `withConfig()` removes the handler.
226
+ *
227
+ * Note: This only applies to HTTP requests. Real-time listener connections
228
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
229
+ *
230
+ * @internal
231
+ * @deprecated Don't use outside of Sanity internals
232
+ * @see {@link RequestHandler}
233
+ */
234
+ _requestHandler?: RequestHandler
206
235
  }
207
236
 
208
237
  /** @public */
@@ -412,6 +441,38 @@ export type HttpRequest = {
412
441
  (options: RequestOptions, requester: Requester): ReturnType<Requester>
413
442
  }
414
443
 
444
+ /**
445
+ * A function that intercepts HTTP requests made by the client.
446
+ *
447
+ * Receives the resolved request options, a `defaultRequester` function that
448
+ * executes the request through the normal pipeline, and a `client` instance
449
+ * without a `_requestHandler` (to avoid recursive interception).
450
+ *
451
+ * The consumer can:
452
+ * - Modify request options before calling `defaultRequester`
453
+ * - Transform the response stream (e.g. via `pipe`)
454
+ * - Skip `defaultRequester` entirely and return a custom Observable
455
+ * - Use `client` to make additional requests (e.g. refresh an auth token on 401)
456
+ *
457
+ * When set via `withConfig()`, the new handler **replaces** (not wraps) the previous one.
458
+ *
459
+ * Note: This only applies to HTTP requests. Real-time listener connections
460
+ * (`client.listen()`) use EventSource and are not intercepted by this handler.
461
+ *
462
+ * @param request - The resolved request options including `url`
463
+ * @param defaultRequester - Executes the request through the normal pipeline
464
+ * @param client - A client instance with the same configuration but without a `_requestHandler`,
465
+ * useful for making side requests (e.g. token refresh) without triggering the handler recursively
466
+ *
467
+ * @internal
468
+ * @deprecated Don't use outside of Sanity internals
469
+ */
470
+ export type RequestHandler = (
471
+ request: RequestOptions & {url: string},
472
+ defaultRequester: (options: RequestOptions & {url: string}) => Observable<HttpRequestEvent>,
473
+ client: SanityClient,
474
+ ) => Observable<HttpRequestEvent>
475
+
415
476
  /** @internal */
416
477
  export interface RequestObservableOptions extends Omit<RequestOptions, 'url'> {
417
478
  url?: string