@sanity/client 8.3.0 → 8.5.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 (54) hide show
  1. package/README.md +80 -4
  2. package/dist/{browserUpload-2tz6Sdqp.js → browserUpload-C7PwCs-C.js} +6 -9
  3. package/dist/browserUpload-C7PwCs-C.js.map +1 -0
  4. package/dist/{browserUpload-CwpNx7Vl.js → browserUpload-D-2Rmfjo.js} +6 -9
  5. package/dist/browserUpload-D-2Rmfjo.js.map +1 -0
  6. package/dist/{config-3wiPP-sZ.js → config-CgJ16jET.js} +4 -2
  7. package/dist/config-CgJ16jET.js.map +1 -0
  8. package/dist/csm.js +1 -1
  9. package/dist/{dist-C9ExSk2R.js → dist-C5K_YcEU.js} +3 -2
  10. package/dist/{dist-C9ExSk2R.js.map → dist-C5K_YcEU.js.map} +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +1111 -80
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.node.d.ts +3561 -53
  15. package/dist/index.node.js +983 -30
  16. package/dist/index.node.js.map +1 -1
  17. package/dist/media-library.d.ts +1 -1
  18. package/dist/rolldown-runtime-4YWMqDIC.js +9 -0
  19. package/dist/stega.js +2 -2
  20. package/dist/{dist-Z8cIRxoB.js → stegaClean-YZRATV86.js} +19 -2
  21. package/dist/stegaClean-YZRATV86.js.map +1 -0
  22. package/dist/{stegaEncodeSourceMap-DbM2fTN4.js → stegaEncodeSourceMap-CO1HKnm2.js} +2 -2
  23. package/dist/{stegaEncodeSourceMap-DbM2fTN4.js.map → stegaEncodeSourceMap-CO1HKnm2.js.map} +1 -1
  24. package/dist/{stegaEncodeSourceMap-YR3NQ3iz.js → stegaEncodeSourceMap-Dj29aWKG.js} +2 -2
  25. package/dist/{stegaEncodeSourceMap-YR3NQ3iz.js.map → stegaEncodeSourceMap-Dj29aWKG.js.map} +1 -1
  26. package/dist/{types-0x2hPfhJ.d.ts → types-CtHEe8SF.d.ts} +3562 -54
  27. package/package.json +18 -15
  28. package/src/SanityClient.ts +183 -9
  29. package/src/agent/actions/AgentActionsClient.ts +8 -2
  30. package/src/assets/AssetsClient.ts +13 -2
  31. package/src/config.ts +1 -0
  32. package/src/context/ContextClient.ts +1006 -0
  33. package/src/context/openapi.json +5345 -0
  34. package/src/context/reads.ts +206 -0
  35. package/src/context/store.ts +100 -0
  36. package/src/context/types.gen.ts +2428 -0
  37. package/src/context/types.ts +228 -0
  38. package/src/data/dataMethods.ts +4 -1
  39. package/src/data/live.ts +1 -0
  40. package/src/datasets/DatasetsClient.ts +8 -2
  41. package/src/defineCreateClient.ts +1 -0
  42. package/src/http/browserUpload.ts +0 -12
  43. package/src/mediaLibrary/MediaLibraryVideoClient.ts +8 -2
  44. package/src/projects/ProjectsClient.ts +8 -2
  45. package/src/releases/ReleasesClient.ts +8 -2
  46. package/src/types.ts +68 -4
  47. package/src/users/UsersClient.ts +8 -2
  48. package/src/validators.ts +1 -0
  49. package/dist/browserUpload-2tz6Sdqp.js.map +0 -1
  50. package/dist/browserUpload-CwpNx7Vl.js.map +0 -1
  51. package/dist/config-3wiPP-sZ.js.map +0 -1
  52. package/dist/dist-Z8cIRxoB.js.map +0 -1
  53. package/dist/stegaClean-C18wLWau.js +0 -21
  54. package/dist/stegaClean-C18wLWau.js.map +0 -1
@@ -0,0 +1,228 @@
1
+ import type {
2
+ ListenOptions,
3
+ RequestOptions as MainRequestOptions,
4
+ ResumableListenOptions,
5
+ UploadBody,
6
+ } from '../types'
7
+ import type {components, paths} from './types.gen'
8
+
9
+ /** Options accepted by every Context method. @beta */
10
+ export type RequestOptions = {signal?: AbortSignal; tag?: string}
11
+
12
+ /** @internal */
13
+ export const possibleStoreRequestOptions = ['headers', 'signal', 'tag', 'timeout', 'token'] as const
14
+
15
+ /**
16
+ * Request options honored by `context.fetch`.
17
+ *
18
+ * @beta
19
+ */
20
+ export type ContextRequestOptions = Pick<
21
+ MainRequestOptions,
22
+ (typeof possibleStoreRequestOptions)[number]
23
+ >
24
+
25
+ /**
26
+ * Listener options for `context.listen`.
27
+ *
28
+ * `includeAllVersions` is left out: Context documents are written by the
29
+ * Context API with no drafts or versions, so it would never make a
30
+ * difference.
31
+ *
32
+ * @beta
33
+ */
34
+ export type ContextListenOptions =
35
+ | Omit<ListenOptions, 'includeAllVersions'>
36
+ | Omit<ResumableListenOptions, 'includeAllVersions'>
37
+
38
+ /**
39
+ * A file import. The client stages the upload, PUTs the bytes straight to
40
+ * storage with a signed URL, and confirms. The Context API never holds the
41
+ * file content.
42
+ * @beta
43
+ */
44
+ export type CreateFileImportParams = {
45
+ type: 'file'
46
+ /** Same shapes `assets.upload` accepts, minus node streams: the bytes go
47
+ * out through `fetch`, which has no portable stream support. */
48
+ file: Exclude<UploadBody, NodeJS.ReadableStream>
49
+ filename: string
50
+ contentType?: string
51
+ }
52
+
53
+ type KnowledgeBasesPath = '/{apiVersion}/context/knowledge-bases'
54
+ type ConversationPath =
55
+ '/{apiVersion}/context/organizations/{organizationId}/conversations/{threadId}'
56
+ type KnowledgeBasePath = '/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}'
57
+ type ImportsPath = `${KnowledgeBasePath}/imports`
58
+ type ImportPath = `${KnowledgeBasePath}/imports/{importId}`
59
+ type UploadsPath = `${KnowledgeBasePath}/imports/uploads`
60
+ type EntryRebuildPath = `${KnowledgeBasePath}/entries/{entryPath}/rebuild`
61
+ type SourcesPath = `${KnowledgeBasePath}/sources`
62
+ type SourcePath = `${KnowledgeBasePath}/sources/{sourceId}`
63
+ type SourceContentPath = `${KnowledgeBasePath}/sources/{sourceId}/content`
64
+ type IssuesApplyPath = `${KnowledgeBasePath}/issues/apply`
65
+ type InstructionPath = `${KnowledgeBasePath}/instructions/{instructionId}`
66
+ type JobPath = `${KnowledgeBasePath}/jobs/{jobId}`
67
+ type IssueResolvePath = `${KnowledgeBasePath}/issues/{issueId}/resolve`
68
+ type IssueDismissPath = `${KnowledgeBasePath}/issues/{issueId}/dismiss`
69
+ type IssueReopenPath = `${KnowledgeBasePath}/issues/{issueId}/reopen`
70
+ type InstructionsPath = `${KnowledgeBasePath}/instructions`
71
+
72
+ type JsonResponse<T> = T extends {content: {'application/json': infer R}} ? R : never
73
+ type JsonBody<T> = T extends {
74
+ requestBody: {content: {'application/json': infer R}}
75
+ }
76
+ ? R
77
+ : never
78
+
79
+ /**
80
+ * A knowledge base: one buildable body of knowledge inside Context.
81
+ * @beta
82
+ */
83
+ export type KnowledgeBase = JsonResponse<paths[KnowledgeBasePath]['get']['responses']['200']>
84
+
85
+ /**
86
+ * Parameters for creating a knowledge base.
87
+ * @beta
88
+ */
89
+ export type CreateKnowledgeBaseParams = JsonBody<paths[KnowledgeBasesPath]['post']>
90
+ /** @beta */
91
+ export type EditKnowledgeBaseParams = JsonBody<paths[KnowledgeBasePath]['patch']>
92
+
93
+ /**
94
+ * Parameters for importing content. Discriminated on `type`:
95
+ * inline text, a website crawl, or a Sanity dataset bind.
96
+ * @beta
97
+ */
98
+ export type CreateImportParams = JsonBody<paths[ImportsPath]['post']>
99
+
100
+ /**
101
+ * Accepted async work. Poll the job with `jobs.get` until it reaches a
102
+ * terminal state.
103
+ * @beta
104
+ */
105
+ export type JobAccepted = JsonResponse<
106
+ paths[`${KnowledgeBasePath}/build`]['post']['responses']['202']
107
+ >
108
+
109
+ /** @beta */
110
+ export type Job = JsonResponse<paths[JobPath]['get']['responses']['200']>
111
+
112
+ /**
113
+ * Accepted entry rebuild: the job to poll plus every entry the rebuild
114
+ * touches.
115
+ * @beta
116
+ */
117
+ export type RebuildEntryResponse = JsonResponse<paths[EntryRebuildPath]['post']['responses']['202']>
118
+
119
+ /** @beta */
120
+ export type ApplyIssuesParams = JsonBody<paths[IssuesApplyPath]['post']>
121
+ /** @beta */
122
+ export type ApplyIssuesResponse = JsonResponse<paths[IssuesApplyPath]['post']['responses']['202']>
123
+ /** @beta */
124
+ export type ResolveIssueParams = JsonBody<paths[IssueResolvePath]['post']>
125
+ /** @beta */
126
+ export type ResolveIssueResponse = JsonResponse<paths[IssueResolvePath]['post']['responses']['200']>
127
+ /** @beta */
128
+ export type DismissIssueResponse = JsonResponse<paths[IssueDismissPath]['post']['responses']['200']>
129
+ /** @beta */
130
+ export type ReopenIssueResponse = JsonResponse<paths[IssueReopenPath]['post']['responses']['200']>
131
+
132
+ /** @beta */
133
+ export type CreateInstructionParams = JsonBody<paths[InstructionsPath]['post']>
134
+ /**
135
+ * A standing instruction, as the instruction endpoints return it.
136
+ * @beta
137
+ */
138
+ export type Instruction = JsonResponse<paths[InstructionPath]['patch']['responses']['200']>
139
+ /** The created instruction, wrapped the way the create endpoint returns it. @beta */
140
+ export type CreateInstructionResponse = JsonResponse<
141
+ paths[InstructionsPath]['post']['responses']['201']
142
+ >
143
+ /** @beta */
144
+ export type EditInstructionParams = JsonBody<paths[InstructionPath]['patch']>
145
+
146
+ /** @beta */
147
+ export type KnowledgeBasesResponse = JsonResponse<
148
+ paths[KnowledgeBasesPath]['get']['responses']['200']
149
+ >
150
+
151
+ /** @beta */
152
+ export type ImportsResponse = JsonResponse<paths[ImportsPath]['get']['responses']['200']>
153
+ /** @beta */
154
+ export type Import = ImportsResponse['data'][number]
155
+ /** @beta */
156
+ export type ImportDetail = JsonResponse<paths[ImportPath]['get']['responses']['200']>
157
+ /** @beta */
158
+ export type ImportDownloadResponse = JsonResponse<
159
+ paths[`${ImportPath}/download`]['get']['responses']['200']
160
+ >
161
+
162
+ /**
163
+ * The staged half of a file upload: PUT the bytes to `uploadUrl`, then
164
+ * confirm with the complete endpoint. `imports.create({type: 'file'})` does
165
+ * all of this in one call.
166
+ * @beta
167
+ */
168
+ export type StagedUpload = JsonResponse<paths[UploadsPath]['post']['responses']['201']>
169
+
170
+ /** @beta */
171
+ export type SourcesResponse = JsonResponse<paths[SourcesPath]['get']['responses']['200']>
172
+ /** @beta */
173
+ export type Source = SourcesResponse['data'][number]
174
+ /** @beta */
175
+ export type SourceDetail = JsonResponse<paths[SourcePath]['get']['responses']['200']>
176
+ /** @beta */
177
+ export type SourceContentResponse = JsonResponse<
178
+ paths[SourceContentPath]['get']['responses']['200']
179
+ >
180
+
181
+ /**
182
+ * A recorded conversation: one agent thread's transcript plus the
183
+ * classification recorded on it. Standalone org-level telemetry — dimensions
184
+ * (MCP endpoints, app, the customer's own keys) live in the `metadata` bag.
185
+ * @beta
186
+ */
187
+ export type Conversation = JsonResponse<paths[ConversationPath]['put']['responses']['200']>
188
+ /**
189
+ * Body for the conversation ingest upsert. Messages replace the stored
190
+ * transcript wholesale; `metadata` and model fields only overwrite when
191
+ * present.
192
+ * @beta
193
+ */
194
+ export type SaveConversationParams = JsonBody<paths[ConversationPath]['put']>
195
+ /** Exactly one of a verdict (`coreMetrics`) or a failure (`classificationError`). @beta */
196
+ export type ClassifyConversationParams = JsonBody<paths[ConversationPath]['patch']>
197
+
198
+ /**
199
+ * The raw `sanity.context.entry` document shape, as stored in the
200
+ * organization's document store. For typing GROQ reads.
201
+ * @beta
202
+ */
203
+ export type EntryDoc = components['schemas']['EntryDoc']
204
+ /** @beta */
205
+ export type IssueDoc = components['schemas']['IssueDoc']
206
+ /** @beta */
207
+ export type InstructionDoc = components['schemas']['InstructionDoc']
208
+ /**
209
+ * The raw `sanity.context.mcp` document shape (an MCP endpoint
210
+ * configuration), as stored in the organization's document store. For
211
+ * typing GROQ reads.
212
+ * @beta
213
+ */
214
+ export type McpDoc = components['schemas']['McpDoc']
215
+
216
+ /**
217
+ * The metadata view of an entry, as `entries.list` projects it. Bodies stay
218
+ * behind `entries.get` (or a GROQ read through `context.fetch`).
219
+ * @beta
220
+ */
221
+ export type Entry = Pick<EntryDoc, '_id' | 'path' | 'title' | 'tldr' | 'status'>
222
+
223
+ /**
224
+ * The raw `sanity.context.conversation` document shape, as stored in the
225
+ * organization's document store. For typing GROQ reads.
226
+ * @beta
227
+ */
228
+ export type ConversationDoc = components['schemas']['ConversationDoc']
@@ -1128,7 +1128,7 @@ export function _prepareRequest(client: Client, options: RequestObservableOption
1128
1128
  *
1129
1129
  * @internal
1130
1130
  */
1131
- function _observe<R>(
1131
+ export function _observe<R>(
1132
1132
  userSignal: AbortSignal | undefined,
1133
1133
  run: (signal: AbortSignal) => Promise<R>,
1134
1134
  ): Observable<R> {
@@ -1291,6 +1291,9 @@ const resourceDataBase = (config: InitializedClientConfig): string => {
1291
1291
  case 'canvas': {
1292
1292
  return `/canvases/${id}`
1293
1293
  }
1294
+ case 'knowledge-base': {
1295
+ return `/knowledge-bases/${id}`
1296
+ }
1294
1297
  case 'media-library': {
1295
1298
  return `/media-libraries/${id}`
1296
1299
  }
package/src/data/live.ts CHANGED
@@ -26,6 +26,7 @@ const requiredApiVersion = '2021-03-25'
26
26
 
27
27
  /**
28
28
  * @public
29
+ * @inline
29
30
  */
30
31
  export class LiveClient {
31
32
  #client: SanityClient | ObservableSanityClient
@@ -13,7 +13,10 @@ import type {
13
13
  } from '../types'
14
14
  import * as validate from '../validators'
15
15
 
16
- /** @internal */
16
+ /**
17
+ * @internal
18
+ * @inline
19
+ */
17
20
  export class ObservableDatasetsClient {
18
21
  #client: ObservableSanityClient
19
22
  #httpRequest: HttpRequest
@@ -107,7 +110,10 @@ export class ObservableDatasetsClient {
107
110
  }
108
111
  }
109
112
 
110
- /** @internal */
113
+ /**
114
+ * @internal
115
+ * @inline
116
+ */
111
117
  export class DatasetsClient {
112
118
  #client: SanityClient
113
119
  #httpRequest: HttpRequest
@@ -26,6 +26,7 @@ export {
26
26
  isQueryParseError,
27
27
  ServerError,
28
28
  } from './http/errors'
29
+ export * as Context from './context/types'
29
30
  export * from './SanityClient'
30
31
  export * from './types'
31
32
 
@@ -1,14 +1,9 @@
1
- import {createDebug} from 'obug'
2
1
  import {Observable} from 'rxjs'
3
2
 
4
3
  import type {UploadEvent} from '../types'
5
4
  import {ClientError, httpResponseFromFetch, ServerError} from './errors'
6
5
  import {parseJsonText} from './request'
7
6
 
8
- const log = createDebug('sanity:client')
9
-
10
- let nextRequestId = 1
11
-
12
7
  /**
13
8
  * Options for a browser-side asset upload that needs progress events.
14
9
  *
@@ -36,11 +31,8 @@ export interface BrowserUploadOptions {
36
31
  export function uploadWithProgress<T>(options: BrowserUploadOptions): Observable<UploadEvent<T>> {
37
32
  return new Observable<UploadEvent<T>>((subscriber) => {
38
33
  const xhr = new XMLHttpRequest()
39
- const requestId = nextRequestId++
40
34
  const {url, method, headers, body, withCredentials, timeout, signal} = options
41
35
 
42
- log('[%d] %s %s (XHR upload with progress)', requestId, method, url)
43
-
44
36
  xhr.open(method, url)
45
37
  xhr.withCredentials = withCredentials
46
38
  if (typeof timeout === 'number' && timeout > 0) {
@@ -63,8 +55,6 @@ export function uploadWithProgress<T>(options: BrowserUploadOptions): Observable
63
55
  }
64
56
 
65
57
  xhr.onload = () => {
66
- log('[%d] %s %s — %d', requestId, method, url, xhr.status)
67
-
68
58
  if (xhr.status >= 400) {
69
59
  // Same typed errors as the fetch transport, so consumers can keep
70
60
  // detecting `ClientError`/`ServerError` and reading `statusCode`,
@@ -100,12 +90,10 @@ export function uploadWithProgress<T>(options: BrowserUploadOptions): Observable
100
90
  }
101
91
 
102
92
  xhr.onerror = () => {
103
- log('[%d] %s %s — network error', requestId, method, url)
104
93
  subscriber.error(new Error('XHR upload network error'))
105
94
  }
106
95
 
107
96
  xhr.ontimeout = () => {
108
- log('[%d] %s %s — timed out after %dms', requestId, method, url, timeout)
109
97
  // Same error shape as the fetch transport's timeout rejection.
110
98
  subscriber.error(
111
99
  new DOMException(
@@ -10,7 +10,10 @@ import type {
10
10
  VideoPlaybackInfo,
11
11
  } from '../types'
12
12
 
13
- /** @internal */
13
+ /**
14
+ * @internal
15
+ * @inline
16
+ */
14
17
  export class ObservableMediaLibraryVideoClient {
15
18
  #client: ObservableSanityClient
16
19
  #httpRequest: HttpRequest
@@ -53,7 +56,10 @@ export class ObservableMediaLibraryVideoClient {
53
56
  }
54
57
  }
55
58
 
56
- /** @internal */
59
+ /**
60
+ * @internal
61
+ * @inline
62
+ */
57
63
  export class MediaLibraryVideoClient {
58
64
  #client: SanityClient
59
65
  #httpRequest: HttpRequest
@@ -15,7 +15,10 @@ type OmittedProjectFields<T extends ListOptions | undefined> =
15
15
  | (T extends {includeMembers: false} ? 'members' : never)
16
16
  | (T extends {includeFeatures: false} ? 'features' : never)
17
17
 
18
- /** @internal */
18
+ /**
19
+ * @internal
20
+ * @inline
21
+ */
19
22
  export class ObservableProjectsClient {
20
23
  #client: ObservableSanityClient
21
24
  #httpRequest: HttpRequest
@@ -69,7 +72,10 @@ export class ObservableProjectsClient {
69
72
  }
70
73
  }
71
74
 
72
- /** @internal */
75
+ /**
76
+ * @internal
77
+ * @inline
78
+ */
73
79
  export class ProjectsClient {
74
80
  #client: SanityClient
75
81
  #httpRequest: HttpRequest
@@ -28,7 +28,10 @@ import type {
28
28
  } from '../types'
29
29
  import {createRelease} from './createRelease'
30
30
 
31
- /** @public */
31
+ /**
32
+ * @public
33
+ * @inline
34
+ */
32
35
  export class ObservableReleasesClient {
33
36
  #client: ObservableSanityClient
34
37
  #httpRequest: HttpRequest
@@ -365,7 +368,10 @@ export class ObservableReleasesClient {
365
368
  }
366
369
  }
367
370
 
368
- /** @public */
371
+ /**
372
+ * @public
373
+ * @inline
374
+ */
369
375
  export class ReleasesClient {
370
376
  #client: SanityClient
371
377
  #httpRequest: HttpRequest
package/src/types.ts CHANGED
@@ -109,6 +109,10 @@ type ClientConfigResource =
109
109
  type: 'canvas'
110
110
  id: string
111
111
  }
112
+ | {
113
+ type: 'knowledge-base'
114
+ id: string
115
+ }
112
116
  | {
113
117
  type: 'media-library'
114
118
  id: string
@@ -314,6 +318,17 @@ export interface ClientConfig {
314
318
  collaboration?: {
315
319
  organizationId?: string
316
320
  }
321
+
322
+ /**
323
+ * Organization-scoped configuration for Context APIs.
324
+ *
325
+ * Currently this is used by `context.insights` methods.
326
+ *
327
+ * @beta
328
+ */
329
+ context?: {
330
+ organizationId?: string
331
+ }
317
332
  }
318
333
 
319
334
  /** @public */
@@ -620,6 +635,7 @@ export type DatasetAclMode = 'public' | 'private' | 'custom'
620
635
  /** @public */
621
636
  export type DatasetCreateOptions = {
622
637
  aclMode?: DatasetAclMode
638
+ description?: string | null
623
639
  embeddings?: {
624
640
  enabled: boolean
625
641
  projection?: string
@@ -629,6 +645,7 @@ export type DatasetCreateOptions = {
629
645
  /** @public */
630
646
  export type DatasetEditOptions = {
631
647
  aclMode?: DatasetAclMode
648
+ description?: string | null
632
649
  }
633
650
 
634
651
  /** @public */
@@ -645,17 +662,25 @@ export type EmbeddingsSettingsBody = {
645
662
  }
646
663
 
647
664
  /** @public */
648
- export type DatasetResponse = {datasetName: string; aclMode: DatasetAclMode}
665
+ export type DatasetResponse = {
666
+ datasetName: string
667
+ aclMode: DatasetAclMode
668
+ description: string | null
669
+ }
649
670
  /** @public */
650
671
  export type DatasetsResponse = {
651
672
  name: string
652
673
  aclMode: DatasetAclMode
674
+ description?: string
653
675
  createdAt: string
654
676
  createdByUserId: string
655
677
  addonFor: string | null
656
678
  datasetProfile: string
657
679
  features: string[]
658
- tags: string[]
680
+ tags: {
681
+ name: string
682
+ title: string
683
+ }[]
659
684
  }[]
660
685
 
661
686
  /** @public */
@@ -2255,8 +2280,47 @@ export type LiveEvent =
2255
2280
  | LiveEventWelcome
2256
2281
  | LiveEventGoAway
2257
2282
 
2258
- /** @public */
2259
- export interface SanityQueries {}
2283
+ declare global {
2284
+ /**
2285
+ * Query result types, keyed by GROQ query string. Empty by default, `sanity typegen` registers
2286
+ * the queries it finds:
2287
+ * ```ts
2288
+ * declare global {
2289
+ * interface SanityQueries {
2290
+ * '*[_type == "post"]': PostsQueryResult
2291
+ * }
2292
+ * }
2293
+ * ```
2294
+ * `client.fetch(query)` and `ClientReturn<typeof query>` then resolve to the registered type.
2295
+ *
2296
+ * The registry is a global rather than a module augmentation of `@sanity/client` so that it
2297
+ * does not depend on module resolution: it resolves the same whether `@sanity/client` is a
2298
+ * direct dependency, how many copies of it are installed, and from every subpath export.
2299
+ */
2300
+ interface SanityQueries {}
2301
+ }
2302
+
2303
+ /**
2304
+ * The query registry as seen from `@sanity/client`. Inherits every query registered on the global
2305
+ * `SanityQueries` interface, and still accepts the older module augmentation form:
2306
+ * ```ts
2307
+ * declare module '@sanity/client' {
2308
+ * interface SanityQueries {
2309
+ * '*[_type == "post"]': PostsQueryResult
2310
+ * }
2311
+ * }
2312
+ * ```
2313
+ * `@sanity/client` releases that predate the global registry only read this interface, so a
2314
+ * generated file that registers queries globally can bridge them with an augmentation that adds
2315
+ * the global as a base type. It is harmless on releases that already inherit it:
2316
+ * ```ts
2317
+ * declare module '@sanity/client' {
2318
+ * interface SanityQueries extends globalThis.SanityQueries {}
2319
+ * }
2320
+ * ```
2321
+ * @public
2322
+ */
2323
+ export interface SanityQueries extends globalThis.SanityQueries {}
2260
2324
 
2261
2325
  /** @public */
2262
2326
  export type ClientReturn<
@@ -4,7 +4,10 @@ import {_request, _requestObservable} from '../data/dataMethods'
4
4
  import type {ObservableSanityClient, SanityClient} from '../SanityClient'
5
5
  import type {CurrentSanityUser, HttpRequest, SanityUser} from '../types'
6
6
 
7
- /** @public */
7
+ /**
8
+ * @public
9
+ * @inline
10
+ */
8
11
  export class ObservableUsersClient {
9
12
  #client: ObservableSanityClient
10
13
  #httpRequest: HttpRequest
@@ -27,7 +30,10 @@ export class ObservableUsersClient {
27
30
  }
28
31
  }
29
32
 
30
- /** @public */
33
+ /**
34
+ * @public
35
+ * @inline
36
+ */
31
37
  export class UsersClient {
32
38
  #client: SanityClient
33
39
  #httpRequest: HttpRequest
package/src/validators.ts CHANGED
@@ -128,6 +128,7 @@ export const resourceConfig = (config: InitializedClientConfig): void => {
128
128
  return
129
129
  }
130
130
  case 'dashboard':
131
+ case 'knowledge-base':
131
132
  case 'media-library':
132
133
  case 'canvas': {
133
134
  return
@@ -1 +0,0 @@
1
- {"version":3,"file":"browserUpload-2tz6Sdqp.js","names":[],"sources":["../src/http/browserUpload.ts"],"sourcesContent":["import {createDebug} from 'obug'\nimport {Observable} from 'rxjs'\n\nimport type {UploadEvent} from '../types'\nimport {ClientError, httpResponseFromFetch, ServerError} from './errors'\nimport {parseJsonText} from './request'\n\nconst log = createDebug('sanity:client')\n\nlet nextRequestId = 1\n\n/**\n * Options for a browser-side asset upload that needs progress events.\n *\n * @internal\n */\nexport interface BrowserUploadOptions {\n url: string\n method: string\n headers: Record<string, string>\n body: unknown\n withCredentials: boolean\n /** Milliseconds before the upload is aborted; `false` and `0` both disable the timeout. */\n timeout?: number | false\n signal?: AbortSignal\n}\n\n/**\n * Run an asset upload through `XMLHttpRequest` so we can surface per-chunk\n * upload progress events. get-it v9 / fetch has no equivalent hook in the\n * browser, so the observable asset-upload API falls back to this path when\n * `XMLHttpRequest` is available.\n *\n * @internal\n */\nexport function uploadWithProgress<T>(options: BrowserUploadOptions): Observable<UploadEvent<T>> {\n return new Observable<UploadEvent<T>>((subscriber) => {\n const xhr = new XMLHttpRequest()\n const requestId = nextRequestId++\n const {url, method, headers, body, withCredentials, timeout, signal} = options\n\n log('[%d] %s %s (XHR upload with progress)', requestId, method, url)\n\n xhr.open(method, url)\n xhr.withCredentials = withCredentials\n if (typeof timeout === 'number' && timeout > 0) {\n xhr.timeout = timeout\n }\n\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value)\n }\n\n xhr.upload.onprogress = (e) => {\n subscriber.next({\n type: 'progress',\n stage: 'upload',\n percent: e.lengthComputable ? Math.round((e.loaded / e.total) * 100) : 0,\n total: e.total || undefined,\n loaded: e.loaded,\n lengthComputable: e.lengthComputable,\n })\n }\n\n xhr.onload = () => {\n log('[%d] %s %s — %d', requestId, method, url, xhr.status)\n\n if (xhr.status >= 400) {\n // Same typed errors as the fetch transport, so consumers can keep\n // detecting `ClientError`/`ServerError` and reading `statusCode`,\n // `responseBody` and the structured API `details` on failed uploads.\n const errorHeaders = parseXhrResponseHeaders(xhr.getAllResponseHeaders())\n const canonical = httpResponseFromFetch(\n {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: errorHeaders,\n body: parseJsonText(xhr.responseText, errorHeaders),\n url: xhr.responseURL,\n },\n url,\n method,\n )\n subscriber.error(\n xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical),\n )\n return\n }\n\n let responseBody: T\n try {\n responseBody = JSON.parse(xhr.responseText) as T\n } catch {\n subscriber.error(new Error('Failed to parse upload response as JSON'))\n return\n }\n\n subscriber.next({type: 'response', body: responseBody})\n subscriber.complete()\n }\n\n xhr.onerror = () => {\n log('[%d] %s %s — network error', requestId, method, url)\n subscriber.error(new Error('XHR upload network error'))\n }\n\n xhr.ontimeout = () => {\n log('[%d] %s %s — timed out after %dms', requestId, method, url, timeout)\n // Same error shape as the fetch transport's timeout rejection.\n subscriber.error(\n new DOMException(\n `The operation timed out after ${timeout}ms while attempting to reach ${url}`,\n 'TimeoutError',\n ),\n )\n }\n\n xhr.onabort = () => {\n subscriber.error(new DOMException('Upload aborted', 'AbortError'))\n }\n\n const onSignalAbort = () => xhr.abort()\n if (signal) {\n if (signal.aborted) {\n // `xhr.abort()` before `send()` fires no `abort` event per spec, so\n // error out directly instead of relying on `onabort`.\n subscriber.error(new DOMException('Upload aborted', 'AbortError'))\n return undefined\n }\n signal.addEventListener('abort', onSignalAbort, {once: true})\n }\n\n xhr.send(body as XMLHttpRequestBodyInit)\n\n // Unsubscribing cancels the in-flight upload, mirroring how the fetch\n // path aborts its request (`_observe`). After settle this is a no-op —\n // except for detaching from the caller's signal, which may be long-lived\n // and must not accumulate a listener per upload.\n return () => {\n signal?.removeEventListener('abort', onSignalAbort)\n xhr.abort()\n }\n })\n}\n\n/**\n * Parse `XMLHttpRequest.getAllResponseHeaders()` output (CRLF-separated\n * `name: value` lines) into a `Headers` instance.\n */\nfunction parseXhrResponseHeaders(raw: string): Headers {\n const headers = new Headers()\n for (const line of raw.split('\\r\\n')) {\n const separator = line.indexOf(':')\n if (separator <= 0) continue\n try {\n headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim())\n } catch {\n // Skip header lines the Headers constructor rejects — better a partial\n // header record on the error than no error details at all.\n }\n }\n return headers\n}\n"],"mappings":";;;AAOA,MAAM,MAAM,YAAY,eAAe;AAEvC,IAAI,gBAAgB;;;;;;;;;AA0BpB,SAAgB,mBAAsB,SAA2D;CAC/F,OAAO,IAAI,YAA4B,eAAe;EACpD,IAAM,MAAM,IAAI,eAAe,GACzB,YAAY,iBACZ,EAAC,KAAK,QAAQ,SAAS,MAAM,iBAAiB,SAAS,WAAU;EAMvE,AAJA,IAAI,yCAAyC,WAAW,QAAQ,GAAG,GAEnE,IAAI,KAAK,QAAQ,GAAG,GACpB,IAAI,kBAAkB,iBAClB,OAAO,WAAY,YAAY,UAAU,MAC3C,IAAI,UAAU;EAGhB,KAAK,IAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,iBAAiB,KAAK,KAAK;EAmEjC,AAhEA,IAAI,OAAO,cAAc,MAAM;GAC7B,WAAW,KAAK;IACd,MAAM;IACN,OAAO;IACP,SAAS,EAAE,mBAAmB,KAAK,MAAO,EAAE,SAAS,EAAE,QAAS,GAAG,IAAI;IACvE,OAAO,EAAE,SAAS,KAAA;IAClB,QAAQ,EAAE;IACV,kBAAkB,EAAE;GACtB,CAAC;EACH,GAEA,IAAI,eAAe;GAGjB,IAFA,IAAI,mBAAmB,WAAW,QAAQ,KAAK,IAAI,MAAM,GAErD,IAAI,UAAU,KAAK;IAIrB,IAAM,eAAe,wBAAwB,IAAI,sBAAsB,CAAC,GAClE,YAAY,sBAChB;KACE,QAAQ,IAAI;KACZ,YAAY,IAAI;KAChB,SAAS;KACT,MAAM,cAAc,IAAI,cAAc,YAAY;KAClD,KAAK,IAAI;IACX,GACA,KACA,MACF;IACA,WAAW,MACT,IAAI,UAAU,MAAM,IAAI,YAAY,SAAS,IAAI,IAAI,YAAY,SAAS,CAC5E;IACA;GACF;GAEA,IAAI;GACJ,IAAI;IACF,eAAe,KAAK,MAAM,IAAI,YAAY;GAC5C,QAAQ;IACN,WAAW,MAAM,gBAAI,MAAM,yCAAyC,CAAC;IACrE;GACF;GAGA,AADA,WAAW,KAAK;IAAC,MAAM;IAAY,MAAM;GAAY,CAAC,GACtD,WAAW,SAAS;EACtB,GAEA,IAAI,gBAAgB;GAElB,AADA,IAAI,8BAA8B,WAAW,QAAQ,GAAG,GACxD,WAAW,MAAM,gBAAI,MAAM,0BAA0B,CAAC;EACxD,GAEA,IAAI,kBAAkB;GAGpB,AAFA,IAAI,qCAAqC,WAAW,QAAQ,KAAK,OAAO,GAExE,WAAW,MACT,IAAI,aACF,iCAAiC,QAAQ,+BAA+B,OACxE,cACF,CACF;EACF,GAEA,IAAI,gBAAgB;GAClB,WAAW,MAAM,IAAI,aAAa,kBAAkB,YAAY,CAAC;EACnE;EAEA,IAAM,sBAAsB,IAAI,MAAM;EACtC,IAAI,QAAQ;GACV,IAAI,OAAO,SAAS;IAGlB,WAAW,MAAM,IAAI,aAAa,kBAAkB,YAAY,CAAC;IACjE;GACF;GACA,OAAO,iBAAiB,SAAS,eAAe,EAAC,MAAM,GAAI,CAAC;EAC9D;EAQA,OANA,IAAI,KAAK,IAA8B,SAM1B;GAEX,AADA,QAAQ,oBAAoB,SAAS,aAAa,GAClD,IAAI,MAAM;EACZ;CACF,CAAC;AACH;;;;;AAMA,SAAS,wBAAwB,KAAsB;CACrD,IAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,IAAM,QAAQ,IAAI,MAAM,MAAM,GAAG;EACpC,IAAM,YAAY,KAAK,QAAQ,GAAG;EAC9B,mBAAa,IACjB,IAAI;GACF,QAAQ,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC,KAAK,GAAG,KAAK,MAAM,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;EAClF,QAAQ,CAGR;CACF;CACA,OAAO;AACT"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"browserUpload-CwpNx7Vl.js","names":[],"sources":["../src/http/browserUpload.ts"],"sourcesContent":["import {createDebug} from 'obug'\nimport {Observable} from 'rxjs'\n\nimport type {UploadEvent} from '../types'\nimport {ClientError, httpResponseFromFetch, ServerError} from './errors'\nimport {parseJsonText} from './request'\n\nconst log = createDebug('sanity:client')\n\nlet nextRequestId = 1\n\n/**\n * Options for a browser-side asset upload that needs progress events.\n *\n * @internal\n */\nexport interface BrowserUploadOptions {\n url: string\n method: string\n headers: Record<string, string>\n body: unknown\n withCredentials: boolean\n /** Milliseconds before the upload is aborted; `false` and `0` both disable the timeout. */\n timeout?: number | false\n signal?: AbortSignal\n}\n\n/**\n * Run an asset upload through `XMLHttpRequest` so we can surface per-chunk\n * upload progress events. get-it v9 / fetch has no equivalent hook in the\n * browser, so the observable asset-upload API falls back to this path when\n * `XMLHttpRequest` is available.\n *\n * @internal\n */\nexport function uploadWithProgress<T>(options: BrowserUploadOptions): Observable<UploadEvent<T>> {\n return new Observable<UploadEvent<T>>((subscriber) => {\n const xhr = new XMLHttpRequest()\n const requestId = nextRequestId++\n const {url, method, headers, body, withCredentials, timeout, signal} = options\n\n log('[%d] %s %s (XHR upload with progress)', requestId, method, url)\n\n xhr.open(method, url)\n xhr.withCredentials = withCredentials\n if (typeof timeout === 'number' && timeout > 0) {\n xhr.timeout = timeout\n }\n\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value)\n }\n\n xhr.upload.onprogress = (e) => {\n subscriber.next({\n type: 'progress',\n stage: 'upload',\n percent: e.lengthComputable ? Math.round((e.loaded / e.total) * 100) : 0,\n total: e.total || undefined,\n loaded: e.loaded,\n lengthComputable: e.lengthComputable,\n })\n }\n\n xhr.onload = () => {\n log('[%d] %s %s — %d', requestId, method, url, xhr.status)\n\n if (xhr.status >= 400) {\n // Same typed errors as the fetch transport, so consumers can keep\n // detecting `ClientError`/`ServerError` and reading `statusCode`,\n // `responseBody` and the structured API `details` on failed uploads.\n const errorHeaders = parseXhrResponseHeaders(xhr.getAllResponseHeaders())\n const canonical = httpResponseFromFetch(\n {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: errorHeaders,\n body: parseJsonText(xhr.responseText, errorHeaders),\n url: xhr.responseURL,\n },\n url,\n method,\n )\n subscriber.error(\n xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical),\n )\n return\n }\n\n let responseBody: T\n try {\n responseBody = JSON.parse(xhr.responseText) as T\n } catch {\n subscriber.error(new Error('Failed to parse upload response as JSON'))\n return\n }\n\n subscriber.next({type: 'response', body: responseBody})\n subscriber.complete()\n }\n\n xhr.onerror = () => {\n log('[%d] %s %s — network error', requestId, method, url)\n subscriber.error(new Error('XHR upload network error'))\n }\n\n xhr.ontimeout = () => {\n log('[%d] %s %s — timed out after %dms', requestId, method, url, timeout)\n // Same error shape as the fetch transport's timeout rejection.\n subscriber.error(\n new DOMException(\n `The operation timed out after ${timeout}ms while attempting to reach ${url}`,\n 'TimeoutError',\n ),\n )\n }\n\n xhr.onabort = () => {\n subscriber.error(new DOMException('Upload aborted', 'AbortError'))\n }\n\n const onSignalAbort = () => xhr.abort()\n if (signal) {\n if (signal.aborted) {\n // `xhr.abort()` before `send()` fires no `abort` event per spec, so\n // error out directly instead of relying on `onabort`.\n subscriber.error(new DOMException('Upload aborted', 'AbortError'))\n return undefined\n }\n signal.addEventListener('abort', onSignalAbort, {once: true})\n }\n\n xhr.send(body as XMLHttpRequestBodyInit)\n\n // Unsubscribing cancels the in-flight upload, mirroring how the fetch\n // path aborts its request (`_observe`). After settle this is a no-op —\n // except for detaching from the caller's signal, which may be long-lived\n // and must not accumulate a listener per upload.\n return () => {\n signal?.removeEventListener('abort', onSignalAbort)\n xhr.abort()\n }\n })\n}\n\n/**\n * Parse `XMLHttpRequest.getAllResponseHeaders()` output (CRLF-separated\n * `name: value` lines) into a `Headers` instance.\n */\nfunction parseXhrResponseHeaders(raw: string): Headers {\n const headers = new Headers()\n for (const line of raw.split('\\r\\n')) {\n const separator = line.indexOf(':')\n if (separator <= 0) continue\n try {\n headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim())\n } catch {\n // Skip header lines the Headers constructor rejects — better a partial\n // header record on the error than no error details at all.\n }\n }\n return headers\n}\n"],"mappings":";;;AAOA,MAAM,MAAM,YAAY,eAAe;AAEvC,IAAI,gBAAgB;;;;;;;;;AA0BpB,SAAgB,mBAAsB,SAA2D;CAC/F,OAAO,IAAI,YAA4B,eAAe;EACpD,IAAM,MAAM,IAAI,eAAe,GACzB,YAAY,iBACZ,EAAC,KAAK,QAAQ,SAAS,MAAM,iBAAiB,SAAS,WAAU;EAMvE,AAJA,IAAI,yCAAyC,WAAW,QAAQ,GAAG,GAEnE,IAAI,KAAK,QAAQ,GAAG,GACpB,IAAI,kBAAkB,iBAClB,OAAO,WAAY,YAAY,UAAU,MAC3C,IAAI,UAAU;EAGhB,KAAK,IAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,iBAAiB,KAAK,KAAK;EAmEjC,AAhEA,IAAI,OAAO,cAAc,MAAM;GAC7B,WAAW,KAAK;IACd,MAAM;IACN,OAAO;IACP,SAAS,EAAE,mBAAmB,KAAK,MAAO,EAAE,SAAS,EAAE,QAAS,GAAG,IAAI;IACvE,OAAO,EAAE,SAAS,KAAA;IAClB,QAAQ,EAAE;IACV,kBAAkB,EAAE;GACtB,CAAC;EACH,GAEA,IAAI,eAAe;GAGjB,IAFA,IAAI,mBAAmB,WAAW,QAAQ,KAAK,IAAI,MAAM,GAErD,IAAI,UAAU,KAAK;IAIrB,IAAM,eAAe,wBAAwB,IAAI,sBAAsB,CAAC,GAClE,YAAY,sBAChB;KACE,QAAQ,IAAI;KACZ,YAAY,IAAI;KAChB,SAAS;KACT,MAAM,cAAc,IAAI,cAAc,YAAY;KAClD,KAAK,IAAI;IACX,GACA,KACA,MACF;IACA,WAAW,MACT,IAAI,UAAU,MAAM,IAAI,YAAY,SAAS,IAAI,IAAI,YAAY,SAAS,CAC5E;IACA;GACF;GAEA,IAAI;GACJ,IAAI;IACF,eAAe,KAAK,MAAM,IAAI,YAAY;GAC5C,QAAQ;IACN,WAAW,MAAM,gBAAI,MAAM,yCAAyC,CAAC;IACrE;GACF;GAGA,AADA,WAAW,KAAK;IAAC,MAAM;IAAY,MAAM;GAAY,CAAC,GACtD,WAAW,SAAS;EACtB,GAEA,IAAI,gBAAgB;GAElB,AADA,IAAI,8BAA8B,WAAW,QAAQ,GAAG,GACxD,WAAW,MAAM,gBAAI,MAAM,0BAA0B,CAAC;EACxD,GAEA,IAAI,kBAAkB;GAGpB,AAFA,IAAI,qCAAqC,WAAW,QAAQ,KAAK,OAAO,GAExE,WAAW,MACT,IAAI,aACF,iCAAiC,QAAQ,+BAA+B,OACxE,cACF,CACF;EACF,GAEA,IAAI,gBAAgB;GAClB,WAAW,MAAM,IAAI,aAAa,kBAAkB,YAAY,CAAC;EACnE;EAEA,IAAM,sBAAsB,IAAI,MAAM;EACtC,IAAI,QAAQ;GACV,IAAI,OAAO,SAAS;IAGlB,WAAW,MAAM,IAAI,aAAa,kBAAkB,YAAY,CAAC;IACjE;GACF;GACA,OAAO,iBAAiB,SAAS,eAAe,EAAC,MAAM,GAAI,CAAC;EAC9D;EAQA,OANA,IAAI,KAAK,IAA8B,SAM1B;GAEX,AADA,QAAQ,oBAAoB,SAAS,aAAa,GAClD,IAAI,MAAM;EACZ;CACF,CAAC;AACH;;;;;AAMA,SAAS,wBAAwB,KAAsB;CACrD,IAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,IAAM,QAAQ,IAAI,MAAM,MAAM,GAAG;EACpC,IAAM,YAAY,KAAK,QAAQ,GAAG;EAC9B,mBAAa,IACjB,IAAI;GACF,QAAQ,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC,KAAK,GAAG,KAAK,MAAM,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;EAClF,QAAQ,CAGR;CACF;CACA,OAAO;AACT"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-3wiPP-sZ.js","names":["resourceConfig","validate.requestTag"],"sources":["../src/generateHelpUrl.ts","../src/validators.ts","../src/util/once.ts","../src/warnings.ts","../src/config.ts"],"sourcesContent":["const BASE_URL = 'https://www.sanity.io/help/'\n\nexport function generateHelpUrl(slug: string) {\n return BASE_URL + slug\n}\n","import type {Any, InitializedClientConfig, SanityDocumentStub} from './types'\n\nconst VALID_ASSET_TYPES = ['image', 'file']\nconst VALID_INSERT_LOCATIONS = ['before', 'after', 'replace']\n\nexport const dataset = (name: string) => {\n if (!/^(~[a-z0-9]{1}[-\\w]{0,63}|[a-z0-9]{1}[-\\w]{0,63})$/.test(name)) {\n throw new Error(\n 'Datasets can only contain lowercase characters, numbers, underscores and dashes, and start with tilde, and be maximum 64 characters',\n )\n }\n}\n\nexport const projectId = (id: string) => {\n if (!/^[-a-z0-9]+$/i.test(id)) {\n throw new Error('`projectId` can only contain only a-z, 0-9 and dashes')\n }\n}\n\nexport const validateAssetType = (type: string) => {\n if (VALID_ASSET_TYPES.indexOf(type) === -1) {\n throw new Error(`Invalid asset type: ${type}. Must be one of ${VALID_ASSET_TYPES.join(', ')}`)\n }\n}\n\nexport const validateObject = (op: string, val: Any) => {\n if (val === null || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`${op}() takes an object of properties`)\n }\n}\n\nexport const validateDocumentId = (op: string, id: string) => {\n if (typeof id !== 'string' || !/^[a-z0-9_][a-z0-9_.-]{0,127}$/i.test(id) || id.includes('..')) {\n throw new Error(`${op}(): \"${id}\" is not a valid document ID`)\n }\n}\n\nexport const requireDocumentId = (op: string, doc: Record<string, Any>) => {\n if (!doc._id) {\n throw new Error(`${op}() requires that the document contains an ID (\"_id\" property)`)\n }\n\n validateDocumentId(op, doc._id)\n}\n\nconst validateDocumentType = (op: string, type: string) => {\n if (typeof type !== 'string') {\n throw new Error(`\\`${op}()\\`: \\`${type}\\` is not a valid document type`)\n }\n}\n\nexport const requireDocumentType = (op: string, doc: Record<string, Any>) => {\n if (!doc._type) {\n throw new Error(`\\`${op}()\\` requires that the document contains a type (\\`_type\\` property)`)\n }\n\n validateDocumentType(op, doc._type)\n}\n\nexport const validateVersionIdMatch = (builtVersionId: string, document: SanityDocumentStub) => {\n if (document._id && document._id !== builtVersionId) {\n throw new Error(\n `The provided document ID (\\`${document._id}\\`) does not match the generated version ID (\\`${builtVersionId}\\`)`,\n )\n }\n}\n\nexport const validateInsert = (at: string, selector: string, items: Any[]) => {\n const signature = 'insert(at, selector, items)'\n if (VALID_INSERT_LOCATIONS.indexOf(at) === -1) {\n const valid = VALID_INSERT_LOCATIONS.map((loc) => `\"${loc}\"`).join(', ')\n throw new Error(`${signature} takes an \"at\"-argument which is one of: ${valid}`)\n }\n\n if (typeof selector !== 'string') {\n throw new Error(`${signature} takes a \"selector\"-argument which must be a string`)\n }\n\n if (!Array.isArray(items)) {\n throw new Error(`${signature} takes an \"items\"-argument which must be an array`)\n }\n}\n\nexport const hasDataset = (config: InitializedClientConfig): string => {\n // Check if dataset is directly on the config\n if (config.dataset) {\n return config.dataset\n }\n\n // Check if dataset is in resource configuration\n // Note: ~experimental_resource is normalized to resource during client initialization\n const resource = config.resource\n if (resource && resource.type === 'dataset') {\n const segments = resource.id.split('.')\n if (segments.length !== 2) {\n throw new Error('Dataset resource ID must be in the format \"project.dataset\"')\n }\n return segments[1]\n }\n\n throw new Error('`dataset` must be provided to perform queries')\n}\n\nexport const requestTag = (tag: string) => {\n if (typeof tag !== 'string' || !/^[a-z0-9._-]{1,75}$/i.test(tag)) {\n throw new Error(\n `Tag can only contain alphanumeric characters, underscores, dashes and dots, and be between one and 75 characters long.`,\n )\n }\n\n return tag\n}\n\nexport const resourceConfig = (config: InitializedClientConfig): void => {\n // Note: ~experimental_resource is normalized to resource during client initialization\n const resource = config.resource\n if (!resource) {\n throw new Error('`resource` must be provided to perform resource queries')\n }\n const {type, id} = resource\n\n switch (type) {\n case 'dataset': {\n const segments = id.split('.')\n if (segments.length !== 2) {\n throw new Error('Dataset resource ID must be in the format \"project.dataset\"')\n }\n return\n }\n case 'dashboard':\n case 'media-library':\n case 'canvas': {\n return\n }\n default:\n // @ts-expect-error - handle all supported resource types\n throw new Error(`Unsupported resource type: ${type.toString()}`)\n }\n}\n\nexport const resourceGuard = (service: string, config: InitializedClientConfig): void => {\n // Note: ~experimental_resource is normalized to resource during client initialization\n const resource = config.resource\n if (resource) {\n throw new Error(`\\`${service}\\` does not support resource-based operations`)\n }\n}\n","import type {Any} from '../types'\n\nexport function once(fn: Any) {\n let didCall = false\n let returnValue: Any\n return (...args: Any[]) => {\n if (didCall) {\n return returnValue\n }\n returnValue = fn(...args)\n didCall = true\n return returnValue\n }\n}\n","import {generateHelpUrl} from './generateHelpUrl'\nimport {type Any} from './types'\nimport {once} from './util/once'\n\nconst createWarningPrinter = (message: string[]) =>\n // oxlint-disable-next-line no-console\n once((...args: Any[]) => console.warn(message.join(' '), ...args))\n\nexport const printCdnAndWithCredentialsWarning = createWarningPrinter([\n `Because you set \\`withCredentials\\` to true, we will override your \\`useCdn\\``,\n `setting to be false since (cookie-based) credentials are never set on the CDN`,\n])\n\nexport const printCdnWarning = createWarningPrinter([\n `Since you haven't set a value for \\`useCdn\\`, we will deliver content using our`,\n `global, edge-cached API-CDN. If you wish to have content delivered faster, set`,\n `\\`useCdn: false\\` to use the Live API. Note: You may incur higher costs using the live API.`,\n])\n\nexport const printCdnPreviewDraftsWarning = createWarningPrinter([\n `The Sanity client is configured with the \\`perspective\\` set to \\`drafts\\` or \\`previewDrafts\\`, which doesn't support the API-CDN.`,\n `The Live API will be used instead. Set \\`useCdn: false\\` in your configuration to hide this warning.`,\n])\n\nexport const printPreviewDraftsDeprecationWarning = createWarningPrinter([\n `The \\`previewDrafts\\` perspective has been renamed to \\`drafts\\` and will be removed in a future API version`,\n])\n\nexport const printBrowserTokenWarning = createWarningPrinter([\n 'You have configured Sanity client to use a token in the browser. This may cause unintentional security issues.',\n `See ${generateHelpUrl(\n 'js-client-browser-token',\n )} for more information and how to hide this warning.`,\n])\n\nexport const printCredentialedTokenWarning = createWarningPrinter([\n 'You have configured Sanity client to use a token, but also provided `withCredentials: true`.',\n 'This is no longer supported - only token will be used - remove `withCredentials: true`.',\n])\n\nexport const printNoApiVersionSpecifiedWarning = createWarningPrinter([\n 'Using the Sanity client without specifying an API version is deprecated.',\n `See ${generateHelpUrl('js-client-api-version')}`,\n])\n\nexport const printNoDefaultExport = createWarningPrinter([\n 'The default export of @sanity/client has been deprecated. Use the named export `createClient` instead.',\n])\n\n// Phrased as a condition rather than as a correction, because the client cannot\n// tell the two cases apart. `baseId` creates a version of a document that\n// already exists, so a caller creating a genuinely new document inside a release\n// has no alternative to `document` - and the previous wording told them they had\n// picked the wrong approach when they had not.\nexport const printCreateVersionWithBaseIdWarning = createWarningPrinter([\n 'You have called `createVersion()` with a defined `document`.',\n 'If you are creating a version of a document that already exists, prefer providing `baseId` and `releaseId` instead.',\n])\n\nexport const printDeprecatedUriOptionWarning = createWarningPrinter([\n 'The `uri` request option has been renamed to `url`.',\n 'Please update your code to use `url` instead. Support for `uri` will be removed in a future version.',\n])\n\nexport const printDeprecatedResourceConfigWarning = createWarningPrinter([\n 'The `~experimental_resource` configuration property has been renamed to `resource`.',\n 'Please update your client configuration to use `resource` instead. Support for `~experimental_resource` will be removed in a future version.',\n])\n","import {generateHelpUrl} from './generateHelpUrl'\nimport type {ClientConfig, ClientPerspective, InitializedClientConfig} from './types'\nimport * as validate from './validators'\nimport * as warnings from './warnings'\n\nconst defaultCdnHost = 'apicdn.sanity.io'\nexport const defaultConfig = {\n apiHost: 'https://api.sanity.io',\n apiVersion: '1',\n useProjectHostname: true,\n stega: {enabled: false},\n} satisfies ClientConfig\n\nconst LOCALHOSTS = ['localhost', '127.0.0.1', '0.0.0.0']\nconst isLocal = (host: string) => LOCALHOSTS.indexOf(host) !== -1\n\nfunction validateApiVersion(apiVersion: string) {\n if (apiVersion === '1' || apiVersion === 'X') {\n return\n }\n\n const apiDate = new Date(apiVersion)\n const apiVersionValid =\n /^\\d{4}-\\d{2}-\\d{2}$/.test(apiVersion) && apiDate instanceof Date && apiDate.getTime() > 0\n\n if (!apiVersionValid) {\n throw new Error('Invalid API version string, expected `1` or date in format `YYYY-MM-DD`')\n }\n}\n\n/**\n * @internal - it may have breaking changes in any release\n */\nexport function validateApiPerspective(\n perspective: unknown,\n): asserts perspective is ClientPerspective {\n if (Array.isArray(perspective) && perspective.length > 1 && perspective.includes('raw')) {\n throw new TypeError(\n `Invalid API perspective value: \"raw\". The raw-perspective can not be combined with other perspectives`,\n )\n }\n}\n\nexport const initConfig = (\n config: Partial<ClientConfig>,\n prevConfig: Partial<ClientConfig>,\n): InitializedClientConfig => {\n const specifiedConfig = {\n ...prevConfig,\n ...config,\n stega: {\n ...(typeof prevConfig.stega === 'boolean'\n ? {enabled: prevConfig.stega}\n : prevConfig.stega || defaultConfig.stega),\n ...(typeof config.stega === 'boolean' ? {enabled: config.stega} : config.stega || {}),\n },\n }\n if (!specifiedConfig.apiVersion) {\n warnings.printNoApiVersionSpecifiedWarning()\n }\n\n const newConfig = {\n ...defaultConfig,\n ...specifiedConfig,\n } as InitializedClientConfig\n\n // Normalize resource configuration - prefer `resource` over deprecated `~experimental_resource`\n if (newConfig['~experimental_resource'] && !newConfig.resource) {\n warnings.printDeprecatedResourceConfigWarning()\n newConfig.resource = newConfig['~experimental_resource']\n }\n\n const resourceConfig = newConfig.resource\n const projectBased = newConfig.useProjectHostname && !resourceConfig\n\n if (typeof Promise === 'undefined') {\n const helpUrl = generateHelpUrl('js-client-promise-polyfill')\n throw new Error(`No native Promise-implementation found, polyfill needed - see ${helpUrl}`)\n }\n\n if (projectBased && !newConfig.projectId) {\n throw new Error('Configuration must contain `projectId`')\n }\n\n if (resourceConfig) {\n validate.resourceConfig(newConfig)\n }\n\n if (typeof newConfig.perspective !== 'undefined') {\n validateApiPerspective(newConfig.perspective)\n }\n\n if ('encodeSourceMap' in newConfig) {\n throw new Error(\n `It looks like you're using options meant for '@sanity/preview-kit/client'. 'encodeSourceMap' is not supported in '@sanity/client'. Did you mean 'stega.enabled'?`,\n )\n }\n if ('encodeSourceMapAtPath' in newConfig) {\n throw new Error(\n `It looks like you're using options meant for '@sanity/preview-kit/client'. 'encodeSourceMapAtPath' is not supported in '@sanity/client'. Did you mean 'stega.filter'?`,\n )\n }\n if (typeof newConfig.stega.enabled !== 'boolean') {\n throw new Error(`stega.enabled must be a boolean, received ${newConfig.stega.enabled}`)\n }\n if (newConfig.stega.enabled && newConfig.stega.studioUrl === undefined) {\n throw new Error(`stega.studioUrl must be defined when stega.enabled is true`)\n }\n if (\n newConfig.stega.enabled &&\n typeof newConfig.stega.studioUrl !== 'string' &&\n typeof newConfig.stega.studioUrl !== 'function'\n ) {\n throw new Error(\n `stega.studioUrl must be a string or a function, received ${newConfig.stega.studioUrl}`,\n )\n }\n\n const isBrowser = typeof window !== 'undefined' && window.location && window.location.hostname\n const isLocalhost = isBrowser && isLocal(window.location.hostname)\n\n const hasToken = Boolean(newConfig.token)\n if (newConfig.withCredentials && hasToken) {\n warnings.printCredentialedTokenWarning()\n newConfig.withCredentials = false\n }\n\n if (isBrowser && isLocalhost && hasToken && newConfig.ignoreBrowserTokenWarning !== true) {\n warnings.printBrowserTokenWarning()\n } else if (typeof newConfig.useCdn === 'undefined') {\n warnings.printCdnWarning()\n }\n\n if (projectBased) {\n validate.projectId(newConfig.projectId!)\n }\n\n if (newConfig.dataset) {\n validate.dataset(newConfig.dataset)\n }\n\n if ('requestTagPrefix' in newConfig) {\n // Allow setting and unsetting request tag prefix\n newConfig.requestTagPrefix = newConfig.requestTagPrefix\n ? validate.requestTag(newConfig.requestTagPrefix).replace(/\\.+$/, '')\n : undefined\n }\n\n newConfig.apiVersion = `${newConfig.apiVersion}`.replace(/^v/, '')\n newConfig.isDefaultApi = newConfig.apiHost === defaultConfig.apiHost\n\n if (newConfig.useCdn === true && newConfig.withCredentials) {\n warnings.printCdnAndWithCredentialsWarning()\n }\n\n // If `useCdn` is undefined, we treat it as `true`\n newConfig.useCdn = newConfig.useCdn !== false && !newConfig.withCredentials\n\n validateApiVersion(newConfig.apiVersion)\n\n const hostParts = newConfig.apiHost.split('://', 2)\n const protocol = hostParts[0]\n const host = hostParts[1]\n const cdnHost = newConfig.isDefaultApi ? defaultCdnHost : host\n\n if (projectBased) {\n newConfig.url = `${protocol}://${newConfig.projectId}.${host}/v${newConfig.apiVersion}`\n newConfig.cdnUrl = `${protocol}://${newConfig.projectId}.${cdnHost}/v${newConfig.apiVersion}`\n } else {\n newConfig.url = `${newConfig.apiHost}/v${newConfig.apiVersion}`\n newConfig.cdnUrl = newConfig.url\n }\n\n return newConfig\n}\n"],"mappings":"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"}