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

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 +810 -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 +1950 -149
  29. package/dist/index.browser.d.ts +1950 -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 +1950 -149
  35. package/dist/index.d.ts +1950 -149
  36. package/dist/index.js +826 -31
  37. package/dist/index.js.map +1 -1
  38. package/dist/stega.browser.d.cts +1950 -149
  39. package/dist/stega.browser.d.ts +1950 -149
  40. package/dist/stega.d.cts +1950 -149
  41. package/dist/stega.d.ts +1950 -149
  42. package/dist/views.cjs +21 -5
  43. package/dist/views.cjs.map +1 -1
  44. package/dist/views.d.cts +54 -36
  45. package/dist/views.d.ts +54 -36
  46. package/dist/views.js +22 -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 +293 -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 +65 -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,47 @@ export interface UnfilteredResponseWithoutQuery extends ResponseQueryOptions {
1064
1229
  returnQuery: false
1065
1230
  }
1066
1231
 
1232
+ /** @public */
1233
+ export enum ViewResourceType {
1234
+ Dataset = 'dataset',
1235
+ View = 'view',
1236
+ }
1237
+
1238
+ /** @public */
1239
+ export type ViewOverride = {
1240
+ resourceType: ViewResourceType.View
1241
+ resourceId: string
1242
+ connections: ViewConnectionOverride[]
1243
+ }
1244
+
1245
+ /** @public */
1246
+ export type ViewConnectionOverride = {
1247
+ query: string
1248
+ resourceType: ViewResourceType
1249
+ resourceId: string
1250
+ }
1251
+
1252
+ /** @public */
1253
+ export interface EmulatedResponseQueryOptions extends ResponseQueryOptions {
1254
+ useEmulate: boolean
1255
+ connections?: ViewConnectionOverride[] | undefined
1256
+
1257
+ filterResponse?: false
1258
+ returnQuery?: false
1259
+ }
1260
+
1067
1261
  /** @public */
1068
1262
  export type QueryOptions =
1069
1263
  | FilteredResponseQueryOptions
1070
1264
  | UnfilteredResponseQueryOptions
1071
1265
  | UnfilteredResponseWithoutQuery
1266
+ | EmulatedResponseQueryOptions
1267
+
1268
+ /** @public */
1269
+ export type ViewQueryOptions = Pick<
1270
+ EmulatedResponseQueryOptions,
1271
+ 'perspective' | 'resultSourceMap' | 'filterResponse'
1272
+ >
1072
1273
 
1073
1274
  /** @public */
1074
1275
  export interface RawQueryResponse<R> {
@@ -1214,11 +1415,26 @@ export interface ApiError {
1214
1415
 
1215
1416
  /** @internal */
1216
1417
  export interface MutationError {
1217
- error: {
1218
- type: 'mutationError'
1219
- description: string
1220
- items?: MutationErrorItem[]
1221
- }
1418
+ type: 'mutationError'
1419
+ description: string
1420
+ items?: MutationErrorItem[]
1421
+ }
1422
+
1423
+ /**
1424
+ * Returned from the Content Lake API when a query is malformed, usually with a start
1425
+ * and end column to indicate where the error occurred, but not always. Can we used to
1426
+ * provide a more structured error message to the user.
1427
+ *
1428
+ * This will be located under the response `error` property.
1429
+ *
1430
+ * @public
1431
+ */
1432
+ export interface QueryParseError {
1433
+ type: 'queryParseError'
1434
+ description: string
1435
+ start?: number
1436
+ end?: number
1437
+ query?: string
1222
1438
  }
1223
1439
 
1224
1440
  /** @internal */
@@ -1232,11 +1448,9 @@ export interface MutationErrorItem {
1232
1448
 
1233
1449
  /** @internal */
1234
1450
  export interface ActionError {
1235
- error: {
1236
- type: 'actionError'
1237
- description: string
1238
- items?: ActionErrorItem[]
1239
- }
1451
+ type: 'actionError'
1452
+ description: string
1453
+ items?: ActionErrorItem[]
1240
1454
  }
1241
1455
 
1242
1456
  /** @internal */
@@ -1249,6 +1463,71 @@ export interface ActionErrorItem {
1249
1463
  index: number
1250
1464
  }
1251
1465
 
1466
+ /** @internal */
1467
+ export type PartialExcept<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>
1468
+
1469
+ /** @beta */
1470
+ export type ReleaseState =
1471
+ | 'active'
1472
+ | 'archiving'
1473
+ | 'unarchiving'
1474
+ | 'archived'
1475
+ | 'published'
1476
+ | 'publishing'
1477
+ | 'scheduled'
1478
+ | 'scheduling'
1479
+
1480
+ /** @internal */
1481
+ export type ReleaseType = 'asap' | 'scheduled' | 'undecided'
1482
+
1483
+ /** @internal */
1484
+ export interface ReleaseDocument extends SanityDocument {
1485
+ /**
1486
+ * typically
1487
+ * `_.releases.<name>`
1488
+ */
1489
+ _id: string
1490
+ /**
1491
+ * where a release has _id `_.releases.foo`, the name is `foo`
1492
+ */
1493
+ name: string
1494
+ _type: 'system.release'
1495
+ _createdAt: string
1496
+ _updatedAt: string
1497
+ _rev: string
1498
+ state: ReleaseState
1499
+ error?: {
1500
+ message: string
1501
+ }
1502
+ finalDocumentStates?: {
1503
+ /** Document ID */
1504
+ id: string
1505
+ }[]
1506
+ /**
1507
+ * If defined, it takes precedence over the intendedPublishAt, the state should be 'scheduled'
1508
+ */
1509
+ publishAt?: string
1510
+ /**
1511
+ * If defined, it provides the time the release was actually published
1512
+ */
1513
+ publishedAt?: string
1514
+ metadata: {
1515
+ title?: string
1516
+ description?: string
1517
+ intendedPublishAt?: string
1518
+ releaseType: ReleaseType
1519
+ }
1520
+ }
1521
+
1522
+ /** @internal */
1523
+ export type EditableReleaseDocument = Omit<
1524
+ PartialExcept<ReleaseDocument, '_id'>,
1525
+ 'metadata' | '_type'
1526
+ > & {
1527
+ _id: string
1528
+ metadata: Partial<ReleaseDocument['metadata']>
1529
+ }
1530
+
1252
1531
  /**
1253
1532
  * DocumentValueSource is a path to a value within a document
1254
1533
  * @public
@@ -1395,8 +1674,12 @@ export type {
1395
1674
  GenerateTargetDocument,
1396
1675
  GenerateTargetInclude,
1397
1676
  } from './agent/actions/generate'
1677
+ export type {PatchDocument, PatchOperation, PatchTarget} from './agent/actions/patch'
1678
+ export type {PromptRequest} from './agent/actions/prompt'
1398
1679
  export type {
1680
+ ImageDescriptionOperation,
1399
1681
  TransformDocument,
1682
+ TransformOperation,
1400
1683
  TransformTarget,
1401
1684
  TransformTargetDocument,
1402
1685
  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
+ }