@sanity/client 7.26.2 → 8.0.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.
Files changed (130) hide show
  1. package/README.md +5 -377
  2. package/dist/browserUpload-CQgx9YYo.js +86 -0
  3. package/dist/browserUpload-CQgx9YYo.js.map +1 -0
  4. package/dist/browserUpload-icWlVP15.js +86 -0
  5. package/dist/browserUpload-icWlVP15.js.map +1 -0
  6. package/dist/config-a8VajuEY.js +126 -0
  7. package/dist/config-a8VajuEY.js.map +1 -0
  8. package/dist/csm.d.ts +122 -335
  9. package/dist/csm.js +79 -91
  10. package/dist/csm.js.map +1 -1
  11. package/dist/dist-C9ExSk2R.js +73 -0
  12. package/dist/dist-C9ExSk2R.js.map +1 -0
  13. package/dist/dist-Z8cIRxoB.js +69 -0
  14. package/dist/dist-Z8cIRxoB.js.map +1 -0
  15. package/dist/index.d.ts +107 -6723
  16. package/dist/index.js +2822 -2847
  17. package/dist/index.js.map +1 -1
  18. package/dist/{index.d.cts → index.node.d.ts} +4291 -5328
  19. package/dist/index.node.js +3131 -0
  20. package/dist/index.node.js.map +1 -0
  21. package/dist/isRecord-Kfmt-nk-.js +7 -0
  22. package/dist/isRecord-Kfmt-nk-.js.map +1 -0
  23. package/dist/media-library.d.ts +9 -100
  24. package/dist/media-library.js +36 -14
  25. package/dist/media-library.js.map +1 -1
  26. package/dist/request-CJxcN16k.js +372 -0
  27. package/dist/request-CJxcN16k.js.map +1 -0
  28. package/dist/request-k7VS_NnC.js +354 -0
  29. package/dist/request-k7VS_NnC.js.map +1 -0
  30. package/dist/resolveEditInfo-sq7yF78q.js +325 -0
  31. package/dist/resolveEditInfo-sq7yF78q.js.map +1 -0
  32. package/dist/rolldown-runtime-vyAXikos.js +9 -0
  33. package/dist/stega.d.ts +78 -7137
  34. package/dist/stega.js +27 -20
  35. package/dist/stega.js.map +1 -1
  36. package/dist/stegaClean-C18wLWau.js +21 -0
  37. package/dist/stegaClean-C18wLWau.js.map +1 -0
  38. package/dist/stegaEncodeSourceMap-B2fGArSf.js +163 -0
  39. package/dist/stegaEncodeSourceMap-B2fGArSf.js.map +1 -0
  40. package/dist/stegaEncodeSourceMap-DkoIlutY.js +367 -0
  41. package/dist/stegaEncodeSourceMap-DkoIlutY.js.map +1 -0
  42. package/dist/{index.browser.d.cts → types-CUxZSgB2.d.ts} +3956 -5256
  43. package/dist/types-CfGzbXrl.d.ts +108 -0
  44. package/package.json +64 -141
  45. package/src/SanityClient.ts +82 -117
  46. package/src/agent/actions/AgentActionsClient.ts +12 -12
  47. package/src/agent/actions/commonTypes.ts +2 -1
  48. package/src/agent/actions/generate.ts +26 -6
  49. package/src/agent/actions/patch.ts +27 -7
  50. package/src/agent/actions/prompt.ts +19 -5
  51. package/src/agent/actions/transform.ts +23 -5
  52. package/src/agent/actions/translate.ts +23 -5
  53. package/src/assets/AssetsClient.ts +71 -23
  54. package/src/csm/applySourceDocuments.ts +3 -1
  55. package/src/csm/createEditUrl.ts +1 -1
  56. package/src/csm/draftUtils.ts +0 -1
  57. package/src/csm/index.ts +2 -2
  58. package/src/csm/studioPath.ts +2 -1
  59. package/src/csm/types.ts +8 -2
  60. package/src/data/dataMethods.ts +801 -349
  61. package/src/data/eventsource.ts +13 -10
  62. package/src/data/listen.ts +18 -23
  63. package/src/data/live.ts +44 -27
  64. package/src/data/resolveEventSourceFetch.ts +96 -0
  65. package/src/datasets/DatasetsClient.ts +58 -41
  66. package/src/defineCreateClient.ts +35 -23
  67. package/src/http/browserMiddleware.ts +7 -1
  68. package/src/http/browserUpload.ts +162 -0
  69. package/src/http/errors.ts +60 -6
  70. package/src/http/nodeMiddleware.ts +94 -30
  71. package/src/http/request.ts +310 -87
  72. package/src/http/requestOptions.ts +131 -15
  73. package/src/{index.browser.ts → index.node.ts} +9 -4
  74. package/src/index.ts +4 -3
  75. package/src/mediaLibrary/MediaLibraryVideoClient.ts +26 -11
  76. package/src/projects/ProjectsClient.ts +18 -16
  77. package/src/releases/ReleasesClient.ts +38 -33
  78. package/src/stega/index.ts +1 -2
  79. package/src/stega/stegaEncodeSourceMap.ts +5 -0
  80. package/src/stega/types.ts +2 -2
  81. package/src/types.ts +148 -105
  82. package/src/users/UsersClient.ts +10 -14
  83. package/src/util/shareReplayLatest.ts +1 -1
  84. package/src/warnings.ts +6 -1
  85. package/dist/_chunks-cjs/config.cjs +0 -206
  86. package/dist/_chunks-cjs/config.cjs.map +0 -1
  87. package/dist/_chunks-cjs/isRecord.cjs +0 -6
  88. package/dist/_chunks-cjs/isRecord.cjs.map +0 -1
  89. package/dist/_chunks-cjs/resolveEditInfo.cjs +0 -334
  90. package/dist/_chunks-cjs/resolveEditInfo.cjs.map +0 -1
  91. package/dist/_chunks-cjs/stegaClean.cjs +0 -46
  92. package/dist/_chunks-cjs/stegaClean.cjs.map +0 -1
  93. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +0 -388
  94. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +0 -1
  95. package/dist/_chunks-es/config.js +0 -207
  96. package/dist/_chunks-es/config.js.map +0 -1
  97. package/dist/_chunks-es/isRecord.js +0 -7
  98. package/dist/_chunks-es/isRecord.js.map +0 -1
  99. package/dist/_chunks-es/resolveEditInfo.js +0 -335
  100. package/dist/_chunks-es/resolveEditInfo.js.map +0 -1
  101. package/dist/_chunks-es/stegaClean.js +0 -47
  102. package/dist/_chunks-es/stegaClean.js.map +0 -1
  103. package/dist/_chunks-es/stegaEncodeSourceMap.js +0 -389
  104. package/dist/_chunks-es/stegaEncodeSourceMap.js.map +0 -1
  105. package/dist/csm.cjs +0 -99
  106. package/dist/csm.cjs.map +0 -1
  107. package/dist/csm.d.cts +0 -391
  108. package/dist/index.browser.cjs +0 -3106
  109. package/dist/index.browser.cjs.map +0 -1
  110. package/dist/index.browser.d.ts +0 -6802
  111. package/dist/index.browser.js +0 -3082
  112. package/dist/index.browser.js.map +0 -1
  113. package/dist/index.cjs +0 -2946
  114. package/dist/index.cjs.map +0 -1
  115. package/dist/media-library.cjs +0 -20
  116. package/dist/media-library.cjs.map +0 -1
  117. package/dist/media-library.d.cts +0 -117
  118. package/dist/stega.browser.cjs +0 -29
  119. package/dist/stega.browser.cjs.map +0 -1
  120. package/dist/stega.browser.d.cts +0 -7200
  121. package/dist/stega.browser.d.ts +0 -7200
  122. package/dist/stega.browser.js +0 -24
  123. package/dist/stega.browser.js.map +0 -1
  124. package/dist/stega.cjs +0 -29
  125. package/dist/stega.cjs.map +0 -1
  126. package/dist/stega.d.cts +0 -7200
  127. package/src/data/eventsourcePolyfill.ts +0 -7
  128. package/umd/.gitkeep +0 -1
  129. package/umd/sanityClient.js +0 -6543
  130. package/umd/sanityClient.min.js +0 -6
@@ -14,8 +14,8 @@ export class ConnectionFailedError extends Error {
14
14
  readonly name = 'ConnectionFailedError'
15
15
  /**
16
16
  * HTTP status code of the rejected connection attempt, if known.
17
- * Only set when the EventSource implementation exposes it — the polyfill used in
18
- * Node.js and when custom headers (eg authorization) are required does, while
17
+ * Only set when the EventSource implementation exposes it — the `eventsource`
18
+ * package used by the client does (as `code` on its error events), while
19
19
  * native EventSource implementations (browser and Node.js) do not.
20
20
  */
21
21
  readonly status?: number
@@ -151,8 +151,10 @@ function connectWithESInstance<EventTypeName extends string>(
151
151
  const [parseError, event] = parseEvent(evt as MessageEvent)
152
152
  observer.error(
153
153
  parseError
154
- ? new MessageParseError('Unable to parse EventSource error message', {cause: event})
155
- : new MessageError((event?.data as {message: string}).message, event),
154
+ ? new MessageParseError('Unable to parse EventSource error message', {
155
+ cause: parseError,
156
+ })
157
+ : new MessageError((event.data as {message: string}).message, event),
156
158
  )
157
159
  return
158
160
  }
@@ -161,12 +163,13 @@ function connectWithESInstance<EventTypeName extends string>(
161
163
  // automatically, but in some cases (like when a laptop lid is closed), it will trigger onError
162
164
  // if it can't reconnect.
163
165
  // see https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model
164
- // The polyfills expose the HTTP status of a rejected connection on the error event
165
- // (native EventSource implementations do not). A status means the server rejected the
166
- // connection attempt, so error out regardless of readyState the polyfills disagree
167
- // on whether the connection closes before or after the error event is dispatched —
168
- // and let `reconnectOnConnectionFailure` classify it (4xx fatal, otherwise retried).
169
- const rawStatus = (evt as {status?: unknown}).status
166
+ // The `eventsource` package exposes the HTTP status of a rejected connection as
167
+ // `code` on the error event (native EventSource implementations expose nothing).
168
+ // A status means the server rejected the connection attempt, so error out
169
+ // regardless of readyState implementations disagree on whether the connection
170
+ // closes before or after the error event is dispatched — and let
171
+ // `reconnectOnConnectionFailure` classify it (4xx fatal, otherwise retried).
172
+ const rawStatus = (evt as {code?: unknown}).code
170
173
  const status = typeof rawStatus === 'number' ? rawStatus : undefined
171
174
  if (status !== undefined) {
172
175
  observer.error(new ConnectionFailedError('EventSource connection failed', {status}))
@@ -1,4 +1,5 @@
1
- import {Observable, of, throwError} from 'rxjs'
1
+ import {EventSource} from 'eventsource'
2
+ import {Observable, throwError} from 'rxjs'
2
3
  import {filter, map} from 'rxjs/operators'
3
4
 
4
5
  import type {ObservableSanityClient, SanityClient} from '../SanityClient'
@@ -22,8 +23,8 @@ import {pick} from '../util/pick'
22
23
  import {_getDataUrl} from './dataMethods'
23
24
  import {encodeQueryString} from './encodeQueryString'
24
25
  import {connectEventSource} from './eventsource'
25
- import {eventSourcePolyfill} from './eventsourcePolyfill'
26
26
  import {reconnectOnConnectionFailure} from './reconnectOnConnectionFailure'
27
+ import {resolveEventSourceFetch} from './resolveEventSourceFetch'
27
28
 
28
29
  // Limit is 16K for a _request_, eg including headers. Have to account for an
29
30
  // unknown range of headers, but an average EventSource request from Chrome seems
@@ -57,7 +58,8 @@ const defaultOptions = {
57
58
  export type MapListenEventNamesToListenEvents<
58
59
  R extends Record<string, Any> = Record<string, Any>,
59
60
  Events extends (ResumableListenEventNames | ListenEventName)[] = (
60
- ResumableListenEventNames | ListenEventName
61
+ | ResumableListenEventNames
62
+ | ListenEventName
61
63
  )[],
62
64
  > = Events extends (infer E)[]
63
65
  ? E extends 'welcome'
@@ -134,7 +136,8 @@ export function _listen<
134
136
  params?: ListenParams,
135
137
  opts: Opts = {} as Opts,
136
138
  ): Observable<ListenEventFromOptions<R, Opts>> {
137
- const {url, token, withCredentials, requestTagPrefix, headers: configHeaders} = this.config()
139
+ const config = this.config()
140
+ const {url, token, withCredentials, requestTagPrefix, headers: configHeaders} = config
138
141
  const tag = opts.tag && requestTagPrefix ? [requestTagPrefix, opts.tag].join('.') : opts.tag
139
142
  const options = {...defaults(opts, defaultOptions), tag}
140
143
  const listenOpts = pick(options, possibleOptions)
@@ -147,29 +150,21 @@ export function _listen<
147
150
 
148
151
  const listenFor = (options.events ? options.events : ['mutation']) satisfies Opts['events']
149
152
 
150
- const esOptions: EventSourceInit & {headers?: Record<string, string>} = {}
151
- if (withCredentials) {
152
- esOptions.withCredentials = true
153
+ const headers: Record<string, string> = {}
154
+ if (token) {
155
+ headers.Authorization = `Bearer ${token}`
153
156
  }
154
-
155
- if (token || configHeaders) {
156
- esOptions.headers = {}
157
-
158
- if (token) {
159
- esOptions.headers.Authorization = `Bearer ${token}`
160
- }
161
-
162
- if (configHeaders) {
163
- Object.assign(esOptions.headers, configHeaders)
164
- }
157
+ if (configHeaders) {
158
+ Object.assign(headers, configHeaders)
165
159
  }
166
160
 
167
161
  const initEventSource = () =>
168
- // use polyfill if there is no global EventSource or if we need to set headers
169
- (typeof EventSource === 'undefined' || esOptions.headers
170
- ? eventSourcePolyfill
171
- : of(EventSource)
172
- ).pipe(map((EventSource) => new EventSource(uri, esOptions)))
162
+ new EventSource(uri, {
163
+ fetch: resolveEventSourceFetch(config, {
164
+ headers: Object.keys(headers).length ? headers : undefined,
165
+ withCredentials,
166
+ }),
167
+ })
173
168
 
174
169
  return connectEventSource(initEventSource, listenFor).pipe(
175
170
  reconnectOnConnectionFailure(),
package/src/data/live.ts CHANGED
@@ -1,9 +1,11 @@
1
+ import {EventSource} from 'eventsource'
1
2
  import {catchError, mergeMap, Observable, of, throwError} from 'rxjs'
2
3
  import {finalize, map} from 'rxjs/operators'
3
4
 
4
5
  import {CorsOriginError} from '../http/errors'
5
6
  import type {ObservableSanityClient, SanityClient} from '../SanityClient'
6
7
  import type {
8
+ InitializedClientConfig,
7
9
  LiveEvent,
8
10
  LiveEventGoAway,
9
11
  LiveEventMessage,
@@ -15,8 +17,8 @@ import type {
15
17
  import {shareReplayLatest} from '../util/shareReplayLatest'
16
18
  import {_getDataUrl} from './dataMethods'
17
19
  import {connectEventSource} from './eventsource'
18
- import {eventSourcePolyfill} from './eventsourcePolyfill'
19
20
  import {reconnectOnConnectionFailure} from './reconnectOnConnectionFailure'
21
+ import {resolveEventSourceFetch} from './resolveEventSourceFetch'
20
22
 
21
23
  const requiredApiVersion = '2021-03-25'
22
24
 
@@ -50,6 +52,7 @@ export class LiveClient {
50
52
  */
51
53
  waitFor?: 'function'
52
54
  } = {}): Observable<LiveEvent> {
55
+ const config = this.#client.config()
53
56
  const {
54
57
  projectId,
55
58
  apiVersion: _apiVersion,
@@ -57,7 +60,7 @@ export class LiveClient {
57
60
  withCredentials,
58
61
  requestTagPrefix,
59
62
  headers: configHeaders,
60
- } = this.#client.config()
63
+ } = config
61
64
  const apiVersion = _apiVersion.replace(/^v/, '')
62
65
  if (apiVersion !== 'X' && apiVersion < requiredApiVersion) {
63
66
  throw new Error(
@@ -83,36 +86,39 @@ export class LiveClient {
83
86
  if (waitFor) {
84
87
  url.searchParams.set('waitFor', waitFor)
85
88
  }
86
- const esOptions: EventSourceInit & {headers?: Record<string, string>} = {}
87
- if (includeDrafts && withCredentials) {
88
- esOptions.withCredentials = true
89
+ const eventSourceHeaders: Record<string, string> = {}
90
+ if (includeDrafts && token) {
91
+ eventSourceHeaders.Authorization = `Bearer ${token}`
89
92
  }
90
-
91
- if ((includeDrafts && token) || configHeaders) {
92
- esOptions.headers = {}
93
-
94
- if (includeDrafts && token) {
95
- esOptions.headers.Authorization = `Bearer ${token}`
96
- }
97
-
98
- if (configHeaders) {
99
- Object.assign(esOptions.headers, configHeaders)
100
- }
93
+ if (configHeaders) {
94
+ Object.assign(eventSourceHeaders, configHeaders)
101
95
  }
96
+ const eventSourceWithCredentials = Boolean(includeDrafts && withCredentials)
102
97
 
103
- const key = `${url.href}::${JSON.stringify(esOptions)}`
104
- const existing = eventsCache.get(key)
98
+ let transportCache = eventsCache.get(config.resolveFetch)
99
+ if (!transportCache) {
100
+ transportCache = new Map()
101
+ eventsCache.set(config.resolveFetch, transportCache)
102
+ }
103
+ const cacheKey = JSON.stringify([
104
+ url.href,
105
+ typeof config.proxy === 'string' ? config.proxy : null,
106
+ eventSourceHeaders,
107
+ eventSourceWithCredentials,
108
+ ])
109
+ const existing = transportCache.get(cacheKey)
105
110
 
106
111
  if (existing) {
107
112
  return existing
108
113
  }
109
114
 
110
115
  const initEventSource = () =>
111
- // use polyfill if there is no global EventSource or if we need to set headers
112
- (typeof EventSource === 'undefined' || esOptions.headers
113
- ? eventSourcePolyfill
114
- : of(EventSource)
115
- ).pipe(map((EventSource) => new EventSource(url.href, esOptions)))
116
+ new EventSource(url.href, {
117
+ fetch: resolveEventSourceFetch(config, {
118
+ headers: Object.keys(eventSourceHeaders).length ? eventSourceHeaders : undefined,
119
+ withCredentials: eventSourceWithCredentials,
120
+ }),
121
+ })
116
122
 
117
123
  const events = connectEventSource(initEventSource, [
118
124
  'message',
@@ -125,7 +131,7 @@ export class LiveClient {
125
131
  const checkCors = checkCorsObservable(
126
132
  new URL(this.#client.getUrl('/check/cors', false)),
127
133
  projectId,
128
- esOptions.withCredentials === true,
134
+ eventSourceWithCredentials,
129
135
  )
130
136
 
131
137
  const observable = events
@@ -162,12 +168,15 @@ export class LiveClient {
162
168
  }),
163
169
  )
164
170
  .pipe(
165
- finalize(() => eventsCache.delete(key)),
171
+ finalize(() => {
172
+ transportCache.delete(cacheKey)
173
+ if (transportCache.size === 0) eventsCache.delete(config.resolveFetch)
174
+ }),
166
175
  shareReplayLatest({
167
176
  predicate: (event) => event.type === 'welcome',
168
177
  }),
169
178
  )
170
- eventsCache.set(key, observable)
179
+ transportCache.set(cacheKey, observable)
171
180
  return observable
172
181
  }
173
182
  }
@@ -262,4 +271,12 @@ function checkCorsObservable(
262
271
  })
263
272
  }
264
273
 
265
- const eventsCache = new Map<string, Observable<LiveEvent>>()
274
+ /**
275
+ * Cached observables capture their transport (`initEventSource` closes over
276
+ * `config.resolveFetch` and `config.proxy`), so the cache is scoped per
277
+ * resolver — `undefined` covers the `globalThis.fetch` fallback.
278
+ */
279
+ const eventsCache = new Map<
280
+ InitializedClientConfig['resolveFetch'],
281
+ Map<string, Observable<LiveEvent>>
282
+ >()
@@ -0,0 +1,96 @@
1
+ import type {EventSourceFetchInit, FetchLikeResponse} from 'eventsource'
2
+ import type {FetchFunction, FetchInit} from 'get-it'
3
+
4
+ import type {InitializedClientConfig} from '../types'
5
+
6
+ /** @internal */
7
+ export interface EventSourceFetchOptions {
8
+ /**
9
+ * Headers that must be merged into every EventSource request. Used for
10
+ * the `Authorization` token, custom `headers` from the client config,
11
+ * etc. — things the native EventSource API has no equivalent for.
12
+ */
13
+ headers?: Record<string, string>
14
+ /**
15
+ * If the client was configured with `withCredentials: true`, the
16
+ * resolved fetch forwards `credentials: 'include'` so the browser
17
+ * attaches cookies to the SSE request.
18
+ */
19
+ withCredentials?: boolean
20
+ }
21
+
22
+ /**
23
+ * Build a `fetch` implementation suitable for the `eventsource` package's
24
+ * `fetch` option. Routes the EventSource connection through the same
25
+ * transport layer the rest of the client uses, so things like the
26
+ * test-fetch override, the per-request `proxy` config, and `HTTPS_PROXY`
27
+ * env-var support apply to SSE too.
28
+ *
29
+ * Resolution order on each request:
30
+ *
31
+ * 1. `config.resolveFetch(config.proxy)` if set — the client's fetch
32
+ * resolver, so SSE uses the same transport as regular requests:
33
+ * custom fetch variants (incl. the test suite's injected mock),
34
+ * undici configuration, an explicit `proxy` config, and env-proxy
35
+ * support all apply to SSE too. The Node entry supplies get-it's
36
+ * undici-backed fetch (threading the resolver through the env
37
+ * instead of importing `get-it/node` directly keeps `undici` out of
38
+ * the browser bundle); the browser entry leaves it unset.
39
+ * 2. `globalThis.fetch`. Note that Node's global fetch does NOT read
40
+ * proxy env vars (that is opt-in via `NODE_USE_ENV_PROXY`), which
41
+ * is one of the reasons step 1 exists.
42
+ *
43
+ * The returned fetch always merges `options.headers` into the outgoing
44
+ * request, regardless of which underlying fetch was picked.
45
+ *
46
+ * @internal
47
+ */
48
+ export function resolveEventSourceFetch(
49
+ config: InitializedClientConfig,
50
+ options: EventSourceFetchOptions = {},
51
+ ): EventSourceFetch {
52
+ const extraHeaders = options.headers
53
+ const credentials: FetchInit['credentials'] = options.withCredentials ? 'include' : undefined
54
+
55
+ return function eventSourceFetch(url, init) {
56
+ const baseFetch = pickBaseFetch(config)
57
+
58
+ // Extra `EventSourceFetchInit` fields get-it's `FetchInit` doesn't
59
+ // declare (`mode`, `cache`) survive the spread and reach whichever
60
+ // fetch implementation is effective.
61
+ const mergedInit: FetchInit = {...init}
62
+ if (extraHeaders) {
63
+ const headers = new Headers(init?.headers)
64
+ for (const [key, value] of Object.entries(extraHeaders)) {
65
+ headers.set(key, value)
66
+ }
67
+ mergedInit.headers = headers
68
+ }
69
+ if (credentials !== undefined) {
70
+ mergedInit.credentials = credentials
71
+ }
72
+ // get-it's `FetchResponse` is a structural superset of the package's
73
+ // `FetchLikeResponse`, so it can be handed over as-is.
74
+ return baseFetch(typeof url === 'string' ? url : url.href, mergedInit)
75
+ }
76
+ }
77
+
78
+ /**
79
+ * The fetch shape handed to the `eventsource` package: accepts what its
80
+ * `FetchLike` passes in, requires only what get-it's `FetchFunction`
81
+ * guarantees back — the full `typeof fetch` contract is not needed anywhere
82
+ * in this chain.
83
+ *
84
+ * @internal
85
+ */
86
+ export type EventSourceFetch = (
87
+ url: string | URL,
88
+ init?: EventSourceFetchInit,
89
+ ) => Promise<FetchLikeResponse>
90
+
91
+ function pickBaseFetch(config: InitializedClientConfig): FetchFunction {
92
+ if (config.resolveFetch) {
93
+ return config.resolveFetch(typeof config.proxy === 'string' ? config.proxy : undefined)
94
+ }
95
+ return globalThis.fetch.bind(globalThis)
96
+ }
@@ -1,6 +1,6 @@
1
- import {lastValueFrom, type Observable} from 'rxjs'
1
+ import {type Observable} from 'rxjs'
2
2
 
3
- import {_request} from '../data/dataMethods'
3
+ import {_request, _requestObservable} from '../data/dataMethods'
4
4
  import type {ObservableSanityClient, SanityClient} from '../SanityClient'
5
5
  import type {
6
6
  DatasetCreateOptions,
@@ -29,7 +29,7 @@ export class ObservableDatasetsClient {
29
29
  * @param options - Options for the dataset, including optional embeddings configuration
30
30
  */
31
31
  create(name: string, options?: DatasetCreateOptions): Observable<DatasetResponse> {
32
- return _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options)
32
+ return _modifyObservable<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options)
33
33
  }
34
34
 
35
35
  /**
@@ -39,7 +39,13 @@ export class ObservableDatasetsClient {
39
39
  * @param options - New options for the dataset
40
40
  */
41
41
  edit(name: string, options?: DatasetEditOptions): Observable<DatasetResponse> {
42
- return _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PATCH', name, options)
42
+ return _modifyObservable<DatasetResponse>(
43
+ this.#client,
44
+ this.#httpRequest,
45
+ 'PATCH',
46
+ name,
47
+ options,
48
+ )
43
49
  }
44
50
 
45
51
  /**
@@ -48,7 +54,7 @@ export class ObservableDatasetsClient {
48
54
  * @param name - Name of the dataset to delete
49
55
  */
50
56
  delete(name: string): Observable<{deleted: true}> {
51
- return _modify<{deleted: true}>(this.#client, this.#httpRequest, 'DELETE', name)
57
+ return _modifyObservable<{deleted: true}>(this.#client, this.#httpRequest, 'DELETE', name)
52
58
  }
53
59
 
54
60
  /**
@@ -58,13 +64,13 @@ export class ObservableDatasetsClient {
58
64
  validate.resourceGuard('dataset', this.#client.config())
59
65
  const config = this.#client.config()
60
66
  const projectId = config.projectId
61
- let uri = '/datasets'
67
+ let url = '/datasets'
62
68
  if (config.useProjectHostname === false) {
63
- uri = `/projects/${projectId}/datasets`
69
+ url = `/projects/${projectId}/datasets`
64
70
  }
65
71
 
66
- return _request<DatasetsResponse>(this.#client, this.#httpRequest, {
67
- uri,
72
+ return _requestObservable<DatasetsResponse>(this.#client, this.#httpRequest, {
73
+ url,
68
74
  tag: null,
69
75
  })
70
76
  }
@@ -77,8 +83,8 @@ export class ObservableDatasetsClient {
77
83
  getEmbeddingsSettings(name: string): Observable<EmbeddingsSettings> {
78
84
  validate.resourceGuard('dataset', this.#client.config())
79
85
  validate.dataset(name)
80
- return _request<EmbeddingsSettings>(this.#client, this.#httpRequest, {
81
- uri: _embeddingsSettingsUri(this.#client, name),
86
+ return _requestObservable<EmbeddingsSettings>(this.#client, this.#httpRequest, {
87
+ url: _embeddingsSettingsUri(this.#client, name),
82
88
  tag: null,
83
89
  })
84
90
  }
@@ -92,9 +98,9 @@ export class ObservableDatasetsClient {
92
98
  editEmbeddingsSettings(name: string, settings: EmbeddingsSettingsBody): Observable<void> {
93
99
  validate.resourceGuard('dataset', this.#client.config())
94
100
  validate.dataset(name)
95
- return _request<void>(this.#client, this.#httpRequest, {
101
+ return _requestObservable<void>(this.#client, this.#httpRequest, {
96
102
  method: 'PUT',
97
- uri: _embeddingsSettingsUri(this.#client, name),
103
+ url: _embeddingsSettingsUri(this.#client, name),
98
104
  body: settings,
99
105
  tag: null,
100
106
  })
@@ -118,9 +124,7 @@ export class DatasetsClient {
118
124
  */
119
125
  create(name: string, options?: DatasetCreateOptions): Promise<DatasetResponse> {
120
126
  validate.resourceGuard('dataset', this.#client.config())
121
- return lastValueFrom(
122
- _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options),
123
- )
127
+ return _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options)
124
128
  }
125
129
 
126
130
  /**
@@ -131,9 +135,7 @@ export class DatasetsClient {
131
135
  */
132
136
  edit(name: string, options?: DatasetEditOptions): Promise<DatasetResponse> {
133
137
  validate.resourceGuard('dataset', this.#client.config())
134
- return lastValueFrom(
135
- _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PATCH', name, options),
136
- )
138
+ return _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PATCH', name, options)
137
139
  }
138
140
 
139
141
  /**
@@ -143,7 +145,7 @@ export class DatasetsClient {
143
145
  */
144
146
  delete(name: string): Promise<{deleted: true}> {
145
147
  validate.resourceGuard('dataset', this.#client.config())
146
- return lastValueFrom(_modify<{deleted: true}>(this.#client, this.#httpRequest, 'DELETE', name))
148
+ return _modify<{deleted: true}>(this.#client, this.#httpRequest, 'DELETE', name)
147
149
  }
148
150
 
149
151
  /**
@@ -153,14 +155,15 @@ export class DatasetsClient {
153
155
  validate.resourceGuard('dataset', this.#client.config())
154
156
  const config = this.#client.config()
155
157
  const projectId = config.projectId
156
- let uri = '/datasets'
158
+ let url = '/datasets'
157
159
  if (config.useProjectHostname === false) {
158
- uri = `/projects/${projectId}/datasets`
160
+ url = `/projects/${projectId}/datasets`
159
161
  }
160
162
 
161
- return lastValueFrom(
162
- _request<DatasetsResponse>(this.#client, this.#httpRequest, {uri, tag: null}),
163
- )
163
+ return _request<DatasetsResponse>(this.#client, this.#httpRequest, {
164
+ url,
165
+ tag: null,
166
+ })
164
167
  }
165
168
 
166
169
  /**
@@ -171,12 +174,10 @@ export class DatasetsClient {
171
174
  getEmbeddingsSettings(name: string): Promise<EmbeddingsSettings> {
172
175
  validate.resourceGuard('dataset', this.#client.config())
173
176
  validate.dataset(name)
174
- return lastValueFrom(
175
- _request<EmbeddingsSettings>(this.#client, this.#httpRequest, {
176
- uri: _embeddingsSettingsUri(this.#client, name),
177
- tag: null,
178
- }),
179
- )
177
+ return _request<EmbeddingsSettings>(this.#client, this.#httpRequest, {
178
+ url: _embeddingsSettingsUri(this.#client, name),
179
+ tag: null,
180
+ })
180
181
  }
181
182
 
182
183
  /**
@@ -188,14 +189,12 @@ export class DatasetsClient {
188
189
  editEmbeddingsSettings(name: string, settings: EmbeddingsSettingsBody): Promise<void> {
189
190
  validate.resourceGuard('dataset', this.#client.config())
190
191
  validate.dataset(name)
191
- return lastValueFrom(
192
- _request<void>(this.#client, this.#httpRequest, {
193
- method: 'PUT',
194
- uri: _embeddingsSettingsUri(this.#client, name),
195
- body: settings,
196
- tag: null,
197
- }),
198
- )
192
+ return _request<void>(this.#client, this.#httpRequest, {
193
+ method: 'PUT',
194
+ url: _embeddingsSettingsUri(this.#client, name),
195
+ body: settings,
196
+ tag: null,
197
+ })
199
198
  }
200
199
  }
201
200
 
@@ -210,7 +209,7 @@ function _embeddingsSettingsUri(
210
209
  return `/datasets/${name}/settings/embeddings`
211
210
  }
212
211
 
213
- function _modify<R = unknown>(
212
+ function _modifyObservable<R = unknown>(
214
213
  client: SanityClient | ObservableSanityClient,
215
214
  httpRequest: HttpRequest,
216
215
  method: 'DELETE' | 'PATCH' | 'PUT',
@@ -220,9 +219,27 @@ function _modify<R = unknown>(
220
219
  validate.resourceGuard('dataset', client.config())
221
220
  validate.dataset(name)
222
221
 
222
+ return _requestObservable<R>(client, httpRequest, {
223
+ method,
224
+ url: `/datasets/${name}`,
225
+ body: options,
226
+ tag: null,
227
+ })
228
+ }
229
+
230
+ function _modify<R = unknown>(
231
+ client: SanityClient | ObservableSanityClient,
232
+ httpRequest: HttpRequest,
233
+ method: 'DELETE' | 'PATCH' | 'PUT',
234
+ name: string,
235
+ options?: DatasetCreateOptions | DatasetEditOptions,
236
+ ): Promise<R> {
237
+ validate.resourceGuard('dataset', client.config())
238
+ validate.dataset(name)
239
+
223
240
  return _request<R>(client, httpRequest, {
224
241
  method,
225
- uri: `/datasets/${name}`,
242
+ url: `/datasets/${name}`,
226
243
  body: options,
227
244
  tag: null,
228
245
  })
@@ -1,7 +1,5 @@
1
- import type {Middlewares} from 'get-it'
2
-
3
- import {defineHttpRequest} from './http/request'
4
- import type {Any, ClientConfig, HttpRequest} from './types'
1
+ import {defineRequester, type EnvironmentOptions} from './http/request'
2
+ import type {ClientConfig, HttpRequest} from './types'
5
3
 
6
4
  export {validateApiPerspective} from './config'
7
5
  export {
@@ -29,9 +27,6 @@ export {
29
27
  export * from './SanityClient'
30
28
  export * from './types'
31
29
 
32
- /** @alpha */
33
- export {adapter as unstable__adapter, environment as unstable__environment} from 'get-it'
34
-
35
30
  /**
36
31
  * Create the `requester` and `createClient` exports, that have environment specific middleware for node and browsers
37
32
  * @internal
@@ -40,27 +35,44 @@ export default function defineCreateClientExports<
40
35
  SanityClientType,
41
36
  ClientConfigType extends ClientConfig,
42
37
  >(
43
- envMiddleware: Middlewares,
38
+ envOptions: EnvironmentOptions,
44
39
  ClassConstructor: new (httpRequest: HttpRequest, config: ClientConfigType) => SanityClientType,
45
40
  ) {
46
- // Set the http client to use for requests, and its environment specific middleware
47
- const defaultRequester = defineHttpRequest(envMiddleware)
41
+ // Set the http client to use for requests, and its environment specific options
42
+ const defaultRequester = defineRequester(envOptions).observable
48
43
 
49
44
  const createClient = (config: ClientConfigType) => {
50
- const clientRequester = defineHttpRequest(envMiddleware, {
51
- ignoreWarnings: config.ignoreWarnings,
52
- })
53
- return new ClassConstructor(
54
- (options, requester) =>
55
- (requester || clientRequester)({
56
- maxRedirects: 0,
57
- maxRetries: config.maxRetries,
58
- retryDelay: config.retryDelay,
59
- lineage: config.lineage,
60
- ...options,
61
- } as Any),
62
- config,
45
+ const {observable: clientRequester, promise: clientRequesterPromise} = defineRequester(
46
+ envOptions,
47
+ {
48
+ ignoreWarnings: config.ignoreWarnings,
49
+ maxRetries: config.maxRetries,
50
+ retryDelay: config.retryDelay,
51
+ },
63
52
  )
53
+ // The single transport for the whole client. Resolves a request to its
54
+ // parsed response body as a Promise; the observable client surface wraps
55
+ // this in `new Observable(...)` (see `_observe` in dataMethods).
56
+ // Redirects are surfaced rather than followed unless a request opts in
57
+ // (via the public `maxRedirects` option, translated in `requestOptions`).
58
+ const httpRequest: HttpRequest = async (options) => {
59
+ const event = await clientRequesterPromise({redirect: 'manual', ...options})
60
+ return event.body
61
+ }
62
+ // Populate `requester` on the initialized config so internal paths
63
+ // (e.g. the asset upload event stream) can reach the underlying transport.
64
+ // `resolveFetch` is threaded onto the config so request building and
65
+ // EventSource fetches can reach the environment's fetch without importing
66
+ // `get-it/node` from a browser-shared module (would leak `undici` into
67
+ // the browser bundle). A caller-supplied `resolveFetch` wins over the
68
+ // environment's — that is the supported way to swap the transport (the
69
+ // test suite injects its mock fetch through it).
70
+ const resolvedConfig = {
71
+ ...config,
72
+ requester: clientRequester,
73
+ resolveFetch: config.resolveFetch ?? envOptions.resolveFetch,
74
+ }
75
+ return new ClassConstructor(httpRequest, resolvedConfig)
64
76
  }
65
77
 
66
78
  return {requester: defaultRequester, createClient}
@@ -1 +1,7 @@
1
- export default []
1
+ import type {EnvironmentOptions} from './request'
2
+
3
+ const environment: EnvironmentOptions = {
4
+ middleware: [],
5
+ }
6
+
7
+ export default environment