@sanity/sdk 0.0.0-alpha.21 → 0.0.0-alpha.23

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 (127) hide show
  1. package/dist/index.d.ts +428 -325
  2. package/dist/index.js +1618 -1553
  3. package/dist/index.js.map +1 -1
  4. package/package.json +6 -7
  5. package/src/_exports/index.ts +31 -30
  6. package/src/auth/authStore.test.ts +149 -104
  7. package/src/auth/authStore.ts +51 -100
  8. package/src/auth/handleAuthCallback.test.ts +67 -34
  9. package/src/auth/handleAuthCallback.ts +8 -7
  10. package/src/auth/logout.test.ts +61 -29
  11. package/src/auth/logout.ts +26 -28
  12. package/src/auth/refreshStampedToken.test.ts +9 -9
  13. package/src/auth/refreshStampedToken.ts +62 -56
  14. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +5 -5
  15. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +45 -47
  16. package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +4 -5
  17. package/src/auth/subscribeToStorageEventsAndSetToken.ts +22 -24
  18. package/src/client/clientStore.test.ts +131 -67
  19. package/src/client/clientStore.ts +117 -116
  20. package/src/comlink/controller/actions/destroyController.test.ts +38 -13
  21. package/src/comlink/controller/actions/destroyController.ts +11 -15
  22. package/src/comlink/controller/actions/getOrCreateChannel.test.ts +56 -27
  23. package/src/comlink/controller/actions/getOrCreateChannel.ts +37 -35
  24. package/src/comlink/controller/actions/getOrCreateController.test.ts +27 -16
  25. package/src/comlink/controller/actions/getOrCreateController.ts +23 -22
  26. package/src/comlink/controller/actions/releaseChannel.test.ts +37 -13
  27. package/src/comlink/controller/actions/releaseChannel.ts +22 -21
  28. package/src/comlink/controller/comlinkControllerStore.test.ts +65 -36
  29. package/src/comlink/controller/comlinkControllerStore.ts +44 -5
  30. package/src/comlink/node/actions/getOrCreateNode.test.ts +31 -15
  31. package/src/comlink/node/actions/getOrCreateNode.ts +30 -29
  32. package/src/comlink/node/actions/releaseNode.test.ts +75 -55
  33. package/src/comlink/node/actions/releaseNode.ts +19 -21
  34. package/src/comlink/node/comlinkNodeStore.test.ts +6 -11
  35. package/src/comlink/node/comlinkNodeStore.ts +22 -5
  36. package/src/config/authConfig.ts +79 -0
  37. package/src/config/sanityConfig.ts +48 -0
  38. package/src/datasets/datasets.test.ts +2 -2
  39. package/src/datasets/datasets.ts +18 -5
  40. package/src/document/actions.test.ts +22 -10
  41. package/src/document/actions.ts +44 -56
  42. package/src/document/applyDocumentActions.test.ts +96 -36
  43. package/src/document/applyDocumentActions.ts +140 -99
  44. package/src/document/documentStore.test.ts +103 -155
  45. package/src/document/documentStore.ts +247 -237
  46. package/src/document/listen.ts +56 -55
  47. package/src/document/patchOperations.ts +0 -43
  48. package/src/document/permissions.test.ts +25 -12
  49. package/src/document/permissions.ts +11 -4
  50. package/src/document/processActions.test.ts +41 -8
  51. package/src/document/reducers.test.ts +87 -16
  52. package/src/document/reducers.ts +2 -2
  53. package/src/document/sharedListener.test.ts +34 -16
  54. package/src/document/sharedListener.ts +33 -11
  55. package/src/preview/getPreviewState.test.ts +40 -39
  56. package/src/preview/getPreviewState.ts +68 -56
  57. package/src/preview/previewConstants.ts +43 -0
  58. package/src/preview/previewQuery.test.ts +1 -1
  59. package/src/preview/previewQuery.ts +4 -5
  60. package/src/preview/previewStore.test.ts +13 -58
  61. package/src/preview/previewStore.ts +7 -21
  62. package/src/preview/resolvePreview.test.ts +33 -104
  63. package/src/preview/resolvePreview.ts +11 -21
  64. package/src/preview/subscribeToStateAndFetchBatches.test.ts +96 -97
  65. package/src/preview/subscribeToStateAndFetchBatches.ts +85 -81
  66. package/src/preview/util.ts +1 -0
  67. package/src/project/project.test.ts +3 -3
  68. package/src/project/project.ts +28 -5
  69. package/src/projection/getProjectionState.test.ts +69 -49
  70. package/src/projection/getProjectionState.ts +42 -50
  71. package/src/projection/projectionQuery.ts +1 -1
  72. package/src/projection/projectionStore.test.ts +13 -51
  73. package/src/projection/projectionStore.ts +6 -18
  74. package/src/projection/resolveProjection.test.ts +32 -127
  75. package/src/projection/resolveProjection.ts +15 -28
  76. package/src/projection/subscribeToStateAndFetchBatches.test.ts +105 -90
  77. package/src/projection/subscribeToStateAndFetchBatches.ts +94 -81
  78. package/src/projection/util.ts +2 -0
  79. package/src/projects/projects.test.ts +13 -4
  80. package/src/projects/projects.ts +6 -1
  81. package/src/query/queryStore.test.ts +10 -47
  82. package/src/query/queryStore.ts +151 -133
  83. package/src/query/queryStoreConstants.ts +2 -0
  84. package/src/store/createActionBinder.test.ts +153 -0
  85. package/src/store/createActionBinder.ts +176 -0
  86. package/src/store/createSanityInstance.test.ts +84 -0
  87. package/src/store/createSanityInstance.ts +124 -0
  88. package/src/store/createStateSourceAction.test.ts +196 -0
  89. package/src/store/createStateSourceAction.ts +260 -0
  90. package/src/store/createStoreInstance.test.ts +81 -0
  91. package/src/store/createStoreInstance.ts +80 -0
  92. package/src/store/createStoreState.test.ts +85 -0
  93. package/src/store/createStoreState.ts +92 -0
  94. package/src/store/defineStore.test.ts +18 -0
  95. package/src/store/defineStore.ts +81 -0
  96. package/src/users/reducers.test.ts +318 -0
  97. package/src/users/reducers.ts +88 -0
  98. package/src/users/types.ts +46 -4
  99. package/src/users/usersConstants.ts +4 -0
  100. package/src/users/usersStore.test.ts +350 -223
  101. package/src/users/usersStore.ts +285 -149
  102. package/src/utils/createFetcherStore.test.ts +6 -7
  103. package/src/utils/createFetcherStore.ts +150 -153
  104. package/src/{common/util.test.ts → utils/hashString.test.ts} +1 -1
  105. package/src/auth/fetchLoginUrls.test.ts +0 -163
  106. package/src/auth/fetchLoginUrls.ts +0 -74
  107. package/src/common/createLiveEventSubscriber.test.ts +0 -121
  108. package/src/common/createLiveEventSubscriber.ts +0 -55
  109. package/src/common/types.ts +0 -4
  110. package/src/instance/identity.test.ts +0 -46
  111. package/src/instance/identity.ts +0 -29
  112. package/src/instance/sanityInstance.test.ts +0 -77
  113. package/src/instance/sanityInstance.ts +0 -57
  114. package/src/instance/types.ts +0 -37
  115. package/src/preview/getPreviewProjection.ts +0 -45
  116. package/src/resources/README.md +0 -370
  117. package/src/resources/createAction.test.ts +0 -101
  118. package/src/resources/createAction.ts +0 -44
  119. package/src/resources/createResource.test.ts +0 -112
  120. package/src/resources/createResource.ts +0 -102
  121. package/src/resources/createStateSourceAction.test.ts +0 -114
  122. package/src/resources/createStateSourceAction.ts +0 -83
  123. package/src/resources/createStore.test.ts +0 -67
  124. package/src/resources/createStore.ts +0 -46
  125. package/src/store/createStore.test.ts +0 -108
  126. package/src/store/createStore.ts +0 -106
  127. /package/src/{common/util.ts → utils/hashString.ts} +0 -0
@@ -1,121 +0,0 @@
1
- import {type LiveEventMessage, SanityClient} from '@sanity/client'
2
- import {Observable, of, Subject} from 'rxjs'
3
- import {describe, it, vi} from 'vitest'
4
-
5
- import {getClientState} from '../client/clientStore'
6
- import {createSanityInstance} from '../instance/sanityInstance'
7
- import {createResourceState, type ResourceState} from '../resources/createResource'
8
- import {type StateSource} from '../resources/createStateSourceAction'
9
- import {createLiveEventSubscriber} from './createLiveEventSubscriber'
10
- import {type LiveEventAwareState} from './types'
11
-
12
- vi.mock('../client/clientStore.ts', () => ({getClientState: vi.fn()}))
13
-
14
- vi.mock('../resources/createResource', async (importOriginal) => {
15
- const original = await importOriginal<typeof import('../resources/createResource')>()
16
- return {...original, getOrCreateResource: vi.fn()}
17
- })
18
-
19
- describe('createLiveEventSubscriber', () => {
20
- const TEST_TAG = 'test-tag'
21
- const instance = createSanityInstance({projectId: 'exampleProject', dataset: 'exampleDataset'})
22
- const initialState: LiveEventAwareState = {
23
- lastLiveEventId: null,
24
- syncTags: {},
25
- }
26
- let state: ResourceState<LiveEventAwareState>
27
-
28
- beforeEach(() => {
29
- state = createResourceState(initialState)
30
- vi.clearAllMocks()
31
- })
32
-
33
- it('listens for matching sync tags and updates the `lastLiveEventId`', async () => {
34
- const mockLiveEvents = new Observable<LiveEventMessage>((observer) => {
35
- observer.next({
36
- type: 'message',
37
- id: 'event123',
38
- tags: ['s1:tag1', 's1:tag2'],
39
- })
40
- })
41
-
42
- const mockClient = {
43
- live: {
44
- events: vi.fn().mockReturnValue(mockLiveEvents),
45
- },
46
- config: vi.fn().mockReturnValue({}),
47
- }
48
-
49
- // Mock the getSubscribableClient to emit our mock client
50
- vi.mocked(getClientState).mockReturnValue({
51
- observable: of(mockClient as unknown as SanityClient),
52
- } as StateSource<SanityClient>)
53
-
54
- // Set up initial state with a matching sync tag
55
- state.set('setSyncTags', {
56
- syncTags: {
57
- 's1:tag1': true,
58
- },
59
- })
60
-
61
- // Create and subscribe to live events
62
- const subscribeToLiveAndSetLastLiveEventId =
63
- createLiveEventSubscriber<LiveEventAwareState>(TEST_TAG)
64
- const subscription = subscribeToLiveAndSetLastLiveEventId({instance, state})
65
-
66
- // Verify the client was configured correctly
67
- expect(mockClient.live.events).toHaveBeenCalledWith({
68
- includeDrafts: false,
69
- tag: TEST_TAG,
70
- })
71
-
72
- // Verify the state was updated with the new event ID
73
- expect(state.get().lastLiveEventId).toBe('event123')
74
-
75
- // Clean up subscription
76
- subscription.unsubscribe()
77
- })
78
-
79
- it('unsubscribes from the previous live content connection if any', () => {
80
- const unsubscribe = vi.fn()
81
-
82
- const mockLiveEvents = new Observable<LiveEventMessage>((observer) => {
83
- observer.next({
84
- type: 'message',
85
- id: 'event123',
86
- tags: ['s1:tag1'],
87
- })
88
-
89
- return unsubscribe
90
- })
91
-
92
- const mockClient = {
93
- live: {
94
- events: vi.fn().mockReturnValue(mockLiveEvents),
95
- },
96
- config: vi.fn().mockReturnValue({}),
97
- }
98
-
99
- const clientSubject = new Subject()
100
-
101
- vi.mocked(getClientState).mockReturnValue({
102
- observable: clientSubject as Observable<SanityClient>,
103
- } as StateSource<SanityClient>)
104
-
105
- // Create and subscribe to live events
106
- const subscribeToLiveAndSetLastLiveEventId =
107
- createLiveEventSubscriber<LiveEventAwareState>(TEST_TAG)
108
- const liveSubscription = subscribeToLiveAndSetLastLiveEventId({instance, state})
109
- clientSubject.next(mockClient)
110
-
111
- expect(mockClient.live.events).toHaveBeenCalledTimes(1)
112
-
113
- const newClient = {...mockClient}
114
- clientSubject.next(newClient)
115
- expect(unsubscribe).toHaveBeenCalledTimes(1)
116
-
117
- // Clean up subscriptions
118
- liveSubscription.unsubscribe()
119
- expect(unsubscribe).toHaveBeenCalledTimes(2)
120
- })
121
- })
@@ -1,55 +0,0 @@
1
- import {combineLatest, distinctUntilChanged, filter, map, type Subscription, switchMap} from 'rxjs'
2
-
3
- import {getClientState} from '../client/clientStore'
4
- import {type ActionContext, createInternalAction} from '../resources/createAction'
5
- import {type LiveEventAwareState} from './types'
6
-
7
- /*
8
- * Factory function for creating a subscribeToLiveAndSetLastLiveEventId action.
9
- * Typically invoked in the initialization of stores that depend on the live events API.
10
- * It listens to events associated with sync tags (also kept internally in the store)
11
-
12
- * Usage like:
13
- *
14
- * const subscribeToLiveAndSetLastLiveEventId = createLiveEventSubscriber<ProjectionStoreState<TValue>>(TAG)
15
- * const liveSubscription = subscribeToLiveAndSetLastLiveEventId(this)
16
- *
17
- * return () => {
18
- * stateSubscriptionForBatches.unsubscribe()
19
- * liveSubscription.unsubscribe()
20
- */
21
- export function createLiveEventSubscriber<TState extends LiveEventAwareState>(
22
- tag: string,
23
- ): (actionContext: ActionContext<TState>) => Subscription {
24
- return createInternalAction(({instance, state}: ActionContext<TState>) => {
25
- const client$ = getClientState(instance, {apiVersion: 'vX'}).observable
26
- const syncTags$ = state.observable.pipe(
27
- map((i) => i.syncTags),
28
- distinctUntilChanged(),
29
- )
30
-
31
- return function () {
32
- const messageEvents$ = client$.pipe(
33
- switchMap((client) =>
34
- client.live
35
- .events({includeDrafts: !!client.config().token, tag})
36
- .pipe(filter((e): e is Extract<typeof e, {type: 'message'}> => e.type === 'message')),
37
- ),
38
- )
39
-
40
- return combineLatest([messageEvents$, syncTags$]).subscribe({
41
- next: ([event, currentSyncTags]) => {
42
- for (const eventTag of event.tags) {
43
- if (currentSyncTags[eventTag]) {
44
- state.set('setLastLiveEventId', (prevState: TState) => ({
45
- ...prevState,
46
- lastLiveEventId: event.id,
47
- }))
48
- return
49
- }
50
- }
51
- },
52
- })
53
- }
54
- })
55
- }
@@ -1,4 +0,0 @@
1
- export interface LiveEventAwareState {
2
- lastLiveEventId: string | null
3
- syncTags: Record<string, true>
4
- }
@@ -1,46 +0,0 @@
1
- import {describe, expect, it} from 'vitest'
2
-
3
- import {getSdkIdentity} from './identity'
4
-
5
- describe('identity', () => {
6
- describe('getSdkIdentity', () => {
7
- it('creates a frozen object with expected properties', () => {
8
- const identity = getSdkIdentity({
9
- projectId: 'test-project',
10
- dataset: 'test-dataset',
11
- })
12
-
13
- // Check if object is frozen
14
- expect(Object.isFrozen(identity)).toBe(true)
15
-
16
- // Check if all expected properties exist
17
- expect(identity).toHaveProperty('id')
18
- expect(identity).toHaveProperty('projectId', 'test-project')
19
- expect(identity).toHaveProperty('dataset', 'test-dataset')
20
- })
21
-
22
- it('generates unique ids for different instances', () => {
23
- const identity1 = getSdkIdentity({
24
- projectId: 'test-project',
25
- dataset: 'test-dataset',
26
- })
27
-
28
- const identity2 = getSdkIdentity({
29
- projectId: 'test-project',
30
- dataset: 'test-dataset',
31
- })
32
-
33
- expect(identity1.id).not.toBe(identity2.id)
34
- })
35
-
36
- it('generates id with correct format', () => {
37
- const identity = getSdkIdentity({
38
- projectId: 'test-project',
39
- dataset: 'test-dataset',
40
- })
41
-
42
- // ID should be 16 characters long (8 pairs of hex digits)
43
- expect(identity.id).toMatch(/^[0-9a-f]{16}$/)
44
- })
45
- })
46
- })
@@ -1,29 +0,0 @@
1
- import {type SdkIdentity} from './types'
2
-
3
- /**
4
- * thoughtLevel 2 - Primarily what we want is to have an object that we can bind stores/memoizations to, but let the things that depend on it (eg projectId, dataset) be internals that can't be overwritten by accident/intentionally
5
- * @public
6
- */
7
- export function getSdkIdentity({
8
- projectId,
9
- dataset,
10
- }: {
11
- projectId: string
12
- dataset: string
13
- }): SdkIdentity {
14
- const id = generateId()
15
- return Object.freeze({
16
- id,
17
- projectId,
18
- dataset,
19
- resourceId: `${projectId}.${dataset}`,
20
- })
21
- }
22
-
23
- function generateId() {
24
- return Array.from({length: 8}, () =>
25
- Math.floor(Math.random() * 16)
26
- .toString(16)
27
- .padStart(2, '0'),
28
- ).join('')
29
- }
@@ -1,77 +0,0 @@
1
- import {beforeEach, describe, expect, test} from 'vitest'
2
-
3
- import {disposeResources} from '../resources/createResource'
4
- import {createSanityInstance, getOrCreateResource} from './sanityInstance'
5
- import {type SanityConfig} from './types'
6
-
7
- vi.mock('../resources/createResource')
8
-
9
- describe('sanityInstance', () => {
10
- let config: SanityConfig
11
-
12
- beforeEach(() => {
13
- config = {
14
- projectId: 'test-project',
15
- dataset: 'test-dataset',
16
- }
17
- })
18
-
19
- describe('createSanityInstance', () => {
20
- test('creates instance with correct configuration', () => {
21
- const instance = createSanityInstance(config)
22
-
23
- expect(instance.identity).toEqual(
24
- expect.objectContaining({
25
- projectId: 'test-project',
26
- dataset: 'test-dataset',
27
- }),
28
- )
29
- })
30
-
31
- test('instance.dispose', () => {
32
- const instance = createSanityInstance(config)
33
- instance.dispose()
34
-
35
- expect(disposeResources).toHaveBeenCalled()
36
- })
37
- })
38
-
39
- describe('getOrCreateResource', () => {
40
- test('creates and caches resource', () => {
41
- const instance = createSanityInstance(config)
42
- let createCount = 0
43
-
44
- const creator = () => {
45
- createCount++
46
- return {value: 'test-resource'}
47
- }
48
-
49
- // First call should create new resource
50
- const resource1 = getOrCreateResource(instance, 'test-key', creator)
51
- expect(resource1).toEqual({value: 'test-resource'})
52
- expect(createCount).toBe(1)
53
-
54
- // Second call should return cached resource
55
- const resource2 = getOrCreateResource(instance, 'test-key', creator)
56
- expect(resource2).toBe(resource1)
57
- expect(createCount).toBe(1)
58
- })
59
-
60
- test('different instances have separate resource caches', () => {
61
- const instance1 = createSanityInstance({...config, projectId: 'project1'})
62
- const instance2 = createSanityInstance({...config, projectId: 'project2'})
63
- let createCount = 0
64
-
65
- const creator = () => {
66
- createCount++
67
- return {value: 'test-resource'}
68
- }
69
-
70
- const resource1 = getOrCreateResource(instance1, 'test-key', creator)
71
- const resource2 = getOrCreateResource(instance2, 'test-key', creator)
72
-
73
- expect(resource1).not.toBe(resource2)
74
- expect(createCount).toBe(2)
75
- })
76
- })
77
- })
@@ -1,57 +0,0 @@
1
- import {disposeResources} from '../resources/createResource'
2
- import {getSdkIdentity} from './identity'
3
- import {type SanityConfig, type SanityInstance, type SdkIdentity} from './types'
4
-
5
- /**
6
- * Returns a new instance of dependencies required for SanitySDK.
7
- *
8
- * @public
9
- *
10
- * @param config - The configuration for this instance
11
- *
12
- * @returns A new "instance" of a Sanity SDK, used to bind resources/configuration to it
13
- */
14
- export function createSanityInstance({
15
- projectId = '',
16
- dataset = '',
17
- ...config
18
- }: SanityConfig): SanityInstance {
19
- const identity = getSdkIdentity({projectId, dataset})
20
- return {
21
- identity,
22
- config,
23
- dispose: () => disposeResources(identity),
24
- }
25
- }
26
-
27
- const resourceStorage = new WeakMap<SdkIdentity, Map<string, unknown>>()
28
-
29
- function getResource(instance: SanityInstance, key: string) {
30
- const instanceMap = resourceStorage.get(instance.identity)
31
- return instanceMap?.get(key)
32
- }
33
-
34
- function setResource(instance: SanityInstance, key: string, value: unknown) {
35
- let instanceMap = resourceStorage.get(instance.identity)
36
- if (!instanceMap) {
37
- instanceMap = new Map()
38
- resourceStorage.set(instance.identity, instanceMap)
39
- }
40
- instanceMap.set(key, value)
41
- }
42
-
43
- /**
44
- * This is an internal function that retrieves or creates a Zustand store resource.
45
- * @internal
46
- */
47
- export function getOrCreateResource<T>(instance: SanityInstance, key: string, creator: () => T): T {
48
- const cached = getResource(instance, key)
49
-
50
- if (cached) {
51
- return cached as T
52
- }
53
-
54
- const resource = creator()
55
- setResource(instance, key, resource)
56
- return resource
57
- }
@@ -1,37 +0,0 @@
1
- /* eslint-disable import/consistent-type-specifier-style */
2
- // NOTE: These have to be type import because we do not want the side-effect
3
- // of importing these modules, we just want the types for their configs
4
- import type {AuthConfig} from '../auth/authStore'
5
- import type {ResourceId} from '../document/patchOperations'
6
-
7
- /**
8
- * @public
9
- */
10
- export interface SanityConfig {
11
- projectId: string
12
- dataset: string
13
- auth?: AuthConfig
14
- }
15
-
16
- /** @public */
17
- export interface SanityInstance {
18
- /**
19
- * The following is used to look up resources associated with this instance,
20
- * and can be used to retrieve an "id" for the instance - useful in debugging.
21
- *
22
- * @public
23
- */
24
- readonly identity: SdkIdentity
25
-
26
- config: Omit<SanityConfig, 'projectId' | 'dataset'>
27
-
28
- dispose: () => void
29
- }
30
-
31
- /** @public */
32
- export interface SdkIdentity {
33
- readonly id: string
34
- readonly projectId: string
35
- readonly dataset: string
36
- readonly resourceId: ResourceId
37
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * The fields to check for a title.
3
- * The order of the items in the array defines the priority.
4
- *
5
- * @internal
6
- */
7
- export const TITLE_CANDIDATES = ['title', 'name', 'label', 'heading', 'header', 'caption']
8
-
9
- /**
10
- * The fields to check for a subtitle.
11
- * The order of the items in the array defines the priority.
12
- *
13
- * @internal
14
- */
15
- export const SUBTITLE_CANDIDATES = ['description', 'subtitle', ...TITLE_CANDIDATES]
16
-
17
- /**
18
- * Generates a GROQ projection for preview data without requiring a schema.
19
- * Uses common field names to make educated guesses about which fields to use.
20
- *
21
- * @internal
22
- */
23
- export function getPreviewProjection(): string {
24
- return `{
25
- // Get all potential title fields
26
- "titleCandidates": {
27
- ${TITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(',\n ')}
28
- },
29
- // Get all potential subtitle fields
30
- "subtitleCandidates": {
31
- ${SUBTITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(',\n ')}
32
- },
33
- "media": coalesce(
34
- select(
35
- defined(asset) => {"type": "image-asset", "_ref": asset._ref},
36
- defined(image.asset) => {"type": "image-asset", "_ref": image.asset._ref},
37
- defined(mainImage.asset) => {"type": "image-asset", "_ref": mainImage.asset._ref},
38
- null
39
- )
40
- ),
41
- _type,
42
- _id,
43
- _updatedAt
44
- }`
45
- }