@sanity/client 7.1.0-views.0 → 7.1.0-views.1

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 (80) hide show
  1. package/README.md +668 -40
  2. package/dist/_chunks-cjs/config.cjs +14 -0
  3. package/dist/_chunks-cjs/config.cjs.map +1 -1
  4. package/dist/_chunks-cjs/dataMethods.cjs +197 -32
  5. package/dist/_chunks-cjs/dataMethods.cjs.map +1 -1
  6. package/dist/_chunks-cjs/isRecord.cjs +6 -0
  7. package/dist/_chunks-cjs/isRecord.cjs.map +1 -0
  8. package/dist/_chunks-cjs/resolveEditInfo.cjs +3 -5
  9. package/dist/_chunks-cjs/resolveEditInfo.cjs.map +1 -1
  10. package/dist/_chunks-cjs/stegaClean.cjs +4 -0
  11. package/dist/_chunks-cjs/stegaClean.cjs.map +1 -1
  12. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +2 -5
  13. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +1 -1
  14. package/dist/_chunks-es/config.js +15 -1
  15. package/dist/_chunks-es/config.js.map +1 -1
  16. package/dist/_chunks-es/dataMethods.js +200 -33
  17. package/dist/_chunks-es/dataMethods.js.map +1 -1
  18. package/dist/_chunks-es/isRecord.js +7 -0
  19. package/dist/_chunks-es/isRecord.js.map +1 -0
  20. package/dist/_chunks-es/resolveEditInfo.js +1 -3
  21. package/dist/_chunks-es/resolveEditInfo.js.map +1 -1
  22. package/dist/_chunks-es/stegaClean.js +4 -0
  23. package/dist/_chunks-es/stegaClean.js.map +1 -1
  24. package/dist/_chunks-es/stegaEncodeSourceMap.js +1 -4
  25. package/dist/_chunks-es/stegaEncodeSourceMap.js.map +1 -1
  26. package/dist/index.browser.cjs +1019 -59
  27. package/dist/index.browser.cjs.map +1 -1
  28. package/dist/index.browser.d.cts +1948 -149
  29. package/dist/index.browser.d.ts +1948 -149
  30. package/dist/index.browser.js +1021 -60
  31. package/dist/index.browser.js.map +1 -1
  32. package/dist/index.cjs +825 -29
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +1948 -149
  35. package/dist/index.d.ts +1948 -149
  36. package/dist/index.js +826 -31
  37. package/dist/index.js.map +1 -1
  38. package/dist/stega.browser.d.cts +1948 -149
  39. package/dist/stega.browser.d.ts +1948 -149
  40. package/dist/stega.d.cts +1948 -149
  41. package/dist/stega.d.ts +1948 -149
  42. package/dist/views.cjs +13 -5
  43. package/dist/views.cjs.map +1 -1
  44. package/dist/views.d.cts +51 -36
  45. package/dist/views.d.ts +51 -36
  46. package/dist/views.js +14 -5
  47. package/dist/views.js.map +1 -1
  48. package/package.json +2 -1
  49. package/src/SanityClient.ts +652 -12
  50. package/src/agent/actions/AgentActionsClient.ts +29 -2
  51. package/src/agent/actions/commonTypes.ts +57 -17
  52. package/src/agent/actions/generate.ts +36 -2
  53. package/src/agent/actions/patch.ts +136 -0
  54. package/src/agent/actions/prompt.ts +145 -0
  55. package/src/agent/actions/transform.ts +105 -7
  56. package/src/agent/actions/translate.ts +5 -2
  57. package/src/config.ts +3 -1
  58. package/src/csm/walkMap.ts +1 -1
  59. package/src/data/dataMethods.ts +170 -12
  60. package/src/data/encodeQueryString.ts +1 -1
  61. package/src/data/eventsource.ts +16 -7
  62. package/src/data/listen.ts +10 -4
  63. package/src/data/live.ts +13 -5
  64. package/src/datasets/DatasetsClient.ts +4 -1
  65. package/src/defineCreateClient.ts +7 -1
  66. package/src/http/errors.ts +92 -27
  67. package/src/http/request.ts +3 -3
  68. package/src/http/requestOptions.ts +4 -0
  69. package/src/projects/ProjectsClient.ts +6 -2
  70. package/src/releases/ReleasesClient.ts +693 -0
  71. package/src/releases/createRelease.ts +53 -0
  72. package/src/types.ts +291 -10
  73. package/src/users/UsersClient.ts +7 -3
  74. package/src/util/codeFrame.ts +174 -0
  75. package/src/util/createVersionId.ts +79 -0
  76. package/src/{csm → util}/isRecord.ts +1 -1
  77. package/src/validators.ts +23 -1
  78. package/src/views/index.ts +51 -15
  79. package/umd/sanityClient.js +1067 -61
  80. package/umd/sanityClient.min.js +2 -2
@@ -0,0 +1,53 @@
1
+ import type {BaseActionOptions, CreateReleaseAction, ReleaseDocument} from '@sanity/client'
2
+
3
+ import {generateReleaseId} from '../util/createVersionId'
4
+
5
+ interface ReleaseOrOptions extends BaseActionOptions {
6
+ releaseId?: string
7
+ metadata?: Partial<ReleaseDocument['metadata']>
8
+ }
9
+
10
+ interface CompleteCreateReleaseAction extends CreateReleaseAction {
11
+ metadata: ReleaseDocument['metadata']
12
+ }
13
+
14
+ const getArgs = (
15
+ releaseOrOptions?: ReleaseOrOptions,
16
+ maybeOptions?: BaseActionOptions,
17
+ ): [string, Partial<ReleaseDocument['metadata']>, BaseActionOptions | undefined] => {
18
+ const isReleaseInput =
19
+ typeof releaseOrOptions === 'object' &&
20
+ releaseOrOptions !== null &&
21
+ ('releaseId' in releaseOrOptions || 'metadata' in releaseOrOptions)
22
+
23
+ if (isReleaseInput) {
24
+ const {releaseId = generateReleaseId(), metadata = {}} = releaseOrOptions
25
+ return [releaseId, metadata, maybeOptions]
26
+ }
27
+
28
+ return [generateReleaseId(), {}, releaseOrOptions as BaseActionOptions]
29
+ }
30
+
31
+ /** @internal */
32
+ export const createRelease = (
33
+ releaseOrOptions?: ReleaseOrOptions,
34
+ maybeOptions?: BaseActionOptions,
35
+ ): {
36
+ action: CompleteCreateReleaseAction
37
+ options?: BaseActionOptions
38
+ } => {
39
+ const [releaseId, metadata, options] = getArgs(releaseOrOptions, maybeOptions)
40
+
41
+ const finalMetadata: ReleaseDocument['metadata'] = {
42
+ ...metadata,
43
+ releaseType: metadata.releaseType || 'undecided',
44
+ }
45
+
46
+ const createAction: CompleteCreateReleaseAction = {
47
+ actionType: 'sanity.action.release.create',
48
+ releaseId,
49
+ metadata: finalMetadata,
50
+ }
51
+
52
+ return {action: createAction, options}
53
+ }
package/src/types.ts CHANGED
@@ -73,6 +73,7 @@ type ClientConfigResource =
73
73
  | {
74
74
  type: 'view'
75
75
  id: string
76
+ useEmulate?: boolean
76
77
  }
77
78
 
78
79
  /** @public */
@@ -107,6 +108,14 @@ export interface ClientConfig {
107
108
  * Optional request tag prefix for all request tags
108
109
  */
109
110
  requestTagPrefix?: string
111
+
112
+ /**
113
+ * Optional default headers to include with all requests
114
+ *
115
+ * @remarks request-specific headers will override any default headers with the same name.
116
+ */
117
+ headers?: Record<string, string>
118
+
110
119
  ignoreBrowserTokenWarning?: boolean
111
120
  withCredentials?: boolean
112
121
  allowReconfigure?: boolean
@@ -178,6 +187,12 @@ export interface InitializedClientConfig extends ClientConfig {
178
187
  * The fully initialized stega config, can be used to check if stega is enabled
179
188
  */
180
189
  stega: InitializedStegaConfig
190
+ /**
191
+ * Default headers to include with all requests
192
+ *
193
+ * @remarks request-specific headers will override any default headers with the same name.
194
+ */
195
+ headers?: Record<string, string>
181
196
  }
182
197
 
183
198
  /** @public */
@@ -578,6 +593,24 @@ export type Mutation<R extends Record<string, Any> = Record<string, Any>> =
578
593
  | {delete: MutationSelection}
579
594
  | {patch: PatchMutationOperation}
580
595
 
596
+ /** @public */
597
+ export type ReleaseAction =
598
+ | CreateReleaseAction
599
+ | EditReleaseAction
600
+ | PublishReleaseAction
601
+ | ArchiveReleaseAction
602
+ | UnarchiveReleaseAction
603
+ | ScheduleReleaseAction
604
+ | UnscheduleReleaseAction
605
+ | DeleteReleaseAction
606
+
607
+ /** @public */
608
+ export type VersionAction =
609
+ | CreateVersionAction
610
+ | DiscardVersionAction
611
+ | ReplaceVersionAction
612
+ | UnpublishVersionAction
613
+
581
614
  /** @public */
582
615
  export type Action =
583
616
  | CreateAction
@@ -587,6 +620,136 @@ export type Action =
587
620
  | DiscardAction
588
621
  | PublishAction
589
622
  | UnpublishAction
623
+ | VersionAction
624
+ | ReleaseAction
625
+
626
+ /**
627
+ * Creates a new release under the given id, with metadata.
628
+ *
629
+ * @public
630
+ */
631
+ export interface CreateReleaseAction {
632
+ actionType: 'sanity.action.release.create'
633
+ releaseId: string
634
+ metadata?: Partial<ReleaseDocument['metadata']>
635
+ }
636
+
637
+ /**
638
+ * Edits an existing release, updating the metadata.
639
+ *
640
+ * @public
641
+ */
642
+ export interface EditReleaseAction {
643
+ actionType: 'sanity.action.release.edit'
644
+ releaseId: string
645
+ patch: PatchOperations
646
+ }
647
+
648
+ /**
649
+ * Publishes all documents in a release at once.
650
+ *
651
+ * @public
652
+ */
653
+ export interface PublishReleaseAction {
654
+ actionType: 'sanity.action.release.publish'
655
+ releaseId: string
656
+ }
657
+
658
+ /**
659
+ * Archives an `active` release, and deletes all the release documents.
660
+ *
661
+ * @public
662
+ */
663
+ export interface ArchiveReleaseAction {
664
+ actionType: 'sanity.action.release.archive'
665
+ releaseId: string
666
+ }
667
+
668
+ /**
669
+ * Unarchived an `archived` release, and restores all the release documents.
670
+ *
671
+ * @public
672
+ */
673
+ export interface UnarchiveReleaseAction {
674
+ actionType: 'sanity.action.release.unarchive'
675
+ releaseId: string
676
+ }
677
+
678
+ /**
679
+ * Queues release for publishing at the given future time.
680
+ *
681
+ * @public
682
+ */
683
+ export interface ScheduleReleaseAction {
684
+ actionType: 'sanity.action.release.schedule'
685
+ releaseId: string
686
+ publishAt: string
687
+ }
688
+
689
+ /**
690
+ * Unschedules a `scheduled` release, stopping it from being published.
691
+ *
692
+ * @public
693
+ */
694
+ export interface UnscheduleReleaseAction {
695
+ actionType: 'sanity.action.release.unschedule'
696
+ releaseId: string
697
+ }
698
+
699
+ /**
700
+ * Deletes a `archived` or `published` release, and all the release documents versions.
701
+ *
702
+ * @public
703
+ */
704
+ export interface DeleteReleaseAction {
705
+ actionType: 'sanity.action.release.delete'
706
+ releaseId: string
707
+ }
708
+
709
+ /**
710
+ * Creates a new version of an existing document, attached to the release as given
711
+ * by `document._id`
712
+ *
713
+ * @public
714
+ */
715
+ export interface CreateVersionAction {
716
+ actionType: 'sanity.action.document.version.create'
717
+ publishedId: string
718
+ document: IdentifiedSanityDocumentStub
719
+ }
720
+
721
+ /**
722
+ * Delete a version of a document.
723
+ *
724
+ * @public
725
+ */
726
+ export interface DiscardVersionAction {
727
+ actionType: 'sanity.action.document.version.discard'
728
+ versionId: string
729
+ purge?: boolean
730
+ }
731
+
732
+ /**
733
+ * Replace an existing version of a document.
734
+ *
735
+ * @public
736
+ */
737
+ export interface ReplaceVersionAction {
738
+ actionType: 'sanity.action.document.version.replace'
739
+ document: IdentifiedSanityDocumentStub
740
+ }
741
+
742
+ /**
743
+ * Identify that a version of a document should be unpublished when
744
+ * the release that version is contained within is published.
745
+ *
746
+ * @public
747
+ */
748
+ export interface UnpublishVersionAction {
749
+ actionType: 'sanity.action.document.version.unpublish'
750
+ versionId: string
751
+ publishedId: string
752
+ }
590
753
 
591
754
  /**
592
755
  * Creates a new draft document. The published version of the document must not already exist.
@@ -619,6 +782,7 @@ export type CreateAction = {
619
782
  * At least one of the draft or published versions of the document must exist.
620
783
  *
621
784
  * @public
785
+ * @deprecated Use {@link ReplaceVersionAction} instead
622
786
  */
623
787
  export type ReplaceDraftAction = {
624
788
  actionType: 'sanity.action.document.replaceDraft'
@@ -691,6 +855,7 @@ export type DeleteAction = {
691
855
  * It is an error if it does not exist. If the purge flag is set, the document history is also deleted.
692
856
  *
693
857
  * @public
858
+ * @deprecated Use {@link DiscardVersionAction} instead
694
859
  */
695
860
  export type DiscardAction = {
696
861
  actionType: 'sanity.action.document.discard'
@@ -1064,11 +1229,45 @@ export interface UnfilteredResponseWithoutQuery extends ResponseQueryOptions {
1064
1229
  returnQuery: false
1065
1230
  }
1066
1231
 
1232
+ /** @public */
1233
+ export enum ViewResourceType {
1234
+ Dataset = 'dataset',
1235
+ }
1236
+
1237
+ /** @public */
1238
+ export type ViewOverride = {
1239
+ id: string
1240
+ connections: ViewConnectionOverride[]
1241
+ }
1242
+
1243
+ /** @public */
1244
+ export type ViewConnectionOverride = {
1245
+ query: string
1246
+ resourceType: ViewResourceType
1247
+ resourceId: string
1248
+ }
1249
+
1250
+ /** @public */
1251
+ export interface EmulatedResponseQueryOptions extends ResponseQueryOptions {
1252
+ useEmulate: boolean
1253
+ connections?: ViewConnectionOverride[] | undefined
1254
+
1255
+ filterResponse?: false
1256
+ returnQuery?: false
1257
+ }
1258
+
1067
1259
  /** @public */
1068
1260
  export type QueryOptions =
1069
1261
  | FilteredResponseQueryOptions
1070
1262
  | UnfilteredResponseQueryOptions
1071
1263
  | UnfilteredResponseWithoutQuery
1264
+ | EmulatedResponseQueryOptions
1265
+
1266
+ /** @public */
1267
+ export type ViewQueryOptions = Pick<
1268
+ EmulatedResponseQueryOptions,
1269
+ 'perspective' | 'resultSourceMap' | 'filterResponse'
1270
+ >
1072
1271
 
1073
1272
  /** @public */
1074
1273
  export interface RawQueryResponse<R> {
@@ -1214,11 +1413,26 @@ export interface ApiError {
1214
1413
 
1215
1414
  /** @internal */
1216
1415
  export interface MutationError {
1217
- error: {
1218
- type: 'mutationError'
1219
- description: string
1220
- items?: MutationErrorItem[]
1221
- }
1416
+ type: 'mutationError'
1417
+ description: string
1418
+ items?: MutationErrorItem[]
1419
+ }
1420
+
1421
+ /**
1422
+ * Returned from the Content Lake API when a query is malformed, usually with a start
1423
+ * and end column to indicate where the error occurred, but not always. Can we used to
1424
+ * provide a more structured error message to the user.
1425
+ *
1426
+ * This will be located under the response `error` property.
1427
+ *
1428
+ * @public
1429
+ */
1430
+ export interface QueryParseError {
1431
+ type: 'queryParseError'
1432
+ description: string
1433
+ start?: number
1434
+ end?: number
1435
+ query?: string
1222
1436
  }
1223
1437
 
1224
1438
  /** @internal */
@@ -1232,11 +1446,9 @@ export interface MutationErrorItem {
1232
1446
 
1233
1447
  /** @internal */
1234
1448
  export interface ActionError {
1235
- error: {
1236
- type: 'actionError'
1237
- description: string
1238
- items?: ActionErrorItem[]
1239
- }
1449
+ type: 'actionError'
1450
+ description: string
1451
+ items?: ActionErrorItem[]
1240
1452
  }
1241
1453
 
1242
1454
  /** @internal */
@@ -1249,6 +1461,71 @@ export interface ActionErrorItem {
1249
1461
  index: number
1250
1462
  }
1251
1463
 
1464
+ /** @internal */
1465
+ export type PartialExcept<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>
1466
+
1467
+ /** @beta */
1468
+ export type ReleaseState =
1469
+ | 'active'
1470
+ | 'archiving'
1471
+ | 'unarchiving'
1472
+ | 'archived'
1473
+ | 'published'
1474
+ | 'publishing'
1475
+ | 'scheduled'
1476
+ | 'scheduling'
1477
+
1478
+ /** @internal */
1479
+ export type ReleaseType = 'asap' | 'scheduled' | 'undecided'
1480
+
1481
+ /** @internal */
1482
+ export interface ReleaseDocument extends SanityDocument {
1483
+ /**
1484
+ * typically
1485
+ * `_.releases.<name>`
1486
+ */
1487
+ _id: string
1488
+ /**
1489
+ * where a release has _id `_.releases.foo`, the name is `foo`
1490
+ */
1491
+ name: string
1492
+ _type: 'system.release'
1493
+ _createdAt: string
1494
+ _updatedAt: string
1495
+ _rev: string
1496
+ state: ReleaseState
1497
+ error?: {
1498
+ message: string
1499
+ }
1500
+ finalDocumentStates?: {
1501
+ /** Document ID */
1502
+ id: string
1503
+ }[]
1504
+ /**
1505
+ * If defined, it takes precedence over the intendedPublishAt, the state should be 'scheduled'
1506
+ */
1507
+ publishAt?: string
1508
+ /**
1509
+ * If defined, it provides the time the release was actually published
1510
+ */
1511
+ publishedAt?: string
1512
+ metadata: {
1513
+ title?: string
1514
+ description?: string
1515
+ intendedPublishAt?: string
1516
+ releaseType: ReleaseType
1517
+ }
1518
+ }
1519
+
1520
+ /** @internal */
1521
+ export type EditableReleaseDocument = Omit<
1522
+ PartialExcept<ReleaseDocument, '_id'>,
1523
+ 'metadata' | '_type'
1524
+ > & {
1525
+ _id: string
1526
+ metadata: Partial<ReleaseDocument['metadata']>
1527
+ }
1528
+
1252
1529
  /**
1253
1530
  * DocumentValueSource is a path to a value within a document
1254
1531
  * @public
@@ -1395,8 +1672,12 @@ export type {
1395
1672
  GenerateTargetDocument,
1396
1673
  GenerateTargetInclude,
1397
1674
  } from './agent/actions/generate'
1675
+ export type {PatchDocument, PatchOperation, PatchTarget} from './agent/actions/patch'
1676
+ export type {PromptRequest} from './agent/actions/prompt'
1398
1677
  export type {
1678
+ ImageDescriptionOperation,
1399
1679
  TransformDocument,
1680
+ TransformOperation,
1400
1681
  TransformTarget,
1401
1682
  TransformTargetDocument,
1402
1683
  TransformTargetInclude,
@@ -47,9 +47,13 @@ export class UsersClient {
47
47
  id: T,
48
48
  ): Promise<T extends 'me' ? CurrentSanityUser : SanityUser> {
49
49
  return lastValueFrom(
50
- _request<T extends 'me' ? CurrentSanityUser : SanityUser>(this.#client.config(), this.#httpRequest, {
51
- uri: `/users/${id}`,
52
- }),
50
+ _request<T extends 'me' ? CurrentSanityUser : SanityUser>(
51
+ this.#client.config(),
52
+ this.#httpRequest,
53
+ {
54
+ uri: `/users/${id}`,
55
+ },
56
+ ),
53
57
  )
54
58
  }
55
59
  }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Inlined, modified version of the `codeFrameColumns` function from `@babel/code-frame`.
3
+ * MIT-licensed - https://github.com/babel/babel/blob/main/LICENSE
4
+ * Copyright (c) 2014-present Sebastian McKenzie and other contributors.
5
+ */
6
+ type Location = {
7
+ column: number
8
+ line: number
9
+ }
10
+
11
+ type NodeLocation = {
12
+ start: Location
13
+ end?: Location
14
+ }
15
+
16
+ type GroqLocation = {
17
+ start: number
18
+ end?: number
19
+ }
20
+
21
+ /**
22
+ * RegExp to test for newlines.
23
+ */
24
+
25
+ const NEWLINE = /\r\n|[\n\r\u2028\u2029]/
26
+
27
+ /**
28
+ * Extract what lines should be marked and highlighted.
29
+ */
30
+
31
+ type MarkerLines = Record<number, true | [number, number]>
32
+
33
+ /**
34
+ * Highlight a code frame with the given location and message.
35
+ *
36
+ * @param query - The query to be highlighted.
37
+ * @param location - The location of the error in the code/query.
38
+ * @param message - Message to be displayed inline (if possible) next to the highlighted
39
+ * location in the code. If it can't be positioned inline, it will be placed above the
40
+ * code frame.
41
+ * @returns The highlighted code frame.
42
+ */
43
+ export function codeFrame(query: string, location: GroqLocation, message?: string): string {
44
+ const lines = query.split(NEWLINE)
45
+ const loc = {
46
+ start: columnToLine(location.start, lines),
47
+ end: location.end ? columnToLine(location.end, lines) : undefined,
48
+ }
49
+
50
+ const {start, end, markerLines} = getMarkerLines(loc, lines)
51
+
52
+ const numberMaxWidth = `${end}`.length
53
+
54
+ return query
55
+ .split(NEWLINE, end)
56
+ .slice(start, end)
57
+ .map((line, index) => {
58
+ const number = start + 1 + index
59
+ const paddedNumber = ` ${number}`.slice(-numberMaxWidth)
60
+ const gutter = ` ${paddedNumber} |`
61
+ const hasMarker = markerLines[number]
62
+ const lastMarkerLine = !markerLines[number + 1]
63
+ if (!hasMarker) {
64
+ return ` ${gutter}${line.length > 0 ? ` ${line}` : ''}`
65
+ }
66
+
67
+ let markerLine = ''
68
+ if (Array.isArray(hasMarker)) {
69
+ const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, ' ')
70
+ const numberOfMarkers = hasMarker[1] || 1
71
+
72
+ markerLine = [
73
+ '\n ',
74
+ gutter.replace(/\d/g, ' '),
75
+ ' ',
76
+ markerSpacing,
77
+ '^'.repeat(numberOfMarkers),
78
+ ].join('')
79
+
80
+ if (lastMarkerLine && message) {
81
+ markerLine += ' ' + message
82
+ }
83
+ }
84
+ return ['>', gutter, line.length > 0 ? ` ${line}` : '', markerLine].join('')
85
+ })
86
+ .join('\n')
87
+ }
88
+
89
+ function getMarkerLines(
90
+ loc: NodeLocation,
91
+ source: Array<string>,
92
+ ): {
93
+ start: number
94
+ end: number
95
+ markerLines: MarkerLines
96
+ } {
97
+ const startLoc: Location = {...loc.start}
98
+ const endLoc: Location = {...startLoc, ...loc.end}
99
+ const linesAbove = 2
100
+ const linesBelow = 3
101
+ const startLine = startLoc.line ?? -1
102
+ const startColumn = startLoc.column ?? 0
103
+ const endLine = endLoc.line
104
+ const endColumn = endLoc.column
105
+
106
+ let start = Math.max(startLine - (linesAbove + 1), 0)
107
+ let end = Math.min(source.length, endLine + linesBelow)
108
+
109
+ if (startLine === -1) {
110
+ start = 0
111
+ }
112
+
113
+ if (endLine === -1) {
114
+ end = source.length
115
+ }
116
+
117
+ const lineDiff = endLine - startLine
118
+ const markerLines: MarkerLines = {}
119
+
120
+ if (lineDiff) {
121
+ for (let i = 0; i <= lineDiff; i++) {
122
+ const lineNumber = i + startLine
123
+
124
+ if (!startColumn) {
125
+ markerLines[lineNumber] = true
126
+ } else if (i === 0) {
127
+ const sourceLength = source[lineNumber - 1].length
128
+
129
+ markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1]
130
+ } else if (i === lineDiff) {
131
+ markerLines[lineNumber] = [0, endColumn]
132
+ } else {
133
+ const sourceLength = source[lineNumber - i].length
134
+
135
+ markerLines[lineNumber] = [0, sourceLength]
136
+ }
137
+ }
138
+ } else {
139
+ if (startColumn === endColumn) {
140
+ if (startColumn) {
141
+ markerLines[startLine] = [startColumn, 0]
142
+ } else {
143
+ markerLines[startLine] = true
144
+ }
145
+ } else {
146
+ markerLines[startLine] = [startColumn, endColumn - startColumn]
147
+ }
148
+ }
149
+
150
+ return {start, end, markerLines}
151
+ }
152
+
153
+ function columnToLine(column: number, lines: string[]): Location {
154
+ let offset = 0
155
+
156
+ for (let i = 0; i < lines.length; i++) {
157
+ const lineLength = lines[i].length + 1 // assume '\n' after each line
158
+
159
+ if (offset + lineLength > column) {
160
+ return {
161
+ line: i + 1, // 1-based line
162
+ column: column - offset, // 0-based column
163
+ }
164
+ }
165
+
166
+ offset += lineLength
167
+ }
168
+
169
+ // Fallback: beyond last line
170
+ return {
171
+ line: lines.length,
172
+ column: lines[lines.length - 1]?.length ?? 0,
173
+ }
174
+ }
@@ -0,0 +1,79 @@
1
+ import {
2
+ getDraftId,
3
+ getVersionFromId,
4
+ getVersionId,
5
+ isDraftId,
6
+ isVersionId,
7
+ } from '@sanity/client/csm'
8
+ import {customAlphabet} from 'nanoid'
9
+
10
+ import type {IdentifiedSanityDocumentStub, SanityDocumentStub} from '../types'
11
+ import {validateVersionIdMatch} from '../validators'
12
+
13
+ /**
14
+ * @internal
15
+ *
16
+ * ~24 years (or 7.54e+8 seconds) needed, in order to have a 1% probability of at least one collision if 10 ID's are generated every hour.
17
+ */
18
+ export const generateReleaseId = customAlphabet(
19
+ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
20
+ 8,
21
+ )
22
+
23
+ /** @internal */
24
+ export const getDocumentVersionId = (publishedId: string, releaseId?: string) =>
25
+ releaseId ? getVersionId(publishedId, releaseId) : getDraftId(publishedId)
26
+
27
+ /** @internal */
28
+ export function deriveDocumentVersionId(
29
+ op: string,
30
+ {
31
+ releaseId,
32
+ publishedId,
33
+ document,
34
+ }: {
35
+ releaseId?: string
36
+ publishedId?: string
37
+ document: SanityDocumentStub | IdentifiedSanityDocumentStub
38
+ },
39
+ ): string {
40
+ if (publishedId && document._id) {
41
+ const versionId = getDocumentVersionId(publishedId, releaseId)
42
+ validateVersionIdMatch(versionId, document)
43
+ return versionId
44
+ }
45
+
46
+ if (document._id) {
47
+ const isDraft = isDraftId(document._id)
48
+ const isVersion = isVersionId(document._id)
49
+
50
+ if (!isDraft && !isVersion) {
51
+ throw new Error(
52
+ `\`${op}()\` requires a document with an \`_id\` that is a version or draft ID`,
53
+ )
54
+ }
55
+
56
+ if (releaseId) {
57
+ if (isDraft) {
58
+ throw new Error(
59
+ `\`${op}()\` was called with a document ID (\`${document._id}\`) that is a draft ID, but a release ID (\`${releaseId}\`) was also provided.`,
60
+ )
61
+ }
62
+
63
+ const builtVersionId = getVersionFromId(document._id)
64
+ if (builtVersionId !== releaseId) {
65
+ throw new Error(
66
+ `\`${op}()\` was called with a document ID (\`${document._id}\`) that is a version ID, but the release ID (\`${releaseId}\`) does not match the document's version ID (\`${builtVersionId}\`).`,
67
+ )
68
+ }
69
+ }
70
+
71
+ return document._id
72
+ }
73
+
74
+ if (publishedId) {
75
+ return getDocumentVersionId(publishedId, releaseId)
76
+ }
77
+
78
+ throw new Error(`\`${op}()\` requires either a publishedId or a document with an \`_id\``)
79
+ }
@@ -1,4 +1,4 @@
1
1
  /** @internal */
2
2
  export function isRecord(value: unknown): value is Record<string, unknown> {
3
- return typeof value === 'object' && value !== null
3
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
4
4
  }