@sanity/client 0.0.0-dev.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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1225 -0
  3. package/dist/index.browser.cjs +1760 -0
  4. package/dist/index.browser.cjs.map +1 -0
  5. package/dist/index.browser.js +1737 -0
  6. package/dist/index.browser.js.map +1 -0
  7. package/dist/index.cjs +1769 -0
  8. package/dist/index.cjs.js +16 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.ts +2234 -0
  11. package/dist/index.js +1746 -0
  12. package/dist/index.js.map +1 -0
  13. package/package.json +127 -0
  14. package/src/SanityClient.ts +1253 -0
  15. package/src/assets/AssetsClient.ts +191 -0
  16. package/src/config.ts +96 -0
  17. package/src/data/dataMethods.ts +416 -0
  18. package/src/data/encodeQueryString.ts +29 -0
  19. package/src/data/listen.ts +196 -0
  20. package/src/data/patch.ts +345 -0
  21. package/src/data/transaction.ts +358 -0
  22. package/src/datasets/DatasetsClient.ts +115 -0
  23. package/src/generateHelpUrl.ts +5 -0
  24. package/src/http/browserMiddleware.ts +1 -0
  25. package/src/http/errors.ts +68 -0
  26. package/src/http/nodeMiddleware.ts +11 -0
  27. package/src/http/request.ts +48 -0
  28. package/src/http/requestOptions.ts +33 -0
  29. package/src/index.browser.ts +28 -0
  30. package/src/index.ts +28 -0
  31. package/src/projects/ProjectsClient.ts +61 -0
  32. package/src/types.ts +575 -0
  33. package/src/users/UsersClient.ts +55 -0
  34. package/src/util/defaults.ts +10 -0
  35. package/src/util/getSelection.ts +21 -0
  36. package/src/util/once.ts +14 -0
  37. package/src/util/pick.ts +11 -0
  38. package/src/validators.ts +78 -0
  39. package/src/warnings.ts +30 -0
  40. package/umd/.gitkeep +1 -0
  41. package/umd/sanityClient.js +4840 -0
  42. package/umd/sanityClient.min.js +14 -0
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ import envMiddleware from './http/nodeMiddleware'
2
+ import {defineHttpRequest} from './http/request'
3
+ import {SanityClient} from './SanityClient'
4
+ import type {ClientConfig} from './types'
5
+ import {printNoDefaultExport} from './warnings'
6
+
7
+ export * from './data/patch'
8
+ export * from './data/transaction'
9
+ export {ClientError, ServerError} from './http/errors'
10
+ export * from './SanityClient'
11
+ export * from './types'
12
+
13
+ // Set the http client to use for requests, and its environment specific middleware
14
+ const httpRequest = defineHttpRequest(envMiddleware)
15
+ /** @public */
16
+ export const requester = httpRequest.defaultRequester
17
+
18
+ /** @public */
19
+ export const createClient = (config: ClientConfig) => new SanityClient(httpRequest, config)
20
+
21
+ /**
22
+ * @public
23
+ * @deprecated Use the named export `createClient` instead of the `default` export
24
+ */
25
+ export default function deprecatedCreateClient(config: ClientConfig) {
26
+ printNoDefaultExport()
27
+ return new SanityClient(httpRequest, config)
28
+ }
@@ -0,0 +1,61 @@
1
+ import {lastValueFrom, type Observable} from 'rxjs'
2
+
3
+ import {_request} from '../data/dataMethods'
4
+ import type {ObservableSanityClient, SanityClient} from '../SanityClient'
5
+ import type {HttpRequest, SanityProject} from '../types'
6
+
7
+ /** @internal */
8
+ export class ObservableProjectsClient {
9
+ #client: ObservableSanityClient
10
+ #httpRequest: HttpRequest
11
+ constructor(client: ObservableSanityClient, httpRequest: HttpRequest) {
12
+ this.#client = client
13
+ this.#httpRequest = httpRequest
14
+ }
15
+
16
+ /**
17
+ * Fetch a list of projects the authenticated user has access to
18
+ */
19
+ list(): Observable<SanityProject[]> {
20
+ return _request<SanityProject[]>(this.#client, this.#httpRequest, {uri: '/projects'})
21
+ }
22
+
23
+ /**
24
+ * Fetch a project by project ID
25
+ *
26
+ * @param projectId - ID of the project to fetch
27
+ */
28
+ getById(projectId: string): Observable<SanityProject> {
29
+ return _request<SanityProject>(this.#client, this.#httpRequest, {uri: `/projects/${projectId}`})
30
+ }
31
+ }
32
+
33
+ /** @internal */
34
+ export class ProjectsClient {
35
+ #client: SanityClient
36
+ #httpRequest: HttpRequest
37
+ constructor(client: SanityClient, httpRequest: HttpRequest) {
38
+ this.#client = client
39
+ this.#httpRequest = httpRequest
40
+ }
41
+
42
+ /**
43
+ * Fetch a list of projects the authenticated user has access to
44
+ */
45
+ list(): Promise<SanityProject[]> {
46
+ return lastValueFrom(
47
+ _request<SanityProject[]>(this.#client, this.#httpRequest, {uri: '/projects'})
48
+ )
49
+ }
50
+
51
+ /**
52
+ * Fetch a project by project ID
53
+ *
54
+ * @param projectId - ID of the project to fetch
55
+ */
56
+ getById(projectId: string): Promise<SanityProject> {
57
+ return lastValueFrom(
58
+ _request<SanityProject>(this.#client, this.#httpRequest, {uri: `/projects/${projectId}`})
59
+ )
60
+ }
61
+ }
package/src/types.ts ADDED
@@ -0,0 +1,575 @@
1
+ import type {Requester} from 'get-it'
2
+
3
+ /**
4
+ * Used to tag types that is set to `any` as a temporary measure, but should be replaced with proper typings in the future
5
+ * @internal
6
+ */
7
+ export type Any = any // eslint-disable-line @typescript-eslint/no-explicit-any
8
+
9
+ /** @public */
10
+ export interface RequestOptions {
11
+ timeout?: number
12
+ token?: string
13
+ tag?: string
14
+ headers?: Record<string, string>
15
+ method?: string
16
+ query?: Any
17
+ body?: Any
18
+ signal?: AbortSignal
19
+ }
20
+
21
+ /** @public */
22
+ export interface ClientConfig {
23
+ projectId?: string
24
+ dataset?: string
25
+ useCdn?: boolean
26
+ token?: string
27
+ apiHost?: string
28
+ apiVersion?: string
29
+ proxy?: string
30
+ requestTagPrefix?: string
31
+ ignoreBrowserTokenWarning?: boolean
32
+ withCredentials?: boolean
33
+ allowReconfigure?: boolean
34
+ timeout?: number
35
+
36
+ /**
37
+ * @deprecated Don't use
38
+ */
39
+ useProjectHostname?: boolean
40
+
41
+ /**
42
+ * @deprecated Don't use
43
+ */
44
+ requester?: Requester
45
+
46
+ /**
47
+ * Experimental, requires apiVersion: 'X' and will overlay drafts on top of published documents
48
+ * which lets you preview your query on what it'll look like after every document is published.
49
+ * @alpha
50
+ */
51
+ unstable_overlayDrafts?: boolean
52
+ }
53
+
54
+ /** @public */
55
+ export interface InitializedClientConfig extends ClientConfig {
56
+ // These are required in the initialized config
57
+ apiHost: string
58
+ apiVersion: string
59
+ useProjectHostname: boolean
60
+ useCdn: boolean
61
+ // These are added by the initConfig function
62
+ /**
63
+ * @deprecated Internal, don't use
64
+ */
65
+ isDefaultApi: boolean
66
+ /**
67
+ * @deprecated Internal, don't use
68
+ */
69
+ url: string
70
+ /**
71
+ * @deprecated Internal, don't use
72
+ */
73
+ cdnUrl: string
74
+ }
75
+
76
+ /** @public */
77
+ export type AssetMetadataType =
78
+ | 'location'
79
+ | 'exif'
80
+ | 'image'
81
+ | 'palette'
82
+ | 'lqip'
83
+ | 'blurhash'
84
+ | 'none'
85
+
86
+ /** @public */
87
+ export interface UploadClientConfig {
88
+ /**
89
+ * Optional request tag for the upload
90
+ */
91
+ tag?: string
92
+
93
+ /**
94
+ * Whether or not to preserve the original filename (default: true)
95
+ */
96
+ preserveFilename?: boolean
97
+
98
+ /**
99
+ * Filename for this file (optional)
100
+ */
101
+ filename?: string
102
+
103
+ /**
104
+ * Milliseconds to wait before timing the request out
105
+ */
106
+ timeout?: number
107
+
108
+ /**
109
+ * Mime type of the file
110
+ */
111
+ contentType?: string
112
+
113
+ /**
114
+ * Array of metadata parts to extract from asset
115
+ */
116
+ extract?: AssetMetadataType[]
117
+
118
+ /**
119
+ * Optional freeform label for the asset. Generally not used.
120
+ */
121
+ label?: string
122
+
123
+ /**
124
+ * Optional title for the asset
125
+ */
126
+ title?: string
127
+
128
+ /**
129
+ * Optional description for the asset
130
+ */
131
+ description?: string
132
+
133
+ /**
134
+ * The credit to person(s) and/or organization(s) required by the supplier of the asset to be used when published
135
+ */
136
+ creditLine?: string
137
+
138
+ /**
139
+ * Source data (when the asset is from an external service)
140
+ */
141
+ source?: {
142
+ /**
143
+ * The (u)id of the asset within the source, i.e. 'i-f323r1E'
144
+ */
145
+ id: string
146
+
147
+ /**
148
+ * The name of the source, i.e. 'unsplash'
149
+ */
150
+ name: string
151
+
152
+ /**
153
+ * A url to where to find the asset, or get more info about it in the source
154
+ */
155
+ url?: string
156
+ }
157
+ }
158
+
159
+ /** @internal */
160
+ export interface SanityReference {
161
+ _ref: string
162
+ }
163
+
164
+ /** @internal */
165
+ export type SanityDocument<T extends Record<string, Any> = Record<string, Any>> = {
166
+ [P in keyof T]: T[P]
167
+ } & {
168
+ _id: string
169
+ _rev: string
170
+ _type: string
171
+ _createdAt: string
172
+ _updatedAt: string
173
+ }
174
+
175
+ /** @internal */
176
+ export interface SanityAssetDocument extends SanityDocument {
177
+ url: string
178
+ path: string
179
+ size: number
180
+ assetId: string
181
+ mimeType: string
182
+ sha1hash: string
183
+ extension: string
184
+ uploadId?: string
185
+ originalFilename?: string
186
+ }
187
+
188
+ /** @internal */
189
+ export interface SanityImagePalette {
190
+ background: string
191
+ foreground: string
192
+ population: number
193
+ title: string
194
+ }
195
+
196
+ /** @internal */
197
+ export interface SanityImageAssetDocument extends SanityAssetDocument {
198
+ metadata: {
199
+ _type: 'sanity.imageMetadata'
200
+ hasAlpha: boolean
201
+ isOpaque: boolean
202
+ lqip?: string
203
+ blurHash?: string
204
+ dimensions: {
205
+ _type: 'sanity.imageDimensions'
206
+ aspectRatio: number
207
+ height: number
208
+ width: number
209
+ }
210
+ palette?: {
211
+ _type: 'sanity.imagePalette'
212
+ darkMuted?: SanityImagePalette
213
+ darkVibrant?: SanityImagePalette
214
+ dominant?: SanityImagePalette
215
+ lightMuted?: SanityImagePalette
216
+ lightVibrant?: SanityImagePalette
217
+ muted?: SanityImagePalette
218
+ vibrant?: SanityImagePalette
219
+ }
220
+ image?: {
221
+ _type: 'sanity.imageExifTags'
222
+ [key: string]: Any
223
+ }
224
+ exif?: {
225
+ _type: 'sanity.imageExifMetadata'
226
+ [key: string]: Any
227
+ }
228
+ }
229
+ }
230
+
231
+ /** @public */
232
+ export interface ErrorProps {
233
+ message: string
234
+ response: Any
235
+ statusCode: number
236
+ responseBody: Any
237
+ details: Any
238
+ }
239
+
240
+ /** @public */
241
+ export type HttpRequest = {
242
+ defaultRequester: Requester
243
+ (options: RequestOptions, requester: Requester): ReturnType<Requester>
244
+ }
245
+
246
+ /** @internal */
247
+ export interface RequestObservableOptions extends Omit<RequestOptions, 'url'> {
248
+ url?: string
249
+ uri?: string
250
+ canUseCdn?: boolean
251
+ tag?: string
252
+ }
253
+
254
+ /** @public */
255
+ export interface ProgressEvent {
256
+ type: 'progress'
257
+ stage: 'upload' | 'download'
258
+ percent: number
259
+ total?: number
260
+ loaded?: number
261
+ lengthComputable: boolean
262
+ }
263
+
264
+ /** @public */
265
+ export interface ResponseEvent<T = unknown> {
266
+ type: 'response'
267
+ body: T
268
+ url: string
269
+ method: string
270
+ statusCode: number
271
+ statusMessage?: string
272
+ headers: Record<string, string>
273
+ }
274
+
275
+ /** @public */
276
+ export type HttpRequestEvent<T = unknown> = ResponseEvent<T> | ProgressEvent
277
+
278
+ /** @internal */
279
+ export interface AuthProvider {
280
+ name: string
281
+ title: string
282
+ url: string
283
+ }
284
+
285
+ /** @internal */
286
+ export type AuthProviderResponse = {providers: AuthProvider[]}
287
+
288
+ /** @internal */
289
+ export type DatasetAclMode = 'public' | 'private' | 'custom'
290
+
291
+ /** @internal */
292
+ export type DatasetResponse = {datasetName: string; aclMode: DatasetAclMode}
293
+ /** @internal */
294
+ export type DatasetsResponse = {name: string; aclMode: DatasetAclMode}[]
295
+
296
+ /** @internal */
297
+ export interface SanityProjectMember {
298
+ id: string
299
+ role: string
300
+ isRobot: boolean
301
+ isCurrentUser: boolean
302
+ }
303
+
304
+ /** @internal */
305
+ export interface SanityProject {
306
+ id: string
307
+ displayName: string
308
+ studioHost: string | null
309
+ organizationId: string | null
310
+ isBlocked: boolean
311
+ isDisabled: boolean
312
+ isDisabledByUser: boolean
313
+ createdAt: string
314
+ pendingInvites?: number
315
+ maxRetentionDays?: number
316
+ members: SanityProjectMember[]
317
+ metadata: {
318
+ color?: string
319
+ externalStudioHost?: string
320
+ }
321
+ }
322
+
323
+ /** @internal */
324
+ export interface SanityUser {
325
+ id: string
326
+ projectId: string
327
+ displayName: string
328
+ familyName: string | null
329
+ givenName: string | null
330
+ middleName: string | null
331
+ imageUrl: string | null
332
+ createdAt: string
333
+ updatedAt: string
334
+ isCurrentUser: boolean
335
+ }
336
+
337
+ /** @internal */
338
+ export interface CurrentSanityUser {
339
+ id: string
340
+ name: string
341
+ email: string
342
+ profileImage: string | null
343
+ role: string
344
+ }
345
+
346
+ /** @public */
347
+ export type SanityDocumentStub<T extends Record<string, Any> = Record<string, Any>> = {
348
+ [P in keyof T]: T[P]
349
+ } & {
350
+ _type: string
351
+ }
352
+
353
+ /** @public */
354
+ export type IdentifiedSanityDocumentStub<T extends Record<string, Any> = Record<string, Any>> = {
355
+ [P in keyof T]: T[P]
356
+ } & {
357
+ _id: string
358
+ } & SanityDocumentStub
359
+
360
+ /** @internal */
361
+ export type InsertPatch =
362
+ | {before: string; items: Any[]}
363
+ | {after: string; items: Any[]}
364
+ | {replace: string; items: Any[]}
365
+
366
+ // Note: this is actually incorrect/invalid, but implemented as-is for backwards compatibility
367
+ /** @internal */
368
+ export interface PatchOperations {
369
+ set?: {[key: string]: Any}
370
+ setIfMissing?: {[key: string]: Any}
371
+ diffMatchPatch?: {[key: string]: Any}
372
+ unset?: string[]
373
+ inc?: {[key: string]: number}
374
+ dec?: {[key: string]: number}
375
+ insert?: InsertPatch
376
+ ifRevisionID?: string
377
+ }
378
+
379
+ /** @public */
380
+ export type QueryParams = {[key: string]: Any}
381
+ /** @internal */
382
+ export type MutationSelection = {query: string; params?: QueryParams} | {id: string | string[]}
383
+ /** @internal */
384
+ export type PatchSelection = string | string[] | MutationSelection
385
+ /** @internal */
386
+ export type PatchMutationOperation = PatchOperations & MutationSelection
387
+
388
+ /** @public */
389
+ export type Mutation<R extends Record<string, Any> = Record<string, Any>> =
390
+ | {create: SanityDocumentStub<R>}
391
+ | {createOrReplace: IdentifiedSanityDocumentStub<R>}
392
+ | {createIfNotExists: IdentifiedSanityDocumentStub<R>}
393
+ | {delete: MutationSelection}
394
+ | {patch: PatchMutationOperation}
395
+
396
+ /** @public */
397
+ export type MutationEvent<R extends Record<string, Any> = Record<string, Any>> = {
398
+ type: 'mutation'
399
+ documentId: string
400
+ eventId: string
401
+ identity: string
402
+ mutations: Mutation[]
403
+ previousRev?: string
404
+ resultRev?: string
405
+ result?: SanityDocument<R>
406
+ previous?: SanityDocument<R> | null
407
+ effects?: {apply: unknown[]; revert: unknown[]}
408
+ timestamp: string
409
+ transactionId: string
410
+ transition: 'update' | 'appear' | 'disappear'
411
+ visibility: 'query' | 'transaction'
412
+ }
413
+
414
+ /** @public */
415
+ export type ChannelErrorEvent = {
416
+ type: 'channelError'
417
+ message: string
418
+ }
419
+
420
+ /** @public */
421
+ export type DisconnectEvent = {
422
+ type: 'disconnect'
423
+ reason: string
424
+ }
425
+
426
+ /** @public */
427
+ export type ReconnectEvent = {
428
+ type: 'reconnect'
429
+ }
430
+
431
+ /** @public */
432
+ export type WelcomeEvent = {
433
+ type: 'welcome'
434
+ }
435
+
436
+ /** @public */
437
+ export type ListenEvent<R extends Record<string, Any>> =
438
+ | MutationEvent<R>
439
+ | ChannelErrorEvent
440
+ | DisconnectEvent
441
+ | ReconnectEvent
442
+ | WelcomeEvent
443
+
444
+ /** @public */
445
+ export type ListenEventName = 'mutation' | 'welcome' | 'reconnect'
446
+
447
+ /** @public */
448
+ export interface ListenOptions {
449
+ includeResult?: boolean
450
+ includePreviousRevision?: boolean
451
+ visibility?: 'sync' | 'async' | 'query'
452
+ events?: ListenEventName[]
453
+ effectFormat?: 'mendoza'
454
+ tag?: string
455
+ }
456
+
457
+ /** @internal */
458
+ export type FilteredResponseQueryOptions = RequestOptions & {
459
+ filterResponse?: true
460
+ }
461
+
462
+ /** @internal */
463
+ export type UnfilteredResponseQueryOptions = RequestOptions & {
464
+ filterResponse: false
465
+ }
466
+
467
+ /** @internal */
468
+ export interface RawQueryResponse<R> {
469
+ q: string
470
+ ms: number
471
+ result: R
472
+ }
473
+
474
+ /** @internal */
475
+ export type BaseMutationOptions = RequestOptions & {
476
+ visibility?: 'sync' | 'async' | 'deferred'
477
+ returnDocuments?: boolean
478
+ returnFirst?: boolean
479
+ dryRun?: boolean
480
+ autoGenerateArrayKeys?: boolean
481
+ skipCrossDatasetReferenceValidation?: boolean
482
+ }
483
+
484
+ /** @internal */
485
+ export type FirstDocumentMutationOptions = BaseMutationOptions & {
486
+ returnFirst?: true
487
+ returnDocuments?: true
488
+ }
489
+
490
+ /** @internal */
491
+ export type FirstDocumentIdMutationOptions = BaseMutationOptions & {
492
+ returnFirst?: true
493
+ returnDocuments: false
494
+ }
495
+
496
+ /** @internal */
497
+ export type AllDocumentsMutationOptions = BaseMutationOptions & {
498
+ returnFirst: false
499
+ returnDocuments?: true
500
+ }
501
+
502
+ /** @internal */
503
+ export type MutationOperation = 'create' | 'delete' | 'update' | 'none'
504
+
505
+ /** @internal */
506
+ export interface SingleMutationResult {
507
+ transactionId: string
508
+ documentId: string
509
+ results: {id: string; operation: MutationOperation}[]
510
+ }
511
+
512
+ /** @internal */
513
+ export interface MultipleMutationResult {
514
+ transactionId: string
515
+ documentIds: string[]
516
+ results: {id: string; operation: MutationOperation}[]
517
+ }
518
+
519
+ /** @internal */
520
+ export type AllDocumentIdsMutationOptions = BaseMutationOptions & {
521
+ returnFirst: false
522
+ returnDocuments: false
523
+ }
524
+
525
+ /** @internal */
526
+ export type AttributeSet = {[key: string]: Any}
527
+
528
+ /** @internal */
529
+ export type TransactionFirstDocumentMutationOptions = BaseMutationOptions & {
530
+ returnFirst: true
531
+ returnDocuments: true
532
+ }
533
+
534
+ /** @internal */
535
+ export type TransactionFirstDocumentIdMutationOptions = BaseMutationOptions & {
536
+ returnFirst: true
537
+ returnDocuments?: false
538
+ }
539
+
540
+ /** @internal */
541
+ export type TransactionAllDocumentsMutationOptions = BaseMutationOptions & {
542
+ returnFirst?: false
543
+ returnDocuments: true
544
+ }
545
+
546
+ /** @internal */
547
+ export type TransactionAllDocumentIdsMutationOptions = BaseMutationOptions & {
548
+ returnFirst?: false
549
+ returnDocuments?: false
550
+ }
551
+
552
+ /** @internal */
553
+ export type TransactionMutationOptions =
554
+ | TransactionFirstDocumentMutationOptions
555
+ | TransactionFirstDocumentIdMutationOptions
556
+ | TransactionAllDocumentsMutationOptions
557
+ | TransactionAllDocumentIdsMutationOptions
558
+
559
+ /** @internal */
560
+ export interface RawRequestOptions {
561
+ url?: string
562
+ uri?: string
563
+ method?: string
564
+ token?: string
565
+ json?: boolean
566
+ tag?: string
567
+ useGlobalApi?: boolean
568
+ withCredentials?: boolean
569
+ query?: {[key: string]: string | string[]}
570
+ headers?: {[key: string]: string}
571
+ timeout?: number
572
+ proxy?: string
573
+ body?: Any
574
+ maxRedirects?: number
575
+ }
@@ -0,0 +1,55 @@
1
+ import {lastValueFrom, type Observable} from 'rxjs'
2
+
3
+ import {_request} from '../data/dataMethods'
4
+ import type {ObservableSanityClient, SanityClient} from '../SanityClient'
5
+ import type {CurrentSanityUser, HttpRequest, SanityUser} from '../types'
6
+
7
+ /** @public */
8
+ export class ObservableUsersClient {
9
+ #client: ObservableSanityClient
10
+ #httpRequest: HttpRequest
11
+ constructor(client: ObservableSanityClient, httpRequest: HttpRequest) {
12
+ this.#client = client
13
+ this.#httpRequest = httpRequest
14
+ }
15
+
16
+ /**
17
+ * Fetch a user by user ID
18
+ *
19
+ * @param id - User ID of the user to fetch. If `me` is provided, a minimal response including the users role is returned.
20
+ */
21
+ getById<T extends 'me' | string>(
22
+ id: T
23
+ ): Observable<T extends 'me' ? CurrentSanityUser : SanityUser> {
24
+ return _request<T extends 'me' ? CurrentSanityUser : SanityUser>(
25
+ this.#client,
26
+ this.#httpRequest,
27
+ {uri: `/users/${id}`}
28
+ )
29
+ }
30
+ }
31
+
32
+ /** @public */
33
+ export class UsersClient {
34
+ #client: SanityClient
35
+ #httpRequest: HttpRequest
36
+ constructor(client: SanityClient, httpRequest: HttpRequest) {
37
+ this.#client = client
38
+ this.#httpRequest = httpRequest
39
+ }
40
+
41
+ /**
42
+ * Fetch a user by user ID
43
+ *
44
+ * @param id - User ID of the user to fetch. If `me` is provided, a minimal response including the users role is returned.
45
+ */
46
+ getById<T extends 'me' | string>(
47
+ id: T
48
+ ): Promise<T extends 'me' ? CurrentSanityUser : SanityUser> {
49
+ return lastValueFrom(
50
+ _request<T extends 'me' ? CurrentSanityUser : SanityUser>(this.#client, this.#httpRequest, {
51
+ uri: `/users/${id}`,
52
+ })
53
+ )
54
+ }
55
+ }