@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
package/dist/index.js CHANGED
@@ -1,17 +1,63 @@
1
1
  import { createClient } from "@sanity/client";
2
- import { Observable, share, map, distinctUntilChanged, skip, filter, switchMap, interval, takeWhile, fromEvent, EMPTY, defer, firstValueFrom, from, asapScheduler, concatMap, of, withLatestFrom, concat, timer, throwError, first as first$1, partition, merge, shareReplay, Subject, tap as tap$1, catchError as catchError$1, startWith as startWith$1, pairwise as pairwise$1, groupBy as groupBy$1, mergeMap as mergeMap$1, throttle, race, combineLatest, debounceTime, NEVER } from "rxjs";
2
+ import { Observable, share, map, distinctUntilChanged, skip, filter, switchMap, interval, takeWhile, fromEvent, EMPTY, defer, firstValueFrom, from, asapScheduler, concatMap, of, withLatestFrom, concat, timer, throwError, first as first$1, Subject, takeUntil, partition, merge, shareReplay, tap as tap$1, catchError as catchError$1, startWith as startWith$1, pairwise as pairwise$1, groupBy as groupBy$1, mergeMap as mergeMap$1, throttle, race, NEVER, combineLatest, debounceTime } from "rxjs";
3
3
  import { devtools } from "zustand/middleware";
4
- import { createStore as createStore$1 } from "zustand/vanilla";
5
- import { createSelector } from "reselect";
6
- import { isEqual, omit, isObject, noop } from "lodash-es";
4
+ import { createStore } from "zustand/vanilla";
5
+ import { pick, isEqual, omit, isObject } from "lodash-es";
7
6
  import { createController, createNode } from "@sanity/comlink";
8
7
  import { first, switchMap as switchMap$1, groupBy, mergeMap, startWith, pairwise, filter as filter$1, map as map$1, delay, tap, catchError, scan } from "rxjs/operators";
9
8
  import { SanityEncoder } from "@sanity/mutate";
10
9
  import { getPublishedId as getPublishedId$1 } from "@sanity/client/csm";
10
+ import { createSelector } from "reselect";
11
11
  import { applyPatches, parsePatch, makePatches, stringifyPatches } from "@sanity/diff-match-patch";
12
12
  import { isKeySegment, isKeyedObject } from "@sanity/types";
13
13
  import { createDocumentLoaderFromClient } from "@sanity/mutate/_unstable_store";
14
14
  var AuthStateType = /* @__PURE__ */ ((AuthStateType2) => (AuthStateType2.LOGGED_IN = "logged-in", AuthStateType2.LOGGING_IN = "logging-in", AuthStateType2.ERROR = "error", AuthStateType2.LOGGED_OUT = "logged-out", AuthStateType2))(AuthStateType || {});
15
+ function getPublishedId(id) {
16
+ const draftsPrefix = "drafts.";
17
+ return id.startsWith(draftsPrefix) ? id.slice(draftsPrefix.length) : id;
18
+ }
19
+ function getDraftId(id) {
20
+ const draftsPrefix = "drafts.";
21
+ return id.startsWith(draftsPrefix) ? id : `${draftsPrefix}${id}`;
22
+ }
23
+ function insecureRandomId() {
24
+ return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
25
+ }
26
+ function createSanityInstance(config = {}) {
27
+ const instanceId = crypto.randomUUID(), disposeListeners = /* @__PURE__ */ new Map(), disposed = { current: !1 }, instance = {
28
+ instanceId,
29
+ config,
30
+ isDisposed: () => disposed.current,
31
+ dispose: () => {
32
+ disposed.current || (disposed.current = !0, disposeListeners.forEach((listener) => listener()), disposeListeners.clear());
33
+ },
34
+ onDispose: (cb) => {
35
+ const listenerId = insecureRandomId();
36
+ return disposeListeners.set(listenerId, cb), () => {
37
+ disposeListeners.delete(listenerId);
38
+ };
39
+ },
40
+ getParent: () => {
41
+ },
42
+ createChild: (next) => Object.assign(
43
+ createSanityInstance({
44
+ ...config,
45
+ ...next,
46
+ ...config.auth === next.auth ? config.auth : config.auth && next.auth && { auth: { ...config.auth, ...next.auth } }
47
+ }),
48
+ { getParent: () => instance }
49
+ ),
50
+ match: (targetConfig) => {
51
+ if (Object.entries(pick(targetConfig, "auth", "projectId", "dataset")).every(
52
+ ([key, value]) => config[key] === value
53
+ ))
54
+ return instance;
55
+ const parent = instance.getParent();
56
+ if (parent) return parent.match(targetConfig);
57
+ }
58
+ };
59
+ return instance;
60
+ }
15
61
  function getEnv(key) {
16
62
  if (typeof import.meta < "u" && import.meta.env)
17
63
  return import.meta.env[key];
@@ -20,68 +66,78 @@ function getEnv(key) {
20
66
  if (typeof window < "u" && window.ENV)
21
67
  return window.ENV?.[key];
22
68
  }
23
- const resourceCache = /* @__PURE__ */ new WeakMap();
24
- function createResourceState(initialState, devToolsOptions) {
25
- const store = createStore$1()(devtools(() => initialState, devToolsOptions));
69
+ function createStoreState(initialState, devToolsOptions) {
70
+ const store = createStore()(devtools(() => initialState, devToolsOptions));
26
71
  return {
27
72
  get: store.getState,
28
73
  set: (actionKey, updatedState) => {
29
- store.getState() !== updatedState && store.setState(updatedState, !1, actionKey);
74
+ const currentState = store.getState(), nextState = typeof updatedState == "function" ? updatedState(currentState) : updatedState;
75
+ currentState !== nextState && store.setState(nextState, !1, actionKey);
30
76
  },
31
77
  observable: new Observable((observer) => {
32
78
  const emit = () => observer.next(store.getState());
33
- return emit(), store.subscribe(emit);
79
+ emit();
80
+ const unsubscribe = store.subscribe(emit);
81
+ return () => unsubscribe();
34
82
  })
35
83
  };
36
84
  }
37
- function initializeResource(instance, resource) {
38
- const fullName = resource.name === "Auth" ? "Auth-global" : `${resource.name}-${instance.identity.resourceId}`, initialState = resource.getInitialState(instance), state = createResourceState(initialState, {
39
- name: fullName,
40
- enabled: !!getEnv("DEV")
41
- }), dispose = resource.initialize?.call({ instance, state }, instance) ?? (() => {
42
- });
43
- return { state, dispose };
44
- }
45
- function getOrCreateResource(instance, resource) {
46
- const fullName = resource.name === "Auth" ? "Auth-global" : `${resource.name}-${instance.identity.resourceId}`;
47
- resourceCache.has(instance.identity) || resourceCache.set(instance.identity, /* @__PURE__ */ new Map());
48
- const initializedResources = resourceCache.get(instance.identity), cached = initializedResources.get(fullName);
49
- if (cached) return cached;
50
- const result = initializeResource(instance, resource);
51
- return initializedResources.set(fullName, result), result;
52
- }
53
- function disposeResources(identity) {
54
- const resources = resourceCache.get(identity);
55
- if (resources)
56
- for (const resource of resources.values())
57
- resource.dispose();
58
- }
59
- function createAction(resource, actionDefinition) {
60
- return (dependencies, ...args) => {
61
- const instance = "state" in dependencies ? dependencies.instance : dependencies, { state } = "state" in dependencies ? dependencies : getOrCreateResource(dependencies, resource), actionContext = { instance, state };
62
- return actionDefinition(actionContext).bind(actionContext)(...args);
85
+ function createStoreInstance(instance, { name, getInitialState, initialize }) {
86
+ const state = createStoreState(getInitialState(instance), {
87
+ enabled: !!getEnv("DEV"),
88
+ name: `${name}-${instance.config.projectId}.${instance.config.dataset}`
89
+ }), dispose = initialize?.({ state, instance }), disposed = { current: !1 };
90
+ return {
91
+ state,
92
+ dispose: () => {
93
+ disposed.current || (disposed.current = !0, dispose?.());
94
+ },
95
+ isDisposed: () => disposed.current
63
96
  };
64
97
  }
65
- function createInternalAction(actionDefinition) {
66
- return (actionContext, ...args) => actionDefinition(actionContext).bind(actionContext)(...args);
98
+ function createActionBinder(keyFn) {
99
+ const instanceRegistry = /* @__PURE__ */ new Map(), storeRegistry = /* @__PURE__ */ new Map();
100
+ return function(storeDefinition, action) {
101
+ return function(instance, ...params) {
102
+ const keySuffix = keyFn(instance.config), compositeKey = storeDefinition.name + (keySuffix ? `:${keySuffix}` : "");
103
+ let instances = instanceRegistry.get(compositeKey);
104
+ instances || (instances = /* @__PURE__ */ new Set(), instanceRegistry.set(compositeKey, instances)), instances.has(instance.instanceId) || (instances.add(instance.instanceId), instance.onDispose(() => {
105
+ instances.delete(instance.instanceId), instances.size === 0 && (storeRegistry.get(compositeKey)?.dispose(), storeRegistry.delete(compositeKey), instanceRegistry.delete(compositeKey));
106
+ }));
107
+ let storeInstance = storeRegistry.get(compositeKey);
108
+ return storeInstance || (storeInstance = createStoreInstance(instance, storeDefinition), storeRegistry.set(compositeKey, storeInstance)), action({ instance, state: storeInstance.state }, ...params);
109
+ };
110
+ };
67
111
  }
68
- function createStateSourceAction(resource, options) {
69
- const selector = typeof options == "function" ? options : options.selector, subscribeHandler = options && "onSubscribe" in options ? options.onSubscribe : void 0, isEqual2 = options && "isEqual" in options ? options.isEqual ?? Object.is : Object.is;
70
- return createAction(resource, ({ state }) => function(...args) {
71
- const getCurrent = () => selector(state.get(), ...args), subscribe = (onStoreChanged) => {
72
- const cleanup = subscribeHandler?.(this, ...args), subscription = state.observable.pipe(
112
+ const bindActionByDataset = createActionBinder(({ projectId, dataset }) => {
113
+ if (!projectId || !dataset)
114
+ throw new Error("This API requires a project ID and dataset configured.");
115
+ return `${projectId}.${dataset}`;
116
+ }), bindActionGlobally = createActionBinder(() => "global");
117
+ function createStateSourceAction(options) {
118
+ const selector = typeof options == "function" ? options : options.selector, subscribeHandler = options && "onSubscribe" in options ? options.onSubscribe : void 0, isEqual2 = options && "isEqual" in options ? options.isEqual ?? Object.is : Object.is, selectorContextCache = /* @__PURE__ */ new WeakMap();
119
+ function stateSourceAction(context, ...params) {
120
+ const { state, instance } = context, getCurrent = () => {
121
+ const currentState = state.get();
122
+ if (typeof currentState != "object" || currentState === null)
123
+ throw new Error(
124
+ `Expected store state to be an object but got "${typeof currentState}" instead`
125
+ );
126
+ let instanceCache = selectorContextCache.get(currentState);
127
+ instanceCache || (instanceCache = /* @__PURE__ */ new WeakMap(), selectorContextCache.set(currentState, instanceCache));
128
+ let selectorContext = instanceCache.get(instance);
129
+ return selectorContext || (selectorContext = { state: currentState, instance }, instanceCache.set(instance, selectorContext)), selector(selectorContext, ...params);
130
+ }, subscribe = (onStoreChanged) => {
131
+ const cleanup = subscribeHandler?.(context, ...params), subscription = state.observable.pipe(
132
+ // Derive value from current state
73
133
  map(getCurrent),
134
+ // Filter unchanged values using custom equality check
74
135
  distinctUntilChanged(isEqual2),
75
- // skip the first emission because we only want to emit when the
76
- // value changes. `distinctUntilChanged` will always emit the first
77
- // the first value so we skip this emission
136
+ // Skip initial emission since we only want changes
78
137
  skip(1)
79
138
  ).subscribe({
80
139
  next: () => onStoreChanged?.(),
81
- // the convention is to have the selector throw the error so we
82
- // invoke onStoreChanged on error as well. this will cause the
83
- // observable code path below to emit an error because the selector
84
- // will throw and that will be used to emit an .error on the observer
140
+ // Propagate selector errors to both subscription types
85
141
  error: () => onStoreChanged?.()
86
142
  });
87
143
  return () => {
@@ -102,96 +158,91 @@ function createStateSourceAction(resource, options) {
102
158
  subscribe,
103
159
  observable
104
160
  };
105
- });
106
- }
107
- const DEFAULT_BASE = "http://localhost", AUTH_CODE_PARAM = "sid", DEFAULT_API_VERSION$1 = "2021-06-07", REQUEST_TAG_PREFIX = "sanity.sdk.auth", refreshStampedToken = createInternalAction(
108
- ({ state }) => {
109
- const { clientFactory, apiHost, storageArea, storageKey } = state.get().options, refreshToken$ = state.observable.pipe(
110
- map(({ authState }) => authState),
111
- filter(
112
- (authState) => authState.type === AuthStateType.LOGGED_IN
113
- ),
114
- distinctUntilChanged(),
115
- filter((authState) => authState.token.includes("-st")),
116
- // Ensure we only try to refresh stamped tokens
117
- switchMap(
118
- (authState) => interval(10 * 60 * 1e3).pipe(
119
- takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),
120
- map(() => authState.token),
121
- distinctUntilChanged(),
122
- map(
123
- (token) => clientFactory({
124
- apiVersion: DEFAULT_API_VERSION$1,
125
- requestTagPrefix: "sdk.token-refresh",
126
- useProjectHostname: !1,
127
- token,
128
- ignoreBrowserTokenWarning: !0,
129
- ...apiHost && { apiHost }
130
- })
131
- ),
132
- switchMap(
133
- (client) => client.observable.request({
134
- uri: "auth/refresh-token",
135
- method: "POST",
136
- body: {
137
- token: authState.token
138
- }
139
- })
140
- )
141
- )
142
- )
143
- );
144
- return function() {
145
- return refreshToken$.subscribe({
146
- next: (response) => {
147
- state.set("setRefreshStampedToken", (prev) => ({
148
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, token: response.token } : prev.authState
149
- })), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
150
- },
151
- error: (error) => {
152
- state.set("setRefreshStampedTokenError", { authState: { type: AuthStateType.ERROR, error } });
153
- }
154
- });
155
- };
156
161
  }
157
- ), subscribeToStateAndFetchCurrentUser = createInternalAction(
158
- ({ state }) => {
159
- const { clientFactory, apiHost } = state.get().options, currentUser$ = state.observable.pipe(
160
- map(({ authState }) => authState),
161
- filter(
162
- (authState) => authState.type === AuthStateType.LOGGED_IN && !authState.currentUser
163
- ),
164
- map((authState) => authState.token),
165
- distinctUntilChanged()
166
- ).pipe(
167
- map(
168
- (token) => clientFactory({
169
- apiVersion: DEFAULT_API_VERSION$1,
170
- requestTagPrefix: REQUEST_TAG_PREFIX,
171
- token,
172
- ignoreBrowserTokenWarning: !0,
173
- useProjectHostname: !1,
174
- ...apiHost && { apiHost }
175
- })
176
- ),
177
- switchMap(
178
- (client) => client.observable.request({ uri: "/users/me", method: "GET" })
162
+ return stateSourceAction;
163
+ }
164
+ const DEFAULT_BASE = "http://localhost", AUTH_CODE_PARAM = "sid", DEFAULT_API_VERSION$1 = "2021-06-07", REQUEST_TAG_PREFIX = "sanity.sdk.auth", refreshStampedToken = ({ state }) => {
165
+ const { clientFactory, apiHost, storageArea, storageKey } = state.get().options, refreshInterval = 12 * 60 * 60 * 1e3;
166
+ return state.observable.pipe(
167
+ map(({ authState }) => authState),
168
+ filter(
169
+ (authState) => authState.type === AuthStateType.LOGGED_IN
170
+ ),
171
+ distinctUntilChanged(),
172
+ filter((authState) => authState.token.includes("-st")),
173
+ // Ensure we only try to refresh stamped tokens
174
+ switchMap(
175
+ (authState) => interval(refreshInterval).pipe(
176
+ takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),
177
+ map(() => authState.token),
178
+ distinctUntilChanged(),
179
+ map(
180
+ (token) => clientFactory({
181
+ apiVersion: DEFAULT_API_VERSION$1,
182
+ requestTagPrefix: "sdk.token-refresh",
183
+ useProjectHostname: !1,
184
+ token,
185
+ ignoreBrowserTokenWarning: !0,
186
+ ...apiHost && { apiHost }
187
+ })
188
+ ),
189
+ switchMap(
190
+ (client) => client.observable.request({
191
+ uri: "auth/refresh-token",
192
+ method: "POST",
193
+ body: {
194
+ token: authState.token
195
+ }
196
+ })
197
+ )
179
198
  )
180
- );
181
- return function() {
182
- return currentUser$.subscribe({
183
- next: (currentUser) => {
184
- state.set("setCurrentUser", (prev) => ({
185
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, currentUser } : prev.authState
186
- }));
187
- },
188
- error: (error) => {
189
- state.set("setError", { authState: { type: AuthStateType.ERROR, error } });
190
- }
191
- });
192
- };
193
- }
194
- );
199
+ )
200
+ ).subscribe({
201
+ next: (response) => {
202
+ state.set("setRefreshStampedToken", (prev) => ({
203
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, token: response.token } : prev.authState
204
+ })), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
205
+ },
206
+ error: (error) => {
207
+ state.set("setRefreshStampedTokenError", { authState: { type: AuthStateType.ERROR, error } });
208
+ }
209
+ });
210
+ }, subscribeToStateAndFetchCurrentUser = ({
211
+ state
212
+ }) => {
213
+ const { clientFactory, apiHost } = state.get().options;
214
+ return state.observable.pipe(
215
+ map(({ authState }) => authState),
216
+ filter(
217
+ (authState) => authState.type === AuthStateType.LOGGED_IN && !authState.currentUser
218
+ ),
219
+ map((authState) => authState.token),
220
+ distinctUntilChanged()
221
+ ).pipe(
222
+ map(
223
+ (token) => clientFactory({
224
+ apiVersion: DEFAULT_API_VERSION$1,
225
+ requestTagPrefix: REQUEST_TAG_PREFIX,
226
+ token,
227
+ ignoreBrowserTokenWarning: !0,
228
+ useProjectHostname: !1,
229
+ ...apiHost && { apiHost }
230
+ })
231
+ ),
232
+ switchMap(
233
+ (client) => client.observable.request({ uri: "/users/me", method: "GET" })
234
+ )
235
+ ).subscribe({
236
+ next: (currentUser) => {
237
+ state.set("setCurrentUser", (prev) => ({
238
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, currentUser } : prev.authState
239
+ }));
240
+ },
241
+ error: (error) => {
242
+ state.set("setError", { authState: { type: AuthStateType.ERROR, error } });
243
+ }
244
+ });
245
+ };
195
246
  function getAuthCode(callbackUrl, locationHref) {
196
247
  const loc = new URL(locationHref, DEFAULT_BASE), callbackLocation = callbackUrl ? new URL(callbackUrl, DEFAULT_BASE) : void 0, callbackLocationMatches = callbackLocation ? loc.pathname.toLowerCase().startsWith(callbackLocation.pathname.toLowerCase()) : !0, authCode = new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM) || new URLSearchParams(loc.search).get(AUTH_CODE_PARAM);
197
248
  return authCode && callbackLocationMatches ? authCode : null;
@@ -226,24 +277,22 @@ function getDefaultLocation() {
226
277
  return DEFAULT_BASE;
227
278
  }
228
279
  }
229
- const subscribeToStorageEventsAndSetToken = createInternalAction(
230
- ({ state }) => {
231
- const { storageArea, storageKey } = state.get().options, tokenFromStorage$ = defer(getStorageEvents).pipe(
232
- filter(
233
- (e3) => e3.storageArea === storageArea && e3.key === storageKey
234
- ),
235
- map(() => getTokenFromStorage(storageArea, storageKey)),
236
- distinctUntilChanged()
237
- );
238
- return function() {
239
- return tokenFromStorage$.subscribe((token) => {
240
- state.set("updateTokenFromStorageEvent", {
241
- authState: token ? { type: AuthStateType.LOGGED_IN, token, currentUser: null } : { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
242
- });
243
- });
244
- };
245
- }
246
- );
280
+ const subscribeToStorageEventsAndSetToken = ({
281
+ state
282
+ }) => {
283
+ const { storageArea, storageKey } = state.get().options;
284
+ return defer(getStorageEvents).pipe(
285
+ filter(
286
+ (e3) => e3.storageArea === storageArea && e3.key === storageKey
287
+ ),
288
+ map(() => getTokenFromStorage(storageArea, storageKey)),
289
+ distinctUntilChanged()
290
+ ).subscribe((token) => {
291
+ state.set("updateTokenFromStorageEvent", {
292
+ authState: token ? { type: AuthStateType.LOGGED_IN, token, currentUser: null } : { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
293
+ });
294
+ });
295
+ };
247
296
  let tokenRefresherRunning = !1;
248
297
  const authStore = {
249
298
  name: "Auth",
@@ -257,12 +306,20 @@ const authStore = {
257
306
  initialLocationHref = getDefaultLocation(),
258
307
  storageArea = getDefaultStorage()
259
308
  } = instance.config.auth ?? {}, storageKey = "__sanity_auth_token";
309
+ let loginDomain = "https://www.sanity.io";
310
+ try {
311
+ apiHost && new URL(apiHost).hostname.endsWith(".sanity.work") && (loginDomain = "https://www.sanity.work");
312
+ } catch {
313
+ }
314
+ const loginUrl = new URL("/login", loginDomain);
315
+ loginUrl.searchParams.set("origin", initialLocationHref), loginUrl.searchParams.set("type", "stampedToken"), loginUrl.searchParams.set("withSid", "true");
260
316
  let authState;
261
317
  const token = getTokenFromStorage(storageArea, storageKey);
262
318
  return providedToken ? authState = { type: AuthStateType.LOGGED_IN, token: providedToken, currentUser: null } : getAuthCode(callbackUrl, initialLocationHref) ? authState = { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 } : token ? authState = { type: AuthStateType.LOGGED_IN, token, currentUser: null } : authState = { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }, {
263
319
  authState,
264
320
  options: {
265
321
  apiHost,
322
+ loginUrl: loginUrl.toString(),
266
323
  callbackUrl,
267
324
  customProviders,
268
325
  providedToken,
@@ -273,61 +330,36 @@ const authStore = {
273
330
  }
274
331
  };
275
332
  },
276
- initialize() {
277
- const stateSubscription = subscribeToStateAndFetchCurrentUser(this);
278
- let storageEventsSubscription;
279
- this.state.get().options?.storageArea && (storageEventsSubscription = subscribeToStorageEventsAndSetToken(this));
280
- let refreshStampedTokenSubscription;
281
- return tokenRefresherRunning || (tokenRefresherRunning = !0, refreshStampedTokenSubscription = refreshStampedToken(this)), () => {
282
- stateSubscription.unsubscribe(), storageEventsSubscription?.unsubscribe(), refreshStampedTokenSubscription?.unsubscribe();
333
+ initialize(context) {
334
+ const subscriptions = [];
335
+ return subscriptions.push(subscribeToStateAndFetchCurrentUser(context)), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context)), tokenRefresherRunning || (tokenRefresherRunning = !0, subscriptions.push(refreshStampedToken(context))), () => {
336
+ for (const subscription of subscriptions)
337
+ subscription.unsubscribe();
283
338
  };
284
339
  }
285
- }, getCurrentUserState = createStateSourceAction(
340
+ }, getCurrentUserState = bindActionGlobally(
286
341
  authStore,
287
- ({ authState }) => authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null
288
- ), getTokenState = createStateSourceAction(
342
+ createStateSourceAction(
343
+ ({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null
344
+ )
345
+ ), getTokenState = bindActionGlobally(
289
346
  authStore,
290
- ({ authState }) => authState.type === AuthStateType.LOGGED_IN ? authState.token : null
291
- ), getLoginUrlsState = createStateSourceAction(
347
+ createStateSourceAction(
348
+ ({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.token : null
349
+ )
350
+ ), getLoginUrlState = bindActionGlobally(
292
351
  authStore,
293
- ({ providers }) => providers ?? null
294
- ), getAuthState = createStateSourceAction(authStore, ({ authState }) => authState), getDashboardOrganizationId = createStateSourceAction(
352
+ createStateSourceAction(({ state: { options } }) => options.loginUrl)
353
+ ), getAuthState = bindActionGlobally(
295
354
  authStore,
296
- ({ dashboardContext }) => dashboardContext?.orgId
297
- ), fetchLoginUrls = createAction(authStore, ({ state }) => {
298
- const { callbackUrl, clientFactory, apiHost, customProviders } = state.get().options, client = clientFactory({
299
- apiVersion: DEFAULT_API_VERSION$1,
300
- requestTagPrefix: REQUEST_TAG_PREFIX,
301
- useProjectHostname: !1,
302
- ...apiHost && { apiHost }
303
- });
304
- return async function() {
305
- const cachedProviders = state.get().providers;
306
- if (cachedProviders) return cachedProviders;
307
- const { providers: defaultProviders } = await client.request({
308
- uri: "/auth/providers",
309
- tag: "fetch-providers"
310
- });
311
- let providers;
312
- if (typeof customProviders == "function")
313
- providers = await customProviders(defaultProviders);
314
- else if (!customProviders?.length)
315
- providers = defaultProviders;
316
- else {
317
- const customProviderUrls = new Set(customProviders.map((p2) => p2.url));
318
- providers = defaultProviders.filter((official) => !customProviderUrls.has(official.url)).concat(customProviders);
319
- }
320
- const configuredProviders = providers.map((provider) => {
321
- const url = new URL(provider.url), origin = new URL(
322
- callbackUrl ? new URL(callbackUrl, new URL(getDefaultLocation()).origin).toString() : getDefaultLocation()
323
- ), hashParams = new URLSearchParams(origin.hash.slice(1));
324
- return hashParams.delete("sid"), origin.hash = hashParams.toString(), origin.searchParams.delete("sid"), origin.searchParams.delete("url"), origin.searchParams.delete("error"), url.searchParams.set("origin", origin.toString()), url.searchParams.set("withSid", "true"), url.searchParams.set("type", "stampedToken"), { ...provider, url: url.toString() };
325
- });
326
- return state.set("fetchedLoginUrls", { providers: configuredProviders }), configuredProviders;
327
- };
328
- }), handleAuthCallback = createAction(authStore, ({ state }) => {
329
- const { providedToken, callbackUrl, clientFactory, apiHost, storageArea, storageKey } = state.get().options;
330
- return async function(locationHref = getDefaultLocation()) {
355
+ createStateSourceAction(({ state: { authState } }) => authState)
356
+ ), getDashboardOrganizationId = bindActionGlobally(
357
+ authStore,
358
+ createStateSourceAction(({ state: { dashboardContext } }) => dashboardContext?.orgId)
359
+ ), handleAuthCallback = bindActionGlobally(
360
+ authStore,
361
+ async ({ state }, locationHref = getDefaultLocation()) => {
362
+ const { providedToken, callbackUrl, clientFactory, apiHost, storageArea, storageKey } = state.get().options;
331
363
  if (providedToken) return !1;
332
364
  const { authState } = state.get();
333
365
  if (authState.type === AuthStateType.LOGGING_IN && authState.isExchangingToken) return !1;
@@ -364,116 +396,484 @@ const authStore = {
364
396
  } catch (error) {
365
397
  return state.set("exchangeSessionForTokenError", { authState: { type: AuthStateType.ERROR, error } }), !1;
366
398
  }
367
- };
368
- }), logout = createAction(authStore, ({ state }) => {
399
+ }
400
+ ), logout = bindActionGlobally(authStore, async ({ state }) => {
369
401
  const { clientFactory, apiHost, providedToken, storageArea, storageKey } = state.get().options;
370
- return async function() {
371
- if (providedToken) return;
372
- const { authState } = state.get();
373
- if (authState.type === AuthStateType.LOGGED_OUT && authState.isDestroyingSession) return;
374
- const token = authState.type === AuthStateType.LOGGED_IN && authState.token;
375
- try {
376
- token && (state.set("loggingOut", {
377
- authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !0 }
378
- }), await clientFactory({
379
- token,
380
- requestTagPrefix: REQUEST_TAG_PREFIX,
381
- apiVersion: DEFAULT_API_VERSION$1,
382
- ...apiHost && { apiHost },
383
- useProjectHostname: !1
384
- }).request({ uri: "/auth/logout", method: "POST" }));
385
- } finally {
386
- state.set("logoutSuccess", {
387
- authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
388
- }), storageArea?.removeItem(storageKey);
389
- }
390
- };
391
- });
392
- function getResourceId(documentResourceId) {
393
- if (documentResourceId)
394
- return documentResourceId.split(":")[1];
395
- }
396
- function parseBracketContent(content) {
397
- const rangeMatch = content.match(/^(\d*):(\d*)$/);
398
- if (rangeMatch) {
399
- const startStr = rangeMatch[1], endStr = rangeMatch[2], start = startStr === "" ? "" : parseInt(startStr, 10), end = endStr === "" ? "" : parseInt(endStr, 10);
400
- return [start, end];
402
+ if (providedToken) return;
403
+ const { authState } = state.get();
404
+ if (authState.type === AuthStateType.LOGGED_OUT && authState.isDestroyingSession) return;
405
+ const token = authState.type === AuthStateType.LOGGED_IN && authState.token;
406
+ try {
407
+ token && (state.set("loggingOut", {
408
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !0 }
409
+ }), await clientFactory({
410
+ token,
411
+ requestTagPrefix: REQUEST_TAG_PREFIX,
412
+ apiVersion: DEFAULT_API_VERSION$1,
413
+ ...apiHost && { apiHost },
414
+ useProjectHostname: !1
415
+ }).request({ uri: "/auth/logout", method: "POST" }));
416
+ } finally {
417
+ state.set("logoutSuccess", {
418
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
419
+ }), storageArea?.removeItem(storageKey);
401
420
  }
402
- const keyedMatch = content.match(/^_key==["'](.+)["']$/);
403
- if (keyedMatch)
404
- return { _key: keyedMatch[1] };
405
- const index = parseInt(content, 10);
406
- if (!isNaN(index))
407
- return index;
408
- throw new Error(`Invalid bracket content: \u201C[${content}]\u201D`);
409
- }
410
- function parseSegment(segment) {
411
- const segments = [];
412
- let idx = 0;
413
- function pushIfNotEmpty(text) {
414
- text && segments.push(text);
421
+ }), DEFAULT_API_VERSION = "2024-11-12", DEFAULT_REQUEST_TAG_PREFIX = "sanity.sdk", allowedKeys = Object.keys({
422
+ apiHost: null,
423
+ useCdn: null,
424
+ token: null,
425
+ perspective: null,
426
+ proxy: null,
427
+ withCredentials: null,
428
+ timeout: null,
429
+ maxRetries: null,
430
+ dataset: null,
431
+ projectId: null,
432
+ scope: null,
433
+ apiVersion: null,
434
+ requestTagPrefix: null,
435
+ useProjectHostname: null
436
+ }), DEFAULT_CLIENT_CONFIG = {
437
+ apiVersion: DEFAULT_API_VERSION,
438
+ useCdn: !1,
439
+ ignoreBrowserTokenWarning: !0,
440
+ allowReconfigure: !1,
441
+ requestTagPrefix: DEFAULT_REQUEST_TAG_PREFIX
442
+ }, clientStore = {
443
+ name: "clientStore",
444
+ getInitialState: (instance) => ({
445
+ clients: {},
446
+ token: getTokenState(instance).getCurrent()
447
+ }),
448
+ initialize(context) {
449
+ const subscription = listenToToken(context);
450
+ return () => subscription.unsubscribe();
415
451
  }
416
- for (; idx < segment.length; ) {
417
- const openIndex = segment.indexOf("[", idx);
418
- if (openIndex === -1) {
419
- const remaining = segment.slice(idx);
420
- pushIfNotEmpty(remaining);
421
- break;
452
+ }, listenToToken = ({ instance, state }) => getTokenState(instance).observable.subscribe((token) => {
453
+ state.set("setTokenAndResetClients", { token, clients: {} });
454
+ }), getClientConfigKey = (options) => JSON.stringify(pick(options, ...allowedKeys)), getClient = bindActionGlobally(
455
+ clientStore,
456
+ ({ state, instance }, options) => {
457
+ const disallowedKeys = Object.keys(options).filter((key2) => !allowedKeys.includes(key2));
458
+ if (disallowedKeys.length > 0) {
459
+ const listFormatter = new Intl.ListFormat("en", { style: "long", type: "conjunction" });
460
+ throw new Error(
461
+ `The client options provided contains unsupported properties: ${listFormatter.format(disallowedKeys)}. Allowed keys are: ${listFormatter.format(allowedKeys)}.`
462
+ );
422
463
  }
423
- const before = segment.slice(idx, openIndex);
424
- pushIfNotEmpty(before);
425
- const closeIndex = segment.indexOf("]", openIndex);
426
- if (closeIndex === -1)
427
- throw new Error(`Unmatched "[" in segment: "${segment}"`);
428
- const bracketContent = segment.slice(openIndex + 1, closeIndex);
429
- segments.push(parseBracketContent(bracketContent)), idx = closeIndex + 1;
464
+ const { token, clients } = state.get(), projectId = options.projectId ?? instance.config.projectId, dataset = options.dataset ?? instance.config.dataset, apiHost = options.apiHost ?? instance.config.auth?.apiHost, effectiveOptions = {
465
+ ...DEFAULT_CLIENT_CONFIG,
466
+ ...(options.scope === "global" || !projectId) && { useProjectHostname: !1 },
467
+ ...token && { token },
468
+ ...options,
469
+ ...projectId && { projectId },
470
+ ...dataset && { dataset },
471
+ ...apiHost && { apiHost }
472
+ }, key = getClientConfigKey(effectiveOptions);
473
+ if (clients[key]) return clients[key];
474
+ const client = createClient(effectiveOptions);
475
+ return state.set("addClient", (prev) => ({ clients: { ...prev.clients, [key]: client } })), client;
430
476
  }
431
- return segments;
432
- }
433
- function parsePath(path) {
434
- const result = [];
435
- let buffer = "", bracketDepth = 0;
436
- for (let i2 = 0; i2 < path.length; i2++) {
437
- const ch = path[i2];
438
- ch === "[" ? (bracketDepth++, buffer += ch) : ch === "]" ? (bracketDepth--, buffer += ch) : ch === "." && bracketDepth === 0 ? buffer && (result.push(...parseSegment(buffer)), buffer = "") : buffer += ch;
477
+ ), getClientState = bindActionGlobally(
478
+ clientStore,
479
+ createStateSourceAction(({ instance }, options) => getClient(instance, options))
480
+ ), destroyController$1 = ({ state }) => {
481
+ const { controller } = state.get();
482
+ controller && (controller.destroy(), state.set("destroyController", {
483
+ controller: null,
484
+ channels: /* @__PURE__ */ new Map()
485
+ }));
486
+ }, getOrCreateChannel$1 = ({ state }, options) => {
487
+ const controller = state.get().controller;
488
+ if (!controller)
489
+ throw new Error("Controller must be initialized before using or creating channels");
490
+ const channels = state.get().channels, existing = channels.get(options.name);
491
+ if (existing) {
492
+ if (!isEqual(existing.options, options))
493
+ throw new Error(`Channel "${options.name}" already exists with different options`);
494
+ return state.set("incrementChannelRefCount", {
495
+ channels: new Map(channels).set(options.name, {
496
+ ...existing,
497
+ refCount: existing.refCount + 1
498
+ })
499
+ }), existing.channel.start(), existing.channel;
439
500
  }
440
- return buffer && result.push(...parseSegment(buffer)), result;
441
- }
442
- function stringifyPath(path) {
443
- let result = "";
444
- for (let i2 = 0; i2 < path.length; i2++) {
445
- const segment = path[i2];
446
- if (typeof segment == "string")
447
- result && (result += "."), result += segment;
448
- else if (typeof segment == "number")
449
- result += `[${segment}]`;
450
- else if (Array.isArray(segment)) {
451
- const [start, end] = segment, startStr = start === "" ? "" : String(start), endStr = end === "" ? "" : String(end);
452
- result += `[${startStr}:${endStr}]`;
453
- } else
454
- result += `[_key=="${segment._key}"]`;
501
+ const channel = controller.createChannel(options);
502
+ return channel.start(), state.set("createChannel", {
503
+ channels: new Map(channels).set(options.name, {
504
+ channel,
505
+ options,
506
+ refCount: 1
507
+ })
508
+ }), channel;
509
+ }, getOrCreateController$1 = ({ state, instance }, targetOrigin) => {
510
+ const { controller, controllerOrigin } = state.get();
511
+ if (controller && controllerOrigin === targetOrigin)
512
+ return controller;
513
+ controller && destroyController$1({ state });
514
+ const newController = createController({ targetOrigin });
515
+ return state.set("initializeController", {
516
+ controllerOrigin: targetOrigin,
517
+ controller: newController
518
+ }), newController;
519
+ }, releaseChannel$1 = ({ state }, name) => {
520
+ const channels = state.get().channels, channelEntry = channels.get(name);
521
+ if (channelEntry) {
522
+ const newRefCount = channelEntry.refCount === 0 ? 0 : channelEntry.refCount - 1;
523
+ newRefCount === 0 ? (channelEntry.channel.stop(), channels.delete(name), state.set("releaseChannel", { channels: new Map(channels) })) : state.set("releaseChannel", {
524
+ channels: new Map(channels).set(name, {
525
+ ...channelEntry,
526
+ refCount: newRefCount
527
+ })
528
+ });
455
529
  }
456
- return result;
457
- }
458
- function jsonMatch(input, pathExpression) {
459
- return matchRecursive(input, parsePath(pathExpression), []);
460
- }
461
- function matchRecursive(value, path, currentPath) {
462
- if (path.length === 0)
463
- return [{ value, path: currentPath }];
464
- const [head, ...rest] = path;
465
- if (typeof head == "string") {
466
- if (value && typeof value == "object" && !Array.isArray(value)) {
467
- const nextValue = value[head];
468
- return matchRecursive(nextValue, rest, [...currentPath, head]);
469
- }
470
- return [];
530
+ }, comlinkControllerStore = {
531
+ name: "connectionStore",
532
+ getInitialState: () => ({
533
+ controller: null,
534
+ controllerOrigin: null,
535
+ channels: /* @__PURE__ */ new Map()
536
+ }),
537
+ initialize({ instance }) {
538
+ return () => {
539
+ destroyController(instance);
540
+ };
471
541
  }
472
- if (typeof head == "number") {
473
- if (Array.isArray(value)) {
474
- const nextValue = value.at(head);
475
- return matchRecursive(nextValue, rest, [...currentPath, head]);
476
- }
542
+ }, destroyController = bindActionGlobally(
543
+ comlinkControllerStore,
544
+ destroyController$1
545
+ ), getOrCreateChannel = bindActionGlobally(
546
+ comlinkControllerStore,
547
+ getOrCreateChannel$1
548
+ ), getOrCreateController = bindActionGlobally(
549
+ comlinkControllerStore,
550
+ getOrCreateController$1
551
+ ), releaseChannel = bindActionGlobally(comlinkControllerStore, releaseChannel$1), getOrCreateNode$1 = ({ state }, options) => {
552
+ const nodes = state.get().nodes, existing = nodes.get(options.name);
553
+ if (existing) {
554
+ if (!isEqual(existing.options, options))
555
+ throw new Error(`Node "${options.name}" already exists with different options`);
556
+ return state.set("incrementNodeRefCount", {
557
+ nodes: new Map(nodes).set(options.name, {
558
+ ...existing,
559
+ refCount: existing.refCount + 1
560
+ })
561
+ }), existing.node.start(), existing.node;
562
+ }
563
+ const node = createNode(options);
564
+ return node.start(), nodes.set(options.name, { node, options, refCount: 1 }), state.set("createNode", { nodes }), node;
565
+ }, releaseNode$1 = ({ state }, name) => {
566
+ const nodes = state.get().nodes, nodeEntry = nodes.get(name);
567
+ if (nodeEntry) {
568
+ const newRefCount = nodeEntry.refCount === 0 ? 0 : nodeEntry.refCount - 1;
569
+ newRefCount === 0 ? (nodeEntry.node.stop(), nodes.delete(name), state.set("releaseNode", { nodes: new Map(nodes) })) : state.set("releaseNode", {
570
+ nodes: new Map(nodes).set(name, {
571
+ ...nodeEntry,
572
+ refCount: newRefCount
573
+ })
574
+ });
575
+ }
576
+ }, comlinkNodeStore = {
577
+ name: "nodeStore",
578
+ getInitialState: () => ({
579
+ nodes: /* @__PURE__ */ new Map()
580
+ }),
581
+ initialize({ state }) {
582
+ return () => {
583
+ state.get().nodes.forEach(({ node }) => {
584
+ node.stop();
585
+ });
586
+ };
587
+ }
588
+ }, releaseNode = bindActionGlobally(comlinkNodeStore, releaseNode$1), getOrCreateNode = bindActionGlobally(comlinkNodeStore, getOrCreateNode$1);
589
+ function createFetcherStore({
590
+ name,
591
+ fetcher: getObservable,
592
+ getKey,
593
+ fetchThrottleInternal = 1e3,
594
+ stateExpirationDelay = 5e3
595
+ }) {
596
+ const store = {
597
+ name,
598
+ getInitialState: () => ({
599
+ stateByParams: {}
600
+ }),
601
+ initialize: (context) => {
602
+ const subscription = subscribeToSubscriptionsAndFetch(context);
603
+ return () => subscription.unsubscribe();
604
+ }
605
+ }, subscribeToSubscriptionsAndFetch = ({
606
+ state
607
+ }) => state.observable.pipe(
608
+ // Map the state to an array of [serialized, entry] pairs.
609
+ switchMap$1((s2) => {
610
+ const entries = Object.entries(s2.stateByParams);
611
+ return entries.length > 0 ? from(entries) : EMPTY;
612
+ }),
613
+ // Group by the serialized key.
614
+ groupBy(([key]) => key),
615
+ mergeMap(
616
+ (group$) => group$.pipe(
617
+ // Emit an initial value for pairwise comparisons.
618
+ startWith([group$.key, void 0]),
619
+ pairwise(),
620
+ // Trigger only when the subscriptions array grows.
621
+ filter$1(([[, prevEntry], [, currEntry]]) => {
622
+ const prevSubs = prevEntry?.subscriptions ?? [];
623
+ return (currEntry?.subscriptions ?? []).length > prevSubs.length;
624
+ }),
625
+ map$1(([, [, currEntry]]) => currEntry),
626
+ // Only trigger if we haven't fetched recently.
627
+ filter$1((entry) => {
628
+ const lastFetch = entry?.lastFetchInitiatedAt;
629
+ return lastFetch ? Date.now() - new Date(lastFetch).getTime() >= fetchThrottleInternal : !0;
630
+ }),
631
+ switchMap$1((entry) => entry ? (state.set("setLastFetchInitiatedAt", (prev) => ({
632
+ stateByParams: {
633
+ ...prev.stateByParams,
634
+ [entry.key]: {
635
+ ...entry,
636
+ ...prev.stateByParams[entry.key],
637
+ lastFetchInitiatedAt: (/* @__PURE__ */ new Date()).toISOString()
638
+ }
639
+ }
640
+ })), getObservable(entry.instance)(...entry.params).pipe(
641
+ // the `createStateSourceAction` util requires the update
642
+ // to
643
+ delay(0, asapScheduler),
644
+ tap(
645
+ (data) => state.set("setData", (prev) => ({
646
+ stateByParams: {
647
+ ...prev.stateByParams,
648
+ [entry.key]: {
649
+ ...omit(entry, "error"),
650
+ ...omit(prev.stateByParams[entry.key], "error"),
651
+ data
652
+ }
653
+ }
654
+ }))
655
+ ),
656
+ catchError((error) => (state.set("setError", (prev) => ({
657
+ stateByParams: {
658
+ ...prev.stateByParams,
659
+ [entry.key]: {
660
+ ...entry,
661
+ ...prev.stateByParams[entry.key],
662
+ error
663
+ }
664
+ }
665
+ })), EMPTY))
666
+ )) : EMPTY)
667
+ )
668
+ )
669
+ ).subscribe({
670
+ error: (error) => state.set("setError", { error })
671
+ }), getState = bindActionGlobally(
672
+ store,
673
+ createStateSourceAction({
674
+ selector: ({
675
+ instance,
676
+ state: { stateByParams, error }
677
+ }, ...params) => {
678
+ if (error) throw error;
679
+ const key = getKey(instance, ...params), entry = stateByParams[key];
680
+ if (entry?.error) throw entry.error;
681
+ return entry?.data;
682
+ },
683
+ onSubscribe: ({ instance, state }, ...params) => {
684
+ const subscriptionId = insecureRandomId(), key = getKey(instance, ...params);
685
+ return state.set("addSubscription", (prev) => ({
686
+ stateByParams: {
687
+ ...prev.stateByParams,
688
+ [key]: {
689
+ ...prev.stateByParams[key],
690
+ instance,
691
+ key,
692
+ params: prev.stateByParams[key]?.params || params,
693
+ subscriptions: [...prev.stateByParams[key]?.subscriptions || [], subscriptionId]
694
+ }
695
+ }
696
+ })), () => {
697
+ setTimeout(() => {
698
+ state.set("removeSubscription", (prev) => {
699
+ const entry = prev.stateByParams[key];
700
+ if (!entry) return prev;
701
+ const newSubs = (entry.subscriptions || []).filter((id) => id !== subscriptionId);
702
+ return newSubs.length === 0 ? { stateByParams: omit(prev.stateByParams, key) } : {
703
+ stateByParams: {
704
+ ...prev.stateByParams,
705
+ [key]: {
706
+ ...entry,
707
+ subscriptions: newSubs
708
+ }
709
+ }
710
+ };
711
+ });
712
+ }, stateExpirationDelay);
713
+ };
714
+ }
715
+ })
716
+ ), resolveState = bindActionGlobally(
717
+ store,
718
+ ({ instance }, ...params) => firstValueFrom(getState(instance, ...params).observable.pipe(first((i2) => i2 !== void 0)))
719
+ );
720
+ return { getState, resolveState };
721
+ }
722
+ const API_VERSION$5 = "v2025-02-19", datasets = createFetcherStore({
723
+ name: "Datasets",
724
+ getKey: (instance, options) => {
725
+ const projectId = options?.projectId ?? instance.config.projectId;
726
+ if (!projectId)
727
+ throw new Error("A projectId is required to use the project API.");
728
+ return projectId;
729
+ },
730
+ fetcher: (instance) => (options) => getClientState(instance, {
731
+ apiVersion: API_VERSION$5,
732
+ // non-null assertion is fine because we check above
733
+ projectId: options?.projectId ?? instance.config.projectId,
734
+ useProjectHostname: !0
735
+ }).observable.pipe(switchMap((client) => client.observable.datasets.list()))
736
+ }), getDatasetsState = datasets.getState, resolveDatasets = datasets.resolveState, isSanityMutatePatch = (value) => !(typeof value != "object" || !value || !("type" in value) || typeof value.type != "string" || value.type !== "patch" || !("id" in value) || typeof value.id != "string" || !("patches" in value) || !Array.isArray(value.patches));
737
+ function createDocument(doc) {
738
+ return {
739
+ type: "document.create",
740
+ ...doc,
741
+ ...doc.documentId && { documentId: getPublishedId(doc.documentId) }
742
+ };
743
+ }
744
+ function deleteDocument(doc) {
745
+ return {
746
+ type: "document.delete",
747
+ ...doc,
748
+ documentId: getPublishedId(doc.documentId)
749
+ };
750
+ }
751
+ function convertSanityMutatePatch(sanityPatchMutation) {
752
+ return SanityEncoder.encode(sanityPatchMutation).map((i2) => {
753
+ const copy = { ...i2.patch };
754
+ return "id" in copy && delete copy.id, copy;
755
+ });
756
+ }
757
+ function editDocument(doc, patches) {
758
+ if (isSanityMutatePatch(patches)) {
759
+ const converted = convertSanityMutatePatch(patches) ?? [];
760
+ return {
761
+ ...doc,
762
+ type: "document.edit",
763
+ documentId: getPublishedId(doc.documentId),
764
+ patches: converted
765
+ };
766
+ }
767
+ return {
768
+ ...doc,
769
+ type: "document.edit",
770
+ documentId: getPublishedId(doc.documentId),
771
+ ...patches && { patches: Array.isArray(patches) ? patches : [patches] }
772
+ };
773
+ }
774
+ function publishDocument(doc) {
775
+ return {
776
+ type: "document.publish",
777
+ ...doc,
778
+ documentId: getPublishedId(doc.documentId)
779
+ };
780
+ }
781
+ function unpublishDocument(doc) {
782
+ return {
783
+ type: "document.unpublish",
784
+ ...doc,
785
+ documentId: getPublishedId(doc.documentId)
786
+ };
787
+ }
788
+ function discardDocument(doc) {
789
+ return {
790
+ type: "document.discard",
791
+ ...doc,
792
+ documentId: getPublishedId(doc.documentId)
793
+ };
794
+ }
795
+ const DOCUMENT_STATE_CLEAR_DELAY = 1e3, INITIAL_OUTGOING_THROTTLE_TIME = 1e3, API_VERSION$4 = "vX";
796
+ function parseBracketContent(content) {
797
+ const rangeMatch = content.match(/^(\d*):(\d*)$/);
798
+ if (rangeMatch) {
799
+ const startStr = rangeMatch[1], endStr = rangeMatch[2], start = startStr === "" ? "" : parseInt(startStr, 10), end = endStr === "" ? "" : parseInt(endStr, 10);
800
+ return [start, end];
801
+ }
802
+ const keyedMatch = content.match(/^_key==["'](.+)["']$/);
803
+ if (keyedMatch)
804
+ return { _key: keyedMatch[1] };
805
+ const index = parseInt(content, 10);
806
+ if (!isNaN(index))
807
+ return index;
808
+ throw new Error(`Invalid bracket content: \u201C[${content}]\u201D`);
809
+ }
810
+ function parseSegment(segment) {
811
+ const segments = [];
812
+ let idx = 0;
813
+ function pushIfNotEmpty(text) {
814
+ text && segments.push(text);
815
+ }
816
+ for (; idx < segment.length; ) {
817
+ const openIndex = segment.indexOf("[", idx);
818
+ if (openIndex === -1) {
819
+ const remaining = segment.slice(idx);
820
+ pushIfNotEmpty(remaining);
821
+ break;
822
+ }
823
+ const before = segment.slice(idx, openIndex);
824
+ pushIfNotEmpty(before);
825
+ const closeIndex = segment.indexOf("]", openIndex);
826
+ if (closeIndex === -1)
827
+ throw new Error(`Unmatched "[" in segment: "${segment}"`);
828
+ const bracketContent = segment.slice(openIndex + 1, closeIndex);
829
+ segments.push(parseBracketContent(bracketContent)), idx = closeIndex + 1;
830
+ }
831
+ return segments;
832
+ }
833
+ function parsePath(path) {
834
+ const result = [];
835
+ let buffer = "", bracketDepth = 0;
836
+ for (let i2 = 0; i2 < path.length; i2++) {
837
+ const ch = path[i2];
838
+ ch === "[" ? (bracketDepth++, buffer += ch) : ch === "]" ? (bracketDepth--, buffer += ch) : ch === "." && bracketDepth === 0 ? buffer && (result.push(...parseSegment(buffer)), buffer = "") : buffer += ch;
839
+ }
840
+ return buffer && result.push(...parseSegment(buffer)), result;
841
+ }
842
+ function stringifyPath(path) {
843
+ let result = "";
844
+ for (let i2 = 0; i2 < path.length; i2++) {
845
+ const segment = path[i2];
846
+ if (typeof segment == "string")
847
+ result && (result += "."), result += segment;
848
+ else if (typeof segment == "number")
849
+ result += `[${segment}]`;
850
+ else if (Array.isArray(segment)) {
851
+ const [start, end] = segment, startStr = start === "" ? "" : String(start), endStr = end === "" ? "" : String(end);
852
+ result += `[${startStr}:${endStr}]`;
853
+ } else
854
+ result += `[_key=="${segment._key}"]`;
855
+ }
856
+ return result;
857
+ }
858
+ function jsonMatch(input, pathExpression) {
859
+ return matchRecursive(input, parsePath(pathExpression), []);
860
+ }
861
+ function matchRecursive(value, path, currentPath) {
862
+ if (path.length === 0)
863
+ return [{ value, path: currentPath }];
864
+ const [head, ...rest] = path;
865
+ if (typeof head == "string") {
866
+ if (value && typeof value == "object" && !Array.isArray(value)) {
867
+ const nextValue = value[head];
868
+ return matchRecursive(nextValue, rest, [...currentPath, head]);
869
+ }
870
+ return [];
871
+ }
872
+ if (typeof head == "number") {
873
+ if (Array.isArray(value)) {
874
+ const nextValue = value.at(head);
875
+ return matchRecursive(nextValue, rest, [...currentPath, head]);
876
+ }
477
877
  return [];
478
878
  }
479
879
  if (Array.isArray(head)) {
@@ -607,475 +1007,105 @@ function inc(input, pathExpressionValues) {
607
1007
  }
608
1008
  function dec(input, pathExpressionValues) {
609
1009
  const result = inc(
610
- input,
611
- Object.fromEntries(
612
- Object.entries(pathExpressionValues).filter(([, value]) => typeof value == "number").map(([key, value]) => [key, -value])
613
- )
614
- );
615
- return ensureArrayKeysDeep(result);
616
- }
617
- function diffMatchPatch(input, pathExpressionValues) {
618
- const result = Object.entries(pathExpressionValues).flatMap(([pathExpression, dmp]) => jsonMatch(input, pathExpression).map((m2) => ({ ...m2, dmp }))).filter((i2) => i2.value !== void 0).map(({ path, value, dmp }) => {
619
- if (typeof value != "string")
620
- throw new Error(
621
- `Can't diff-match-patch \`${JSON.stringify(value)}\` at path \`${stringifyPath(path)}\`, because it is not a string`
622
- );
623
- const [nextValue] = applyPatches(parsePatch(dmp), value);
624
- return { path, value: nextValue };
625
- }).reduce((acc, { path, value }) => setDeep(acc, path, value), input);
626
- return ensureArrayKeysDeep(result);
627
- }
628
- function ifRevisionID(input, revisionId) {
629
- const inputRev = typeof input == "object" && input && "_rev" in input && typeof input._rev == "string" ? input._rev : void 0;
630
- if (typeof inputRev != "string")
631
- throw new Error("Patch specified `ifRevisionID` but could not find document's revision ID.");
632
- if (revisionId !== inputRev)
633
- throw new Error(
634
- `Patch's \`ifRevisionID\` \`${revisionId}\` does not match document's revision ID \`${inputRev}\``
635
- );
636
- return input;
637
- }
638
- function isNonNullable(t2) {
639
- return t2 != null;
640
- }
641
- const indexCache = /* @__PURE__ */ new WeakMap();
642
- function getIndexForKey(input, key) {
643
- if (!Array.isArray(input)) return;
644
- const cached = indexCache.get(input);
645
- if (cached) return cached[key];
646
- const lookup = input.reduce((acc, next, index) => (typeof next?._key == "string" && (acc[next._key] = index), acc), {});
647
- return indexCache.set(input, lookup), lookup[key];
648
- }
649
- function getDeep(input, path) {
650
- const [currentSegment, ...restOfPath] = path;
651
- if (currentSegment === void 0) return input;
652
- if (typeof input != "object" || input === null) return;
653
- let key;
654
- if (isKeySegment(currentSegment) ? key = getIndexForKey(input, currentSegment._key) : (typeof currentSegment == "string" || typeof currentSegment == "number") && (key = currentSegment), key === void 0) return;
655
- const nestedInput = typeof key == "number" && Array.isArray(input) ? input.at(key) : input[key];
656
- return getDeep(nestedInput, restOfPath);
657
- }
658
- function setDeep(input, path, value) {
659
- const [currentSegment, ...restOfPath] = path;
660
- if (currentSegment === void 0) return value;
661
- if (typeof input != "object" || input === null) {
662
- if (typeof currentSegment == "string")
663
- return { [currentSegment]: setDeep(null, restOfPath, value) };
664
- let index;
665
- if (isKeySegment(currentSegment))
666
- index = 0;
667
- else if (typeof currentSegment == "number" && currentSegment >= 0)
668
- index = currentSegment;
669
- else
670
- return input;
671
- return [
672
- // fill until index
673
- ...Array.from({ length: index }).fill(null),
674
- // then set deep here
675
- setDeep(null, restOfPath, value)
676
- ];
677
- }
678
- if (Array.isArray(input)) {
679
- let index;
680
- return isKeySegment(currentSegment) ? index = getIndexForKey(input, currentSegment._key) : typeof currentSegment == "number" && (index = currentSegment < 0 ? input.length + currentSegment : currentSegment), index === void 0 ? input : index in input ? input.map(
681
- (nestedInput, i2) => i2 === index ? setDeep(nestedInput, restOfPath, value) : nestedInput
682
- ) : [
683
- ...input,
684
- ...Array.from({ length: index - input.length }).fill(null),
685
- setDeep(null, restOfPath, value)
686
- ];
687
- }
688
- return typeof currentSegment == "object" ? input : currentSegment in input ? Object.fromEntries(
689
- Object.entries(input).map(
690
- ([key, nestedInput]) => key === currentSegment ? [key, setDeep(nestedInput, restOfPath, value)] : [key, nestedInput]
691
- )
692
- ) : { ...input, [currentSegment]: setDeep(null, restOfPath, value) };
693
- }
694
- function unsetDeep(input, path) {
695
- const [currentSegment, ...restOfPath] = path;
696
- if (currentSegment === void 0 || typeof input != "object" || input === null) return input;
697
- let _segment;
698
- if (isKeySegment(currentSegment) ? _segment = getIndexForKey(input, currentSegment._key) : (typeof currentSegment == "string" || typeof currentSegment == "number") && (_segment = currentSegment), _segment === void 0) return input;
699
- let segment = _segment;
700
- return typeof segment == "number" && Array.isArray(input) && (segment = segment < 0 ? input.length + segment : segment), segment in input ? restOfPath.length ? Array.isArray(input) ? input.map(
701
- (nestedInput, index) => index === segment ? unsetDeep(nestedInput, restOfPath) : nestedInput
702
- ) : Object.fromEntries(
703
- Object.entries(input).map(
704
- ([key, value]) => key === segment ? [key, unsetDeep(value, restOfPath)] : [key, value]
705
- )
706
- ) : Array.isArray(input) ? input.filter((_nestedInput, index) => index !== segment) : Object.fromEntries(Object.entries(input).filter(([key]) => key !== segment.toString())) : input;
707
- }
708
- const DEFAULT_API_VERSION = "2024-11-12", DEFAULT_REQUEST_TAG_PREFIX = "sanity.sdk", clientStore = {
709
- name: "clientStore",
710
- getInitialState: (instance) => {
711
- const { identity, config } = instance, defaultClient = createClient({
712
- projectId: identity.projectId,
713
- dataset: identity.dataset,
714
- token: config?.auth?.token,
715
- useCdn: !1,
716
- apiVersion: DEFAULT_API_VERSION,
717
- requestTagPrefix: DEFAULT_REQUEST_TAG_PREFIX,
718
- ...config?.auth?.apiHost ? { apiHost: config.auth.apiHost } : {}
719
- }), defaultGlobalClient = createClient({
720
- token: config?.auth?.token,
721
- useCdn: !1,
722
- apiVersion: "vX",
723
- // Many global APIs are only available under this version, we may need to support other versions in the future
724
- useProjectHostname: !1,
725
- requestTagPrefix: DEFAULT_REQUEST_TAG_PREFIX,
726
- ...config?.auth?.apiHost ? { apiHost: config.auth.apiHost } : {}
727
- });
728
- return {
729
- defaultClient,
730
- defaultGlobalClient
731
- };
732
- },
733
- initialize() {
734
- const authEventSubscription = subscribeToAuthEvents(this);
735
- return () => {
736
- authEventSubscription.unsubscribe();
737
- };
738
- }
739
- }, receiveToken = (prev, token) => {
740
- const newDefaultClient = prev.defaultClient.withConfig({
741
- token
742
- }), newGlobalClient = prev.defaultGlobalClient.withConfig({
743
- token
744
- });
745
- return {
746
- defaultClient: newDefaultClient,
747
- defaultGlobalClient: newGlobalClient
748
- };
749
- }, subscribeToAuthEvents = createInternalAction(
750
- ({ instance, state }) => () => getTokenState(instance).observable.subscribe((newToken) => {
751
- state.set("receiveToken", (prev) => receiveToken(prev, newToken ?? void 0));
752
- })
753
- ), optionsCache = /* @__PURE__ */ new WeakMap(), defaultClientSelector = (state, options) => options?.scope === "global" ? state.defaultGlobalClient : state.defaultClient, memoizedOptionsSelector = createSelector(
754
- [defaultClientSelector, (_state, options) => options],
755
- (client, options) => {
756
- let nestedCache = optionsCache.get(client);
757
- nestedCache || (nestedCache = /* @__PURE__ */ new Map(), optionsCache.set(client, nestedCache));
758
- const key = JSON.stringify(options);
759
- return nestedCache.get(key) || (nestedCache.set(key, options), options);
760
- }
761
- ), clientSelector = createSelector(
762
- [defaultClientSelector, memoizedOptionsSelector],
763
- (client, options) => client.withConfig(options)
764
- ), getClient = createAction(
765
- clientStore,
766
- ({ state }) => (options) => clientSelector(state.get(), options)
767
- ), getClientState = createStateSourceAction(clientStore, clientSelector), comlinkControllerStore = {
768
- name: "connectionStore",
769
- getInitialState: () => ({
770
- controller: null,
771
- controllerOrigin: null,
772
- channels: /* @__PURE__ */ new Map()
773
- }),
774
- initialize() {
775
- return () => {
776
- destroyController(this);
777
- };
778
- }
779
- }, destroyController = createInternalAction(
780
- ({ state }) => () => {
781
- const { controller } = state.get();
782
- controller && (controller.destroy(), state.set("destroyController", {
783
- controller: null,
784
- channels: /* @__PURE__ */ new Map()
785
- }));
786
- }
787
- ), getOrCreateChannel = createAction(comlinkControllerStore, ({ state }) => (options) => {
788
- const controller = state.get().controller;
789
- if (!controller)
790
- throw new Error("Controller must be initialized before using or creating channels");
791
- const channels = state.get().channels, existing = channels.get(options.name);
792
- if (existing) {
793
- if (!isEqual(existing.options, options))
794
- throw new Error(`Channel "${options.name}" already exists with different options`);
795
- return state.set("incrementChannelRefCount", {
796
- channels: new Map(channels).set(options.name, {
797
- ...existing,
798
- refCount: existing.refCount + 1
799
- })
800
- }), existing.channel.start(), existing.channel;
801
- }
802
- const channel = controller.createChannel(options);
803
- return channel.start(), state.set("createChannel", {
804
- channels: new Map(channels).set(options.name, {
805
- channel,
806
- options,
807
- refCount: 1
808
- })
809
- }), channel;
810
- }), getOrCreateController = createAction(comlinkControllerStore, ({ state, instance }) => (targetOrigin) => {
811
- const { controller, controllerOrigin } = state.get();
812
- if (controller && controllerOrigin === targetOrigin)
813
- return controller;
814
- controller && destroyController({ state, instance });
815
- const newController = createController({ targetOrigin });
816
- return state.set("initializeController", {
817
- controllerOrigin: targetOrigin,
818
- controller: newController
819
- }), newController;
820
- }), releaseChannel = createAction(comlinkControllerStore, ({ state }) => (name) => {
821
- const channels = state.get().channels, channelEntry = channels.get(name);
822
- if (channelEntry) {
823
- const newRefCount = channelEntry.refCount === 0 ? 0 : channelEntry.refCount - 1;
824
- newRefCount === 0 ? (channelEntry.channel.stop(), channels.delete(name), state.set("releaseChannel", { channels: new Map(channels) })) : state.set("releaseChannel", {
825
- channels: new Map(channels).set(name, {
826
- ...channelEntry,
827
- refCount: newRefCount
828
- })
829
- });
830
- }
831
- }), comlinkNodeStore = {
832
- name: "nodeStore",
833
- getInitialState: () => ({
834
- nodes: /* @__PURE__ */ new Map()
835
- }),
836
- initialize() {
837
- return () => {
838
- this.state.get().nodes.forEach(({ node }) => {
839
- node.stop();
840
- });
841
- };
842
- }
843
- }, getOrCreateNode = createAction(comlinkNodeStore, ({ state }) => (options) => {
844
- const nodes = state.get().nodes, existing = nodes.get(options.name);
845
- if (existing) {
846
- if (!isEqual(existing.options, options))
847
- throw new Error(`Node "${options.name}" already exists with different options`);
848
- return state.set("incrementNodeRefCount", {
849
- nodes: new Map(nodes).set(options.name, {
850
- ...existing,
851
- refCount: existing.refCount + 1
852
- })
853
- }), existing.node.start(), existing.node;
854
- }
855
- const node = createNode(options);
856
- return node.start(), nodes.set(options.name, { node, options, refCount: 1 }), state.set("createNode", { nodes }), node;
857
- }), releaseNode = createAction(comlinkNodeStore, ({ state }) => (name) => {
858
- const nodes = state.get().nodes, nodeEntry = nodes.get(name);
859
- if (nodeEntry) {
860
- const newRefCount = nodeEntry.refCount === 0 ? 0 : nodeEntry.refCount - 1;
861
- newRefCount === 0 ? (nodeEntry.node.stop(), nodes.delete(name), state.set("releaseNode", { nodes: new Map(nodes) })) : state.set("releaseNode", {
862
- nodes: new Map(nodes).set(name, {
863
- ...nodeEntry,
864
- refCount: newRefCount
865
- })
866
- });
867
- }
868
- });
869
- function getPublishedId(id) {
870
- const draftsPrefix = "drafts.";
871
- return id.startsWith(draftsPrefix) ? id.slice(draftsPrefix.length) : id;
872
- }
873
- function getDraftId(id) {
874
- const draftsPrefix = "drafts.";
875
- return id.startsWith(draftsPrefix) ? id : `${draftsPrefix}${id}`;
876
- }
877
- function insecureRandomId() {
878
- return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
879
- }
880
- function createFetcherStore({
881
- name,
882
- fetcher: getObservable,
883
- getKey,
884
- fetchThrottleInternal = 1e3,
885
- stateExpirationDelay = 5e3
886
- }) {
887
- const store = {
888
- name,
889
- getInitialState: () => ({
890
- stateByParams: {}
891
- }),
892
- initialize() {
893
- const subscription = subscribeToSubscriptionsAndFetch(this);
894
- return () => subscription.unsubscribe();
895
- }
896
- }, subscribeToSubscriptionsAndFetch = createInternalAction(
897
- ({ instance, state }) => function() {
898
- const factoryFn = getObservable(instance);
899
- return state.observable.pipe(
900
- // Map the state to an array of [serialized, entry] pairs.
901
- switchMap$1((s2) => {
902
- const entries = Object.entries(s2.stateByParams);
903
- return entries.length > 0 ? from(entries) : EMPTY;
904
- }),
905
- // Group by the serialized key.
906
- groupBy(([key]) => key),
907
- mergeMap(
908
- (group$) => group$.pipe(
909
- // Emit an initial value for pairwise comparisons.
910
- startWith([
911
- group$.key,
912
- void 0
913
- ]),
914
- pairwise(),
915
- // Trigger only when the subscriptions array grows.
916
- filter$1(([[, prevEntry], [, currEntry]]) => {
917
- const prevSubs = prevEntry?.subscriptions ?? [];
918
- return (currEntry?.subscriptions ?? []).length > prevSubs.length;
919
- }),
920
- map$1(([, [, currEntry]]) => currEntry),
921
- // Only trigger if we haven't fetched recently.
922
- filter$1((entry) => {
923
- const lastFetch = entry?.lastFetchInitiatedAt;
924
- return lastFetch ? Date.now() - new Date(lastFetch).getTime() >= fetchThrottleInternal : !0;
925
- }),
926
- switchMap$1((entry) => entry ? (state.set(
927
- "setLastFetchInitiatedAt",
928
- (prev) => ({
929
- stateByParams: {
930
- ...prev.stateByParams,
931
- [entry.key]: {
932
- ...entry,
933
- ...prev.stateByParams[entry.key],
934
- lastFetchInitiatedAt: (/* @__PURE__ */ new Date()).toISOString()
935
- }
936
- }
937
- })
938
- ), factoryFn(...entry.params).pipe(
939
- // the `createStateSourceAction` util requires the update
940
- // to
941
- delay(0, asapScheduler),
942
- tap(
943
- (data) => state.set("setData", (prev) => ({
944
- stateByParams: {
945
- ...prev.stateByParams,
946
- [entry.key]: {
947
- ...omit(entry, "error"),
948
- ...omit(prev.stateByParams[entry.key], "error"),
949
- data
950
- }
951
- }
952
- }))
953
- ),
954
- catchError((error) => (state.set("setError", (prev) => ({
955
- stateByParams: {
956
- ...prev.stateByParams,
957
- [entry.key]: {
958
- ...entry,
959
- ...prev.stateByParams[entry.key],
960
- error
961
- }
962
- }
963
- })), EMPTY))
964
- )) : EMPTY)
965
- )
966
- )
967
- ).subscribe({
968
- error: (error) => state.set("setError", { error })
969
- });
970
- }
971
- ), getState2 = createStateSourceAction(store, {
972
- selector: ({ stateByParams, error }, ...params) => {
973
- if (error) throw error;
974
- const key = getKey(...params), entry = stateByParams[key];
975
- if (entry?.error) throw entry.error;
976
- return entry?.data;
977
- },
978
- onSubscribe: ({ state }, ...params) => {
979
- const subscriptionId = insecureRandomId(), key = getKey(...params);
980
- return state.set("addSubscription", (prev) => ({
981
- stateByParams: {
982
- ...prev.stateByParams,
983
- [key]: {
984
- ...prev.stateByParams[key],
985
- key,
986
- params: prev.stateByParams[key]?.params || params,
987
- subscriptions: [...prev.stateByParams[key]?.subscriptions || [], subscriptionId]
988
- }
989
- }
990
- })), () => {
991
- setTimeout(() => {
992
- state.set("removeSubscription", (prev) => {
993
- const entry = prev.stateByParams[key];
994
- if (!entry) return prev;
995
- const newSubs = (entry.subscriptions || []).filter((id) => id !== subscriptionId);
996
- return newSubs.length === 0 ? { stateByParams: omit(prev.stateByParams, key) } : {
997
- stateByParams: {
998
- ...prev.stateByParams,
999
- [key]: {
1000
- ...entry,
1001
- subscriptions: newSubs
1002
- }
1003
- }
1004
- };
1005
- });
1006
- }, stateExpirationDelay);
1007
- };
1008
- }
1009
- }), resolveState = createAction(store, () => function(...params) {
1010
- return firstValueFrom(
1011
- getState2(this, ...params).observable.pipe(first((i2) => i2 !== void 0))
1012
- );
1013
- });
1014
- return { getState: getState2, resolveState };
1010
+ input,
1011
+ Object.fromEntries(
1012
+ Object.entries(pathExpressionValues).filter(([, value]) => typeof value == "number").map(([key, value]) => [key, -value])
1013
+ )
1014
+ );
1015
+ return ensureArrayKeysDeep(result);
1015
1016
  }
1016
- const datasets = createFetcherStore({
1017
- name: "Datasets",
1018
- getKey: () => "datasets",
1019
- fetcher: (instance) => () => getClientState(instance, { apiVersion: "vX", scope: "project" }).observable.pipe(
1020
- switchMap((client) => client.observable.datasets.list())
1021
- )
1022
- }), getDatasetsState = datasets.getState, resolveDatasets = datasets.resolveState, isSanityMutatePatch = (value) => !(typeof value != "object" || !value || !("type" in value) || typeof value.type != "string" || value.type !== "patch" || !("id" in value) || typeof value.id != "string" || !("patches" in value) || !Array.isArray(value.patches));
1023
- function createDocument(doc) {
1024
- return {
1025
- type: "document.create",
1026
- ...doc._id && { documentId: doc._id },
1027
- documentType: doc._type,
1028
- ...doc.resourceId && { resourceId: doc.resourceId }
1029
- };
1017
+ function diffMatchPatch(input, pathExpressionValues) {
1018
+ const result = Object.entries(pathExpressionValues).flatMap(([pathExpression, dmp]) => jsonMatch(input, pathExpression).map((m2) => ({ ...m2, dmp }))).filter((i2) => i2.value !== void 0).map(({ path, value, dmp }) => {
1019
+ if (typeof value != "string")
1020
+ throw new Error(
1021
+ `Can't diff-match-patch \`${JSON.stringify(value)}\` at path \`${stringifyPath(path)}\`, because it is not a string`
1022
+ );
1023
+ const [nextValue] = applyPatches(parsePatch(dmp), value);
1024
+ return { path, value: nextValue };
1025
+ }).reduce((acc, { path, value }) => setDeep(acc, path, value), input);
1026
+ return ensureArrayKeysDeep(result);
1030
1027
  }
1031
- function deleteDocument(doc) {
1032
- return {
1033
- type: "document.delete",
1034
- documentId: getPublishedId(doc._id),
1035
- ...doc.resourceId && { resourceId: doc.resourceId }
1036
- };
1028
+ function ifRevisionID(input, revisionId) {
1029
+ const inputRev = typeof input == "object" && input && "_rev" in input && typeof input._rev == "string" ? input._rev : void 0;
1030
+ if (typeof inputRev != "string")
1031
+ throw new Error("Patch specified `ifRevisionID` but could not find document's revision ID.");
1032
+ if (revisionId !== inputRev)
1033
+ throw new Error(
1034
+ `Patch's \`ifRevisionID\` \`${revisionId}\` does not match document's revision ID \`${inputRev}\``
1035
+ );
1036
+ return input;
1037
1037
  }
1038
- function convertSanityMutatePatch(sanityPatchMutation) {
1039
- const encoded = SanityEncoder.encode(sanityPatchMutation);
1040
- return {
1041
- documentId: sanityPatchMutation.id,
1042
- type: "document.edit",
1043
- patches: encoded.map((i2) => {
1044
- const copy = { ...i2.patch };
1045
- return "id" in copy && delete copy.id, copy;
1046
- })
1047
- };
1038
+ function isNonNullable(t2) {
1039
+ return t2 != null;
1048
1040
  }
1049
- function editDocument(doc, patches) {
1050
- return isSanityMutatePatch(doc) ? convertSanityMutatePatch(doc) : {
1051
- type: "document.edit",
1052
- documentId: getPublishedId(doc._id),
1053
- ...patches && { patches: Array.isArray(patches) ? patches : [patches] },
1054
- ...doc.resourceId && { resourceId: doc.resourceId }
1055
- };
1041
+ const indexCache = /* @__PURE__ */ new WeakMap();
1042
+ function getIndexForKey(input, key) {
1043
+ if (!Array.isArray(input)) return;
1044
+ const cached = indexCache.get(input);
1045
+ if (cached) return cached[key];
1046
+ const lookup = input.reduce((acc, next, index) => (typeof next?._key == "string" && (acc[next._key] = index), acc), {});
1047
+ return indexCache.set(input, lookup), lookup[key];
1056
1048
  }
1057
- function publishDocument(doc) {
1058
- return {
1059
- type: "document.publish",
1060
- documentId: getPublishedId(doc._id),
1061
- ...doc.resourceId && { resourceId: doc.resourceId }
1062
- };
1049
+ function getDeep(input, path) {
1050
+ const [currentSegment, ...restOfPath] = path;
1051
+ if (currentSegment === void 0) return input;
1052
+ if (typeof input != "object" || input === null) return;
1053
+ let key;
1054
+ if (isKeySegment(currentSegment) ? key = getIndexForKey(input, currentSegment._key) : (typeof currentSegment == "string" || typeof currentSegment == "number") && (key = currentSegment), key === void 0) return;
1055
+ const nestedInput = typeof key == "number" && Array.isArray(input) ? input.at(key) : input[key];
1056
+ return getDeep(nestedInput, restOfPath);
1063
1057
  }
1064
- function unpublishDocument(doc) {
1065
- return {
1066
- type: "document.unpublish",
1067
- documentId: getPublishedId(doc._id),
1068
- ...doc.resourceId && { resourceId: doc.resourceId }
1069
- };
1058
+ function setDeep(input, path, value) {
1059
+ const [currentSegment, ...restOfPath] = path;
1060
+ if (currentSegment === void 0) return value;
1061
+ if (typeof input != "object" || input === null) {
1062
+ if (typeof currentSegment == "string")
1063
+ return { [currentSegment]: setDeep(null, restOfPath, value) };
1064
+ let index;
1065
+ if (isKeySegment(currentSegment))
1066
+ index = 0;
1067
+ else if (typeof currentSegment == "number" && currentSegment >= 0)
1068
+ index = currentSegment;
1069
+ else
1070
+ return input;
1071
+ return [
1072
+ // fill until index
1073
+ ...Array.from({ length: index }).fill(null),
1074
+ // then set deep here
1075
+ setDeep(null, restOfPath, value)
1076
+ ];
1077
+ }
1078
+ if (Array.isArray(input)) {
1079
+ let index;
1080
+ return isKeySegment(currentSegment) ? index = getIndexForKey(input, currentSegment._key) : typeof currentSegment == "number" && (index = currentSegment < 0 ? input.length + currentSegment : currentSegment), index === void 0 ? input : index in input ? input.map(
1081
+ (nestedInput, i2) => i2 === index ? setDeep(nestedInput, restOfPath, value) : nestedInput
1082
+ ) : [
1083
+ ...input,
1084
+ ...Array.from({ length: index - input.length }).fill(null),
1085
+ setDeep(null, restOfPath, value)
1086
+ ];
1087
+ }
1088
+ return typeof currentSegment == "object" ? input : currentSegment in input ? Object.fromEntries(
1089
+ Object.entries(input).map(
1090
+ ([key, nestedInput]) => key === currentSegment ? [key, setDeep(nestedInput, restOfPath, value)] : [key, nestedInput]
1091
+ )
1092
+ ) : { ...input, [currentSegment]: setDeep(null, restOfPath, value) };
1070
1093
  }
1071
- function discardDocument(doc) {
1072
- return {
1073
- type: "document.discard",
1074
- documentId: getPublishedId(doc._id),
1075
- ...doc.resourceId && { resourceId: doc.resourceId }
1076
- };
1094
+ function unsetDeep(input, path) {
1095
+ const [currentSegment, ...restOfPath] = path;
1096
+ if (currentSegment === void 0 || typeof input != "object" || input === null) return input;
1097
+ let _segment;
1098
+ if (isKeySegment(currentSegment) ? _segment = getIndexForKey(input, currentSegment._key) : (typeof currentSegment == "string" || typeof currentSegment == "number") && (_segment = currentSegment), _segment === void 0) return input;
1099
+ let segment = _segment;
1100
+ return typeof segment == "number" && Array.isArray(input) && (segment = segment < 0 ? input.length + segment : segment), segment in input ? restOfPath.length ? Array.isArray(input) ? input.map(
1101
+ (nestedInput, index) => index === segment ? unsetDeep(nestedInput, restOfPath) : nestedInput
1102
+ ) : Object.fromEntries(
1103
+ Object.entries(input).map(
1104
+ ([key, value]) => key === segment ? [key, unsetDeep(value, restOfPath)] : [key, value]
1105
+ )
1106
+ ) : Array.isArray(input) ? input.filter((_nestedInput, index) => index !== segment) : Object.fromEntries(Object.entries(input).filter(([key]) => key !== segment.toString())) : input;
1077
1107
  }
1078
- const DOCUMENT_STATE_CLEAR_DELAY = 1e3, INITIAL_OUTGOING_THROTTLE_TIME = 1e3, API_VERSION$2 = "vX", patchOperations = {
1108
+ const patchOperations = {
1079
1109
  ifRevisionID,
1080
1110
  set,
1081
1111
  setIfMissing,
@@ -1284,50 +1314,48 @@ function sortListenerEvents(options) {
1284
1314
  mergeMap((state) => of(...state.emitEvents))
1285
1315
  );
1286
1316
  }
1287
- const listen = createInternalAction(({ state }) => {
1317
+ const listen = ({ state }, documentId) => {
1288
1318
  const { sharedListener, fetchDocument } = state.get();
1289
- return function(documentId) {
1290
- return sharedListener.pipe(
1291
- concatMap((e3) => e3.type === "welcome" ? fetchDocument(documentId).pipe(
1292
- map((document) => ({ type: "sync", document }))
1293
- ) : e3.type === "mutation" && e3.documentId === documentId ? of(e3) : EMPTY),
1294
- sortListenerEvents(),
1295
- withLatestFrom(
1296
- state.observable.pipe(
1297
- map((s2) => s2.documentStates[documentId]),
1298
- filter(Boolean),
1299
- distinctUntilChanged()
1300
- )
1301
- ),
1302
- map(([next, documentState]) => {
1303
- if (next.type === "sync")
1304
- return {
1305
- type: "sync",
1306
- documentId,
1307
- document: next.document,
1308
- revision: next.document?._rev,
1309
- timestamp: next.document?._updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
1310
- };
1311
- const [document] = Object.values(
1312
- processMutations({
1313
- documents: { [documentId]: documentState.remote },
1314
- mutations: next.mutations,
1315
- transactionId: next.transactionId,
1316
- timestamp: next.timestamp
1317
- })
1318
- ), { previousRev, transactionId, timestamp } = next;
1319
+ return sharedListener.events.pipe(
1320
+ concatMap((e3) => e3.type === "welcome" ? fetchDocument(documentId).pipe(
1321
+ map((document) => ({ type: "sync", document }))
1322
+ ) : e3.type === "mutation" && e3.documentId === documentId ? of(e3) : EMPTY),
1323
+ sortListenerEvents(),
1324
+ withLatestFrom(
1325
+ state.observable.pipe(
1326
+ map((s2) => s2.documentStates[documentId]),
1327
+ filter(Boolean),
1328
+ distinctUntilChanged()
1329
+ )
1330
+ ),
1331
+ map(([next, documentState]) => {
1332
+ if (next.type === "sync")
1319
1333
  return {
1320
- type: "mutation",
1334
+ type: "sync",
1321
1335
  documentId,
1322
- document: document ?? null,
1323
- revision: transactionId,
1324
- timestamp,
1325
- ...previousRev && { previousRev }
1336
+ document: next.document,
1337
+ revision: next.document?._rev,
1338
+ timestamp: next.document?._updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
1326
1339
  };
1327
- })
1328
- );
1329
- };
1330
- });
1340
+ const [document] = Object.values(
1341
+ processMutations({
1342
+ documents: { [documentId]: documentState.remote },
1343
+ mutations: next.mutations,
1344
+ transactionId: next.transactionId,
1345
+ timestamp: next.timestamp
1346
+ })
1347
+ ), { previousRev, transactionId, timestamp } = next;
1348
+ return {
1349
+ type: "mutation",
1350
+ documentId,
1351
+ document: document ?? null,
1352
+ revision: transactionId,
1353
+ timestamp,
1354
+ ...previousRev && { previousRev }
1355
+ };
1356
+ })
1357
+ );
1358
+ };
1331
1359
  class e {
1332
1360
  pattern;
1333
1361
  patternRe;
@@ -3189,8 +3217,8 @@ function createGrantsLookup(datasetAcl) {
3189
3217
  }
3190
3218
  const documentsCache = new MultiKeyWeakMap(), actionsCache = /* @__PURE__ */ new WeakMap(), nullReplacer = {}, documentsSelector = createSelector(
3191
3219
  [
3192
- ({ documentStates }) => documentStates,
3193
- (_state, actions) => actions
3220
+ ({ state: { documentStates } }) => documentStates,
3221
+ (_context, actions) => actions
3194
3222
  ],
3195
3223
  (documentStates, actions) => {
3196
3224
  const documentIds = new Set(
@@ -3225,7 +3253,11 @@ function checkGrant$1(grantExpr, document) {
3225
3253
  return C(grantExpr, { params: { document } }).get();
3226
3254
  }
3227
3255
  const enNarrowConjunction = new Intl.ListFormat("en", { style: "narrow", type: "conjunction" }), calculatePermissions = createSelector(
3228
- [({ grants }) => grants, documentsSelector, memoizedActionsSelector],
3256
+ [
3257
+ ({ state: { grants } }) => grants,
3258
+ documentsSelector,
3259
+ memoizedActionsSelector
3260
+ ],
3229
3261
  (grants, documents, actions) => {
3230
3262
  if (!documents || !grants || !actions) return;
3231
3263
  const timestamp = (/* @__PURE__ */ new Date()).toISOString(), reasons = [];
@@ -3795,7 +3827,7 @@ function removeSubscriptionIdFromDocument(prev, documentId, subscriptionId) {
3795
3827
  }
3796
3828
  } : { ...prev, documentStates: omit(prev.documentStates, documentId) } : prev;
3797
3829
  }
3798
- function manageSubscriberIds(state, documentId) {
3830
+ function manageSubscriberIds({ state }, documentId) {
3799
3831
  const documentIds = Array.from(
3800
3832
  new Set(
3801
3833
  (Array.isArray(documentId) ? documentId : [documentId]).flatMap((id) => [
@@ -3853,9 +3885,11 @@ function getDocumentEvents(outgoing) {
3853
3885
  )
3854
3886
  );
3855
3887
  }
3856
- const API_VERSION$1 = "vX";
3888
+ const API_VERSION$3 = "vX";
3857
3889
  function createSharedListener(instance) {
3858
- const events$ = getClientState(instance, { apiVersion: API_VERSION$1 }).observable.pipe(
3890
+ const dispose$ = new Subject(), events$ = getClientState(instance, {
3891
+ apiVersion: API_VERSION$3
3892
+ }).observable.pipe(
3859
3893
  switchMap(
3860
3894
  (client) => (
3861
3895
  // TODO: it seems like the client.listen method is not emitting disconnected
@@ -3876,17 +3910,21 @@ function createSharedListener(instance) {
3876
3910
  )
3877
3911
  )
3878
3912
  ),
3913
+ takeUntil(dispose$),
3879
3914
  share()
3880
3915
  ), [welcome$, mutation$] = partition(events$, (e3) => e3.type === "welcome");
3881
- return merge(
3882
- // we replay the welcome event because that event kicks off fetching the document
3883
- welcome$.pipe(shareReplay(1)),
3884
- mutation$
3885
- );
3916
+ return {
3917
+ events: merge(
3918
+ // we replay the welcome event because that event kicks off fetching the document
3919
+ welcome$.pipe(shareReplay(1)),
3920
+ mutation$
3921
+ ),
3922
+ dispose: () => dispose$.next()
3923
+ };
3886
3924
  }
3887
3925
  function createFetchDocument(instance) {
3888
3926
  return function(documentId) {
3889
- return getClientState(instance, { apiVersion: API_VERSION$1 }).observable.pipe(
3927
+ return getClientState(instance, { apiVersion: API_VERSION$3 }).observable.pipe(
3890
3928
  switchMap((client) => createDocumentLoaderFromClient(client)(documentId)),
3891
3929
  map((result) => {
3892
3930
  if (!result.accessible) {
@@ -3910,329 +3948,458 @@ const documentStore = {
3910
3948
  fetchDocument: createFetchDocument(instance),
3911
3949
  events: new Subject()
3912
3950
  }),
3913
- initialize() {
3914
- const queuedTransactionSubscription = subscribeToQueuedAndApplyNextTransaction(this), subscriptionsSubscription = subscribeToSubscriptionsAndListenToDocuments(this), appliedSubscription = subscribeToAppliedAndSubmitNextTransaction(this), clientSubscription = subscribeToClientAndFetchDatasetAcl(this);
3951
+ initialize(context) {
3952
+ const { sharedListener } = context.state.get(), subscriptions = [
3953
+ subscribeToQueuedAndApplyNextTransaction(context),
3954
+ subscribeToSubscriptionsAndListenToDocuments(context),
3955
+ subscribeToAppliedAndSubmitNextTransaction(context),
3956
+ subscribeToClientAndFetchDatasetAcl(context)
3957
+ ];
3915
3958
  return () => {
3916
- queuedTransactionSubscription.unsubscribe(), subscriptionsSubscription.unsubscribe(), appliedSubscription.unsubscribe(), clientSubscription.unsubscribe();
3959
+ sharedListener.dispose(), subscriptions.forEach((subscription) => subscription.unsubscribe());
3917
3960
  };
3918
3961
  }
3919
3962
  };
3920
3963
  function getDocumentState(...args) {
3921
3964
  return _getDocumentState(...args);
3922
3965
  }
3923
- const _getDocumentState = createStateSourceAction(documentStore, {
3924
- selector: ({ error, documentStates }, doc, path) => {
3925
- const documentId = typeof doc == "string" ? doc : doc._id;
3926
- if (error) throw error;
3927
- const draftId = getDraftId(documentId), publishedId = getPublishedId$1(documentId), draft = documentStates[draftId]?.local, published = documentStates[publishedId]?.local, document = draft ?? published;
3928
- if (document !== void 0)
3929
- return path ? jsonMatch(document, path).at(0)?.value : document;
3930
- },
3931
- onSubscribe: ({ state }, doc) => manageSubscriberIds(state, typeof doc == "string" ? doc : doc._id)
3932
- });
3966
+ const _getDocumentState = bindActionByDataset(
3967
+ documentStore,
3968
+ createStateSourceAction({
3969
+ selector: ({ state: { error, documentStates } }, doc, path) => {
3970
+ const documentId = typeof doc == "string" ? doc : doc.documentId;
3971
+ if (error) throw error;
3972
+ const draftId = getDraftId(documentId), publishedId = getPublishedId$1(documentId), draft = documentStates[draftId]?.local, published = documentStates[publishedId]?.local, document = draft ?? published;
3973
+ if (document !== void 0)
3974
+ return path ? jsonMatch(document, path).at(0)?.value : document;
3975
+ },
3976
+ onSubscribe: (context, doc) => manageSubscriberIds(context, typeof doc == "string" ? doc : doc.documentId)
3977
+ })
3978
+ );
3933
3979
  function resolveDocument(...args) {
3934
3980
  return _resolveDocument(...args);
3935
3981
  }
3936
- const _resolveDocument = createAction(documentStore, () => function(doc) {
3937
- const documentId = typeof doc == "string" ? doc : doc._id;
3938
- return firstValueFrom(
3939
- getDocumentState(this, documentId).observable.pipe(filter((i2) => i2 !== void 0))
3940
- );
3941
- }), getDocumentSyncStatus = createStateSourceAction(documentStore, {
3942
- selector: ({ error, documentStates: documents, outgoing, applied, queued }, doc) => {
3943
- const documentId = doc._id;
3944
- if (error) throw error;
3945
- const draftId = getDraftId(documentId), publishedId = getPublishedId$1(documentId), draft = documents[draftId], published = documents[publishedId];
3946
- if (!(draft === void 0 || published === void 0))
3947
- return !queued.length && !applied.length && !outgoing;
3948
- },
3949
- onSubscribe: ({ state }, doc) => manageSubscriberIds(state, doc._id)
3950
- }), getPermissionsState = createStateSourceAction(documentStore, {
3951
- selector: calculatePermissions,
3952
- onSubscribe: ({ state }, actions) => manageSubscriberIds(state, getDocumentIdsFromActions(actions))
3953
- }), resolvePermissions = createAction(documentStore, () => function(actions) {
3954
- return firstValueFrom(
3955
- getPermissionsState(this, actions).observable.pipe(filter((i2) => i2 !== void 0))
3956
- );
3957
- }), subscribeDocumentEvents = createAction(documentStore, ({ state }) => {
3958
- const { events } = state.get();
3959
- return function(eventHandler) {
3960
- const subscription = events.subscribe(eventHandler);
3961
- return () => subscription.unsubscribe();
3962
- };
3963
- }), subscribeToQueuedAndApplyNextTransaction = createInternalAction(
3964
- ({ state }) => {
3965
- const { events } = state.get();
3966
- return function() {
3967
- return state.observable.pipe(
3968
- map(applyFirstQueuedTransaction),
3969
- distinctUntilChanged(),
3970
- tap$1((next) => state.set("applyFirstQueuedTransaction", next)),
3971
- catchError$1((error, caught) => {
3972
- if (error instanceof ActionError)
3973
- return state.set(
3974
- "removeQueuedTransaction",
3975
- (prev) => removeQueuedTransaction(prev, error.transactionId)
3976
- ), events.next({
3977
- type: "error",
3978
- message: error.message,
3979
- documentId: error.documentId,
3980
- transactionId: error.transactionId,
3981
- error
3982
- }), caught;
3983
- throw error;
3984
- })
3985
- ).subscribe({ error: (error) => state.set("setError", { error }) });
3986
- };
3982
+ const _resolveDocument = bindActionByDataset(
3983
+ documentStore,
3984
+ ({ instance }, doc) => {
3985
+ const documentId = typeof doc == "string" ? doc : doc.documentId;
3986
+ return firstValueFrom(
3987
+ getDocumentState(instance, documentId).observable.pipe(filter((i2) => i2 !== void 0))
3988
+ );
3987
3989
  }
3988
- ), subscribeToAppliedAndSubmitNextTransaction = createInternalAction(
3989
- ({ state, instance }) => {
3990
- const { events } = state.get();
3991
- return function() {
3992
- return state.observable.pipe(
3993
- throttle(
3994
- (s2) => (
3995
- // if there is no outgoing transaction, we can throttle by the
3996
- // initial outgoing throttle time…
3997
- s2.outgoing ? (
3998
- // …otherwise, wait until the outgoing has been cleared
3999
- state.observable.pipe(first$1(({ outgoing }) => !outgoing))
4000
- ) : timer(INITIAL_OUTGOING_THROTTLE_TIME)
4001
- ),
4002
- { leading: !1, trailing: !0 }
4003
- ),
4004
- map(transitionAppliedTransactionsToOutgoing),
4005
- distinctUntilChanged((a2, b2) => a2.outgoing?.transactionId === b2.outgoing?.transactionId),
4006
- tap$1((next) => state.set("transitionAppliedTransactionsToOutgoing", next)),
4007
- map((s2) => s2.outgoing),
4008
- distinctUntilChanged(),
4009
- withLatestFrom(getClientState(instance, { apiVersion: API_VERSION$2 }).observable),
4010
- concatMap(([outgoing, client]) => outgoing ? client.observable.action(outgoing.outgoingActions, {
4011
- transactionId: outgoing.transactionId,
4012
- skipCrossDatasetReferenceValidation: !0
4013
- }).pipe(
4014
- catchError$1((error) => (state.set("revertOutgoingTransaction", revertOutgoingTransaction), events.next({ type: "reverted", message: error.message, outgoing, error }), EMPTY)),
4015
- map((result) => ({ result, outgoing }))
4016
- ) : EMPTY),
4017
- tap$1(({ outgoing, result }) => {
4018
- state.set("cleanupOutgoingTransaction", cleanupOutgoingTransaction);
4019
- for (const e3 of getDocumentEvents(outgoing)) events.next(e3);
4020
- events.next({ type: "accepted", outgoing, result });
4021
- })
4022
- ).subscribe({ error: (error) => state.set("setError", { error }) });
4023
- };
3990
+ ), getDocumentSyncStatus = bindActionByDataset(
3991
+ documentStore,
3992
+ createStateSourceAction({
3993
+ selector: ({ state: { error, documentStates: documents, outgoing, applied, queued } }, doc) => {
3994
+ const documentId = typeof doc == "string" ? doc : doc.documentId;
3995
+ if (error) throw error;
3996
+ const draftId = getDraftId(documentId), publishedId = getPublishedId$1(documentId), draft = documents[draftId], published = documents[publishedId];
3997
+ if (!(draft === void 0 || published === void 0))
3998
+ return !queued.length && !applied.length && !outgoing;
3999
+ },
4000
+ onSubscribe: (context, doc) => manageSubscriberIds(context, doc.documentId)
4001
+ })
4002
+ ), getPermissionsState = bindActionByDataset(
4003
+ documentStore,
4004
+ createStateSourceAction({
4005
+ selector: calculatePermissions,
4006
+ onSubscribe: (context, actions) => manageSubscriberIds(context, getDocumentIdsFromActions(actions))
4007
+ })
4008
+ ), resolvePermissions = bindActionByDataset(
4009
+ documentStore,
4010
+ ({ instance }, actions) => firstValueFrom(
4011
+ getPermissionsState(instance, actions).observable.pipe(filter((i2) => i2 !== void 0))
4012
+ )
4013
+ ), subscribeDocumentEvents = bindActionByDataset(
4014
+ documentStore,
4015
+ ({ state }, eventHandler) => {
4016
+ const { events } = state.get(), subscription = events.subscribe(eventHandler);
4017
+ return () => subscription.unsubscribe();
4024
4018
  }
4025
- ), subscribeToSubscriptionsAndListenToDocuments = createInternalAction(
4026
- ({ state }) => {
4027
- const { events } = state.get();
4028
- return function() {
4029
- return state.observable.pipe(
4030
- filter((s2) => !!s2.grants),
4031
- map((s2) => Object.keys(s2.documentStates)),
4032
- distinctUntilChanged((curr, next) => {
4033
- if (curr.length !== next.length) return !1;
4034
- const currSet = new Set(curr);
4035
- return next.every((i2) => currSet.has(i2));
4036
- }),
4037
- startWith$1(/* @__PURE__ */ new Set()),
4038
- pairwise$1(),
4039
- switchMap((pair) => {
4040
- const [curr, next] = pair.map((ids) => new Set(ids)), added = Array.from(next).filter((i2) => !curr.has(i2)), removed = Array.from(curr).filter((i2) => !next.has(i2)), changes = [
4041
- ...added.map((id) => ({ id, add: !0 })),
4042
- ...removed.map((id) => ({ id, add: !1 }))
4043
- ].sort((a2, b2) => {
4044
- const aIsDraft = a2.id === getDraftId(a2.id), bIsDraft = b2.id === getDraftId(b2.id);
4045
- return aIsDraft && bIsDraft ? a2.id.localeCompare(b2.id, "en-US") : aIsDraft ? -1 : bIsDraft ? 1 : a2.id.localeCompare(b2.id, "en-US");
4046
- });
4047
- return of(...changes);
4048
- }),
4049
- groupBy$1((i2) => i2.id),
4050
- mergeMap$1(
4051
- (group) => group.pipe(
4052
- switchMap((e3) => e3.add ? listen(this, e3.id).pipe(
4053
- catchError$1((error) => {
4054
- throw error instanceof OutOfSyncError && listen(this, e3.id), error;
4055
- }),
4056
- tap$1(
4057
- (remote) => state.set(
4058
- "applyRemoteDocument",
4059
- (prev) => applyRemoteDocument(prev, remote, events)
4060
- )
4061
- )
4062
- ) : EMPTY)
4019
+ ), subscribeToQueuedAndApplyNextTransaction = ({ state }) => {
4020
+ const { events } = state.get();
4021
+ return state.observable.pipe(
4022
+ map(applyFirstQueuedTransaction),
4023
+ distinctUntilChanged(),
4024
+ tap$1((next) => state.set("applyFirstQueuedTransaction", next)),
4025
+ catchError$1((error, caught) => {
4026
+ if (error instanceof ActionError)
4027
+ return state.set(
4028
+ "removeQueuedTransaction",
4029
+ (prev) => removeQueuedTransaction(prev, error.transactionId)
4030
+ ), events.next({
4031
+ type: "error",
4032
+ message: error.message,
4033
+ documentId: error.documentId,
4034
+ transactionId: error.transactionId,
4035
+ error
4036
+ }), caught;
4037
+ throw error;
4038
+ })
4039
+ ).subscribe({ error: (error) => state.set("setError", { error }) });
4040
+ }, subscribeToAppliedAndSubmitNextTransaction = ({
4041
+ state,
4042
+ instance
4043
+ }) => {
4044
+ const { events } = state.get();
4045
+ return state.observable.pipe(
4046
+ throttle(
4047
+ (s2) => (
4048
+ // if there is no outgoing transaction, we can throttle by the
4049
+ // initial outgoing throttle time…
4050
+ s2.outgoing ? (
4051
+ // …otherwise, wait until the outgoing has been cleared
4052
+ state.observable.pipe(first$1(({ outgoing }) => !outgoing))
4053
+ ) : timer(INITIAL_OUTGOING_THROTTLE_TIME)
4054
+ ),
4055
+ { leading: !1, trailing: !0 }
4056
+ ),
4057
+ map(transitionAppliedTransactionsToOutgoing),
4058
+ distinctUntilChanged((a2, b2) => a2.outgoing?.transactionId === b2.outgoing?.transactionId),
4059
+ tap$1((next) => state.set("transitionAppliedTransactionsToOutgoing", next)),
4060
+ map((s2) => s2.outgoing),
4061
+ distinctUntilChanged(),
4062
+ withLatestFrom(getClientState(instance, { apiVersion: API_VERSION$4 }).observable),
4063
+ concatMap(([outgoing, client]) => outgoing ? client.observable.action(outgoing.outgoingActions, {
4064
+ transactionId: outgoing.transactionId,
4065
+ skipCrossDatasetReferenceValidation: !0
4066
+ }).pipe(
4067
+ catchError$1((error) => (state.set("revertOutgoingTransaction", revertOutgoingTransaction), events.next({ type: "reverted", message: error.message, outgoing, error }), EMPTY)),
4068
+ map((result) => ({ result, outgoing }))
4069
+ ) : EMPTY),
4070
+ tap$1(({ outgoing, result }) => {
4071
+ state.set("cleanupOutgoingTransaction", cleanupOutgoingTransaction);
4072
+ for (const e3 of getDocumentEvents(outgoing)) events.next(e3);
4073
+ events.next({ type: "accepted", outgoing, result });
4074
+ })
4075
+ ).subscribe({ error: (error) => state.set("setError", { error }) });
4076
+ }, subscribeToSubscriptionsAndListenToDocuments = (context) => {
4077
+ const { state } = context, { events } = state.get();
4078
+ return state.observable.pipe(
4079
+ filter((s2) => !!s2.grants),
4080
+ map((s2) => Object.keys(s2.documentStates)),
4081
+ distinctUntilChanged((curr, next) => {
4082
+ if (curr.length !== next.length) return !1;
4083
+ const currSet = new Set(curr);
4084
+ return next.every((i2) => currSet.has(i2));
4085
+ }),
4086
+ startWith$1(/* @__PURE__ */ new Set()),
4087
+ pairwise$1(),
4088
+ switchMap((pair) => {
4089
+ const [curr, next] = pair.map((ids) => new Set(ids)), added = Array.from(next).filter((i2) => !curr.has(i2)), removed = Array.from(curr).filter((i2) => !next.has(i2)), changes = [
4090
+ ...added.map((id) => ({ id, add: !0 })),
4091
+ ...removed.map((id) => ({ id, add: !1 }))
4092
+ ].sort((a2, b2) => {
4093
+ const aIsDraft = a2.id === getDraftId(a2.id), bIsDraft = b2.id === getDraftId(b2.id);
4094
+ return aIsDraft && bIsDraft ? a2.id.localeCompare(b2.id, "en-US") : aIsDraft ? -1 : bIsDraft ? 1 : a2.id.localeCompare(b2.id, "en-US");
4095
+ });
4096
+ return of(...changes);
4097
+ }),
4098
+ groupBy$1((i2) => i2.id),
4099
+ mergeMap$1(
4100
+ (group) => group.pipe(
4101
+ switchMap((e3) => e3.add ? listen(context, e3.id).pipe(
4102
+ catchError$1((error) => {
4103
+ throw error instanceof OutOfSyncError && listen(context, e3.id), error;
4104
+ }),
4105
+ tap$1(
4106
+ (remote) => state.set(
4107
+ "applyRemoteDocument",
4108
+ (prev) => applyRemoteDocument(prev, remote, events)
4109
+ )
4063
4110
  )
4064
- )
4065
- ).subscribe({ error: (error) => state.set("setError", { error }) });
4066
- };
4111
+ ) : EMPTY)
4112
+ )
4113
+ )
4114
+ ).subscribe({ error: (error) => state.set("setError", { error }) });
4115
+ }, subscribeToClientAndFetchDatasetAcl = ({
4116
+ instance,
4117
+ state
4118
+ }) => {
4119
+ const { projectId, dataset } = instance.config;
4120
+ return getClientState(instance, { apiVersion: API_VERSION$4 }).observable.pipe(
4121
+ switchMap(
4122
+ (client) => client.observable.request({
4123
+ uri: `/projects/${projectId}/datasets/${dataset}/acl`,
4124
+ tag: "acl.get",
4125
+ withCredentials: !0
4126
+ })
4127
+ ),
4128
+ tap$1((datasetAcl) => state.set("setGrants", { grants: createGrantsLookup(datasetAcl) }))
4129
+ ).subscribe({
4130
+ error: (error) => state.set("setError", { error })
4131
+ });
4132
+ };
4133
+ function applyDocumentActions(...args) {
4134
+ return boundApplyDocumentActions(...args);
4135
+ }
4136
+ const boundApplyDocumentActions = bindActionByDataset(documentStore, _applyDocumentActions);
4137
+ async function _applyDocumentActions({ instance, state }, actionOrActions, { transactionId = crypto.randomUUID(), disableBatching } = {}) {
4138
+ const actions = Array.isArray(actionOrActions) ? actionOrActions : [actionOrActions];
4139
+ let projectId, dataset;
4140
+ for (const action of actions)
4141
+ if (action.projectId) {
4142
+ if (projectId || (projectId = action.projectId), action.projectId !== projectId)
4143
+ throw new Error(
4144
+ `Mismatched project IDs found in actions. All actions must belong to the same project. Found "${action.projectId}" but expected "${projectId}".`
4145
+ );
4146
+ if (action.dataset && (dataset || (dataset = action.dataset), action.dataset !== dataset))
4147
+ throw new Error(
4148
+ `Mismatched datasets found in actions. All actions must belong to the same dataset. Found "${action.dataset}" but expected "${dataset}".`
4149
+ );
4150
+ }
4151
+ if (projectId && projectId !== instance.config.projectId || dataset && dataset !== instance.config.dataset) {
4152
+ const matchedInstance = instance.match({ projectId, dataset });
4153
+ if (!matchedInstance)
4154
+ throw new Error(
4155
+ `Could not find a matching instance for projectId: "${projectId}" and dataset: "${dataset}"`
4156
+ );
4157
+ return boundApplyDocumentActions(matchedInstance, actionOrActions, {
4158
+ disableBatching,
4159
+ transactionId
4160
+ });
4067
4161
  }
4068
- ), subscribeToClientAndFetchDatasetAcl = createInternalAction(
4069
- ({ instance, state }) => {
4070
- const { projectId, dataset } = instance.identity;
4071
- return function() {
4072
- return getClientState(instance, { apiVersion: API_VERSION$2 }).observable.pipe(
4073
- switchMap(
4074
- (client) => client.observable.request({
4075
- uri: `/projects/${projectId}/datasets/${dataset}/acl`,
4076
- tag: "acl.get"
4077
- })
4078
- ),
4079
- tap$1((datasetAcl) => state.set("setGrants", { grants: createGrantsLookup(datasetAcl) }))
4080
- ).subscribe({
4081
- error: (error) => state.set("setError", { error })
4082
- });
4162
+ const { events } = state.get(), transaction = {
4163
+ transactionId,
4164
+ actions,
4165
+ ...disableBatching && { disableBatching }
4166
+ }, fatalError$ = state.observable.pipe(
4167
+ map((s2) => s2.error),
4168
+ first$1(Boolean),
4169
+ map((error) => ({ type: "error", error }))
4170
+ ), transactionError$ = events.pipe(
4171
+ filter((e3) => e3.type === "error"),
4172
+ first$1((e3) => e3.transactionId === transactionId)
4173
+ ), appliedTransaction$ = state.observable.pipe(
4174
+ map((s2) => s2.applied),
4175
+ distinctUntilChanged(),
4176
+ map((applied) => applied.find((t2) => t2.transactionId === transactionId)),
4177
+ first$1(Boolean)
4178
+ ), successfulTransaction$ = events.pipe(
4179
+ filter((e3) => e3.type === "accepted"),
4180
+ first$1((e3) => e3.outgoing.batchedTransactionIds.includes(transactionId))
4181
+ ), rejectedTransaction$ = events.pipe(
4182
+ filter((e3) => e3.type === "reverted"),
4183
+ first$1((e3) => e3.outgoing.batchedTransactionIds.includes(transactionId))
4184
+ ), appliedTransactionOrError = firstValueFrom(
4185
+ race([fatalError$, transactionError$, appliedTransaction$])
4186
+ ), acceptedOrRejectedTransaction = firstValueFrom(
4187
+ race([successfulTransaction$, rejectedTransaction$, transactionError$])
4188
+ );
4189
+ state.set("queueTransaction", (prev) => queueTransaction(prev, transaction));
4190
+ const result = await appliedTransactionOrError;
4191
+ if ("type" in result && result.type === "error") throw result.error;
4192
+ const { working: documents, previous, previousRevs } = result, existingIds = new Set(
4193
+ Object.entries(previous).filter(([, value]) => !!value).map(([key]) => key)
4194
+ ), resultingIds = new Set(
4195
+ Object.entries(documents).filter(([, value]) => !!value).map(([key]) => key)
4196
+ ), allIds = /* @__PURE__ */ new Set([...existingIds, ...resultingIds]), updated = [], appeared = [], disappeared = [];
4197
+ for (const id of allIds)
4198
+ existingIds.has(id) && resultingIds.has(id) ? updated.push(id) : !existingIds.has(id) && resultingIds.has(id) ? appeared.push(id) : !resultingIds.has(id) && existingIds.has(id) && disappeared.push(id);
4199
+ async function submitted() {
4200
+ const raceResult = await acceptedOrRejectedTransaction;
4201
+ if (raceResult.type !== "accepted") throw raceResult.error;
4202
+ return raceResult.result;
4203
+ }
4204
+ return {
4205
+ transactionId,
4206
+ documents,
4207
+ previous,
4208
+ previousRevs,
4209
+ appeared,
4210
+ updated,
4211
+ disappeared,
4212
+ submitted
4213
+ };
4214
+ }
4215
+ const QUERY_STATE_CLEAR_DELAY = 1e3, QUERY_STORE_API_VERSION = "vX", setQueryError = (key, error) => (prev) => {
4216
+ const prevQuery = prev.queries[key];
4217
+ return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, error } } } : prev;
4218
+ }, setQueryData = (key, result, syncTags) => (prev) => {
4219
+ const prevQuery = prev.queries[key];
4220
+ return prevQuery ? {
4221
+ ...prev,
4222
+ queries: { ...prev.queries, [key]: { ...prevQuery, result: result ?? null, syncTags } }
4223
+ } : prev;
4224
+ }, setLastLiveEventId = (key, lastLiveEventId) => (prev) => {
4225
+ const prevQuery = prev.queries[key];
4226
+ return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, lastLiveEventId } } } : prev;
4227
+ }, addSubscriber = (key, subscriptionId) => (prev) => {
4228
+ const prevQuery = prev.queries[key], subscribers = [...prevQuery?.subscribers ?? [], subscriptionId];
4229
+ return { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } };
4230
+ }, removeSubscriber = (key, subscriptionId) => (prev) => {
4231
+ const prevQuery = prev.queries[key];
4232
+ if (!prevQuery) return prev;
4233
+ const subscribers = prevQuery.subscribers.filter((id) => id !== subscriptionId);
4234
+ return subscribers.length ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } } : { ...prev, queries: omit(prev.queries, key) };
4235
+ }, cancelQuery = (key) => (prev) => {
4236
+ const prevQuery = prev.queries[key];
4237
+ return !prevQuery || prevQuery.subscribers.length ? prev : { ...prev, queries: omit(prev.queries, key) };
4238
+ }, initializeQuery = (key) => (prev) => prev.queries[key] ? prev : { ...prev, queries: { ...prev.queries, [key]: { subscribers: [] } } }, EMPTY_ARRAY = [], getQueryKey = (query, options = {}) => JSON.stringify({ query, options }), parseQueryKey = (key) => JSON.parse(key), queryStore = {
4239
+ name: "QueryStore",
4240
+ getInitialState: () => ({ queries: {} }),
4241
+ initialize(context) {
4242
+ const subscriptions = [
4243
+ listenForNewSubscribersAndFetch(context),
4244
+ listenToLiveClientAndSetLastLiveEventIds(context)
4245
+ ];
4246
+ return () => {
4247
+ for (const subscription of subscriptions)
4248
+ subscription.unsubscribe();
4083
4249
  };
4084
4250
  }
4085
- );
4086
- function applyDocumentActions(...args) {
4087
- return _applyDocumentActions(...args);
4251
+ }, errorHandler$1 = (state) => (error) => state.set("setError", { error }), listenForNewSubscribersAndFetch = ({ state, instance }) => state.observable.pipe(
4252
+ map((s2) => new Set(Object.keys(s2.queries))),
4253
+ distinctUntilChanged((curr, next) => curr.size !== next.size ? !1 : Array.from(next).every((i2) => curr.has(i2))),
4254
+ startWith$1(/* @__PURE__ */ new Set()),
4255
+ pairwise$1(),
4256
+ mergeMap$1(([curr, next]) => {
4257
+ const added = Array.from(next).filter((i2) => !curr.has(i2)), removed = Array.from(curr).filter((i2) => !next.has(i2));
4258
+ return [
4259
+ ...added.map((key) => ({ key, added: !0 })),
4260
+ ...removed.map((key) => ({ key, added: !1 }))
4261
+ ];
4262
+ }),
4263
+ groupBy$1((i2) => i2.key),
4264
+ mergeMap$1(
4265
+ (group$) => group$.pipe(
4266
+ switchMap((e3) => {
4267
+ if (!e3.added) return EMPTY;
4268
+ const lastLiveEventId$ = state.observable.pipe(
4269
+ map((s2) => s2.queries[group$.key]?.lastLiveEventId),
4270
+ distinctUntilChanged()
4271
+ ), { query, options: { params, projectId, dataset, tag, ...options } = {} } = parseQueryKey(group$.key), client$ = getClientState(instance, {
4272
+ apiVersion: QUERY_STORE_API_VERSION,
4273
+ projectId,
4274
+ dataset
4275
+ }).observable;
4276
+ return combineLatest([lastLiveEventId$, client$]).pipe(
4277
+ switchMap(
4278
+ ([lastLiveEventId, client]) => client.observable.fetch(query, params, {
4279
+ ...options,
4280
+ filterResponse: !1,
4281
+ returnQuery: !1,
4282
+ lastLiveEventId,
4283
+ tag
4284
+ })
4285
+ )
4286
+ );
4287
+ }),
4288
+ catchError$1((error) => (state.set("setQueryError", setQueryError(group$.key, error)), EMPTY)),
4289
+ tap$1(({ result, syncTags }) => {
4290
+ state.set("setQueryData", setQueryData(group$.key, result, syncTags));
4291
+ })
4292
+ )
4293
+ )
4294
+ ).subscribe({ error: errorHandler$1(state) }), listenToLiveClientAndSetLastLiveEventIds = ({
4295
+ state,
4296
+ instance
4297
+ }) => {
4298
+ const liveMessages$ = getClientState(instance, {
4299
+ apiVersion: QUERY_STORE_API_VERSION
4300
+ }).observable.pipe(
4301
+ switchMap(
4302
+ (client) => client.live.events({ includeDrafts: !!client.config().token, tag: "query-store" })
4303
+ ),
4304
+ share(),
4305
+ filter((e3) => e3.type === "message")
4306
+ );
4307
+ return state.observable.pipe(
4308
+ mergeMap$1((s2) => Object.entries(s2.queries)),
4309
+ groupBy$1(([key]) => key),
4310
+ mergeMap$1((group$) => {
4311
+ const syncTags$ = group$.pipe(
4312
+ map(([, queryState]) => queryState),
4313
+ map((i2) => i2?.syncTags ?? EMPTY_ARRAY),
4314
+ distinctUntilChanged()
4315
+ );
4316
+ return combineLatest([liveMessages$, syncTags$]).pipe(
4317
+ filter(([message, syncTags]) => message.tags.some((tag) => syncTags.includes(tag))),
4318
+ tap$1(([message]) => {
4319
+ state.set("setLastLiveEventId", setLastLiveEventId(group$.key, message.id));
4320
+ })
4321
+ );
4322
+ })
4323
+ ).subscribe({ error: errorHandler$1(state) });
4324
+ };
4325
+ function getQueryState(...args) {
4326
+ return _getQueryState(...args);
4088
4327
  }
4089
- const _applyDocumentActions = createAction(documentStore, ({ state }) => {
4090
- const { events } = state.get();
4091
- return async function(action, { transactionId = crypto.randomUUID(), disableBatching } = {}) {
4092
- const actions = Array.isArray(action) ? action : [action], transaction = {
4093
- transactionId,
4094
- actions,
4095
- ...disableBatching && { disableBatching }
4096
- }, fatalError$ = state.observable.pipe(
4097
- map((s2) => s2.error),
4098
- first$1(Boolean),
4099
- map((error) => ({ type: "error", error }))
4100
- ), transactionError$ = events.pipe(
4101
- filter((e3) => e3.type === "error"),
4102
- first$1((e3) => e3.transactionId === transactionId)
4103
- ), appliedTransaction$ = state.observable.pipe(
4104
- map((s2) => s2.applied),
4105
- distinctUntilChanged(),
4106
- map((applied) => applied.find((t2) => t2.transactionId === transactionId)),
4107
- first$1(Boolean)
4108
- ), successfulTransaction$ = events.pipe(
4109
- filter((e3) => e3.type === "accepted"),
4110
- first$1((e3) => e3.outgoing.batchedTransactionIds.includes(transactionId))
4111
- ), rejectedTransaction$ = events.pipe(
4112
- filter((e3) => e3.type === "reverted"),
4113
- first$1((e3) => e3.outgoing.batchedTransactionIds.includes(transactionId))
4114
- ), appliedTransactionOrError = firstValueFrom(
4115
- race([fatalError$, transactionError$, appliedTransaction$])
4116
- ), acceptedOrRejectedTransaction = firstValueFrom(
4117
- race([successfulTransaction$, rejectedTransaction$, transactionError$])
4118
- );
4119
- state.set("queueTransaction", (prev) => queueTransaction(prev, transaction));
4120
- const result = await appliedTransactionOrError;
4121
- if ("type" in result && result.type === "error") throw result.error;
4122
- const { working: documents, previous, previousRevs } = result, existingIds = new Set(
4123
- Object.entries(previous).filter(([, value]) => !!value).map(([key]) => key)
4124
- ), resultingIds = new Set(
4125
- Object.entries(documents).filter(([, value]) => !!value).map(([key]) => key)
4126
- ), allIds = /* @__PURE__ */ new Set([...existingIds, ...resultingIds]), updated = [], appeared = [], disappeared = [];
4127
- for (const id of allIds)
4128
- existingIds.has(id) && resultingIds.has(id) ? updated.push(id) : !existingIds.has(id) && resultingIds.has(id) ? appeared.push(id) : !resultingIds.has(id) && existingIds.has(id) && disappeared.push(id);
4129
- async function submitted() {
4130
- const raceResult = await acceptedOrRejectedTransaction;
4131
- if (raceResult.type !== "accepted") throw raceResult.error;
4132
- return raceResult.result;
4328
+ const _getQueryState = bindActionByDataset(
4329
+ queryStore,
4330
+ createStateSourceAction({
4331
+ selector: ({ state }, query, options) => {
4332
+ if (state.error) throw state.error;
4333
+ const key = getQueryKey(query, options), queryState = state.queries[key];
4334
+ if (queryState?.error) throw queryState.error;
4335
+ return queryState?.result;
4336
+ },
4337
+ onSubscribe: ({ state }, query, options) => {
4338
+ const subscriptionId = insecureRandomId(), key = getQueryKey(query, options);
4339
+ return state.set("addSubscriber", addSubscriber(key, subscriptionId)), () => {
4340
+ setTimeout(
4341
+ () => state.set("removeSubscriber", removeSubscriber(key, subscriptionId)),
4342
+ QUERY_STATE_CLEAR_DELAY
4343
+ );
4344
+ };
4133
4345
  }
4134
- return {
4135
- transactionId,
4136
- documents,
4137
- previous,
4138
- previousRevs,
4139
- appeared,
4140
- updated,
4141
- disappeared,
4142
- submitted
4143
- };
4144
- };
4145
- });
4146
- function getSdkIdentity({
4147
- projectId,
4148
- dataset
4149
- }) {
4150
- const id = generateId();
4151
- return Object.freeze({
4152
- id,
4153
- projectId,
4154
- dataset,
4155
- resourceId: `${projectId}.${dataset}`
4156
- });
4157
- }
4158
- function generateId() {
4159
- return Array.from(
4160
- { length: 8 },
4161
- () => Math.floor(Math.random() * 16).toString(16).padStart(2, "0")
4162
- ).join("");
4163
- }
4164
- function createSanityInstance({
4165
- projectId = "",
4166
- dataset = "",
4167
- ...config
4168
- }) {
4169
- const identity = getSdkIdentity({ projectId, dataset });
4170
- return {
4171
- identity,
4172
- config,
4173
- dispose: () => disposeResources(identity)
4174
- };
4346
+ })
4347
+ );
4348
+ function resolveQuery(...args) {
4349
+ return _resolveQuery(...args);
4175
4350
  }
4176
- function createLiveEventSubscriber(tag) {
4177
- return createInternalAction(({ instance, state }) => {
4178
- const client$ = getClientState(instance, { apiVersion: "vX" }).observable, syncTags$ = state.observable.pipe(
4179
- map((i2) => i2.syncTags),
4180
- distinctUntilChanged()
4351
+ const _resolveQuery = bindActionByDataset(
4352
+ queryStore,
4353
+ ({ state, instance }, query, { signal, ...options } = {}) => {
4354
+ const { getCurrent } = getQueryState(instance, query, options), key = getQueryKey(query, options), aborted$ = signal ? new Observable((observer) => {
4355
+ const cleanup = () => {
4356
+ signal.removeEventListener("abort", listener);
4357
+ }, listener = () => {
4358
+ observer.error(new DOMException("The operation was aborted.", "AbortError")), observer.complete(), cleanup();
4359
+ };
4360
+ return signal.addEventListener("abort", listener), cleanup;
4361
+ }).pipe(
4362
+ catchError$1((error) => {
4363
+ throw error instanceof Error && error.name === "AbortError" && state.set("cancelQuery", cancelQuery(key)), error;
4364
+ })
4365
+ ) : NEVER;
4366
+ state.set("initializeQuery", initializeQuery(key));
4367
+ const resolved$ = state.observable.pipe(
4368
+ map(getCurrent),
4369
+ first$1((i2) => i2 !== void 0)
4181
4370
  );
4182
- return function() {
4183
- const messageEvents$ = client$.pipe(
4184
- switchMap(
4185
- (client) => client.live.events({ includeDrafts: !!client.config().token, tag }).pipe(filter((e3) => e3.type === "message"))
4186
- )
4187
- );
4188
- return combineLatest([messageEvents$, syncTags$]).subscribe({
4189
- next: ([event, currentSyncTags]) => {
4190
- for (const eventTag of event.tags)
4191
- if (currentSyncTags[eventTag]) {
4192
- state.set("setLastLiveEventId", (prevState) => ({
4193
- ...prevState,
4194
- lastLiveEventId: event.id
4195
- }));
4196
- return;
4197
- }
4198
- }
4199
- });
4200
- };
4201
- });
4202
- }
4371
+ return firstValueFrom(race([resolved$, aborted$]));
4372
+ }
4373
+ );
4203
4374
  function hashString(str) {
4204
4375
  let hash = 0;
4205
4376
  for (let i2 = 0; i2 < str.length; i2++)
4206
4377
  hash = (hash * 31 + str.charCodeAt(i2)) % 2147483647;
4207
4378
  return Math.abs(hash).toString(16).padStart(8, "0");
4208
4379
  }
4209
- const TITLE_CANDIDATES = ["title", "name", "label", "heading", "header", "caption"], SUBTITLE_CANDIDATES = ["description", "subtitle", ...TITLE_CANDIDATES];
4210
- function getPreviewProjection() {
4211
- return `{
4212
- // Get all potential title fields
4213
- "titleCandidates": {
4214
- ${TITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
4380
+ const TITLE_CANDIDATES = ["title", "name", "label", "heading", "header", "caption"], SUBTITLE_CANDIDATES = ["description", "subtitle", ...TITLE_CANDIDATES], PREVIEW_PROJECTION = `{
4381
+ // Get all potential title fields
4382
+ "titleCandidates": {
4383
+ ${TITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
4215
4384
  `)}
4216
- },
4217
- // Get all potential subtitle fields
4218
- "subtitleCandidates": {
4219
- ${SUBTITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
4385
+ },
4386
+ // Get all potential subtitle fields
4387
+ "subtitleCandidates": {
4388
+ ${SUBTITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
4220
4389
  `)}
4221
- },
4222
- "media": coalesce(
4223
- select(
4224
- defined(asset) => {"type": "image-asset", "_ref": asset._ref},
4225
- defined(image.asset) => {"type": "image-asset", "_ref": image.asset._ref},
4226
- defined(mainImage.asset) => {"type": "image-asset", "_ref": mainImage.asset._ref},
4227
- null
4228
- )
4229
- ),
4230
- _type,
4231
- _id,
4232
- _updatedAt
4233
- }`;
4234
- }
4235
- const PREVIEW_TAG = "preview", STABLE_EMPTY_PREVIEW = { data: null, isPending: !1 }, STABLE_ERROR_PREVIEW = {
4390
+ },
4391
+ "media": coalesce(
4392
+ select(
4393
+ defined(asset) => {"type": "image-asset", "_ref": asset._ref},
4394
+ defined(image.asset) => {"type": "image-asset", "_ref": image.asset._ref},
4395
+ defined(mainImage.asset) => {"type": "image-asset", "_ref": mainImage.asset._ref},
4396
+ null
4397
+ )
4398
+ ),
4399
+ _type,
4400
+ _id,
4401
+ _updatedAt
4402
+ }`, PREVIEW_TAG = "preview", PREVIEW_PERSPECTIVE = "drafts", STABLE_EMPTY_PREVIEW = { data: null, isPending: !1 }, STABLE_ERROR_PREVIEW = {
4236
4403
  data: {
4237
4404
  title: "Preview Error",
4238
4405
  ...!!getEnv("DEV") && { subtitle: "Check the console for more details" }
@@ -4296,104 +4463,92 @@ function processPreviewQuery({
4296
4463
  );
4297
4464
  }
4298
4465
  function createPreviewQuery(documentIds) {
4299
- const allIds = Array.from(documentIds).flatMap((id) => [getPublishedId(id), getDraftId(id)]), projection = getPreviewProjection(), queryHash = hashString(projection);
4466
+ const allIds = Array.from(documentIds).flatMap((id) => [getPublishedId(id), getDraftId(id)]), queryHash = hashString(PREVIEW_PROJECTION);
4300
4467
  return {
4301
- query: `*[_id in $__ids_${queryHash}]${projection}`,
4468
+ query: `*[_id in $__ids_${queryHash}]${PREVIEW_PROJECTION}`,
4302
4469
  params: {
4303
4470
  [`__ids_${queryHash}`]: allIds
4304
4471
  }
4305
4472
  };
4306
4473
  }
4307
- const BATCH_DEBOUNCE_TIME$1 = 50, subscribeToStateAndFetchBatches$1 = createInternalAction(
4308
- ({ state, instance }) => function() {
4309
- const client$ = getClientState(instance, { apiVersion: "vX" }).observable, documentTypes$ = state.observable.pipe(
4310
- map((i2) => i2.documentTypes),
4311
- distinctUntilChanged()
4312
- ), lastLiveEventId$ = state.observable.pipe(
4313
- map((i2) => i2.lastLiveEventId),
4314
- distinctUntilChanged()
4315
- ), newSubscriberIds$ = state.observable.pipe(
4316
- map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
4317
- distinctUntilChanged(
4318
- (a2, b2) => a2.size !== b2.size ? !1 : Array.from(a2).every((i2) => b2.has(i2))
4319
- ),
4320
- debounceTime(BATCH_DEBOUNCE_TIME$1),
4321
- startWith$1(/* @__PURE__ */ new Set()),
4322
- pairwise$1(),
4323
- tap$1(([prevIds, currIds]) => {
4324
- const newIds = [...currIds].filter((element) => !prevIds.has(element));
4325
- state.set("updatingPending", (prev) => {
4326
- const pendingValues = newIds.reduce((acc, id) => {
4327
- const prevValue = prev.values[id], value = prevValue?.data ? prevValue.data : null;
4328
- return acc[id] = { data: value, isPending: !0 }, acc;
4329
- }, {});
4330
- return { values: { ...prev.values, ...pendingValues } };
4331
- });
4332
- }),
4333
- withLatestFrom(documentTypes$),
4334
- map(([[, ids], documentTypes]) => ({ ids, documentTypes }))
4335
- );
4336
- return combineLatest([newSubscriberIds$, lastLiveEventId$, client$]).pipe(
4337
- switchMap(([{ ids }, lastLiveEventId, client]) => {
4338
- if (!ids.size) return EMPTY;
4339
- const { query, params } = createPreviewQuery(ids);
4340
- return client.observable.fetch(query, params, {
4341
- filterResponse: !1,
4342
- returnQuery: !1,
4343
- perspective: "drafts",
4474
+ const BATCH_DEBOUNCE_TIME$1 = 50, isSetEqual$1 = (a2, b2) => a2.size === b2.size && Array.from(a2).every((i2) => b2.has(i2)), subscribeToStateAndFetchBatches$1 = ({
4475
+ state,
4476
+ instance
4477
+ }) => state.observable.pipe(
4478
+ map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
4479
+ distinctUntilChanged(isSetEqual$1),
4480
+ debounceTime(BATCH_DEBOUNCE_TIME$1),
4481
+ startWith$1(/* @__PURE__ */ new Set()),
4482
+ pairwise$1(),
4483
+ tap$1(([prevIds, currIds]) => {
4484
+ const newIds = [...currIds].filter((element) => !prevIds.has(element));
4485
+ state.set("updatingPending", (prev) => {
4486
+ const pendingValues = newIds.reduce((acc, id) => {
4487
+ const prevValue = prev.values[id], value = prevValue?.data ? prevValue.data : null;
4488
+ return acc[id] = { data: value, isPending: !0 }, acc;
4489
+ }, {});
4490
+ return { values: { ...prev.values, ...pendingValues } };
4491
+ });
4492
+ }),
4493
+ map(([, ids]) => ids),
4494
+ distinctUntilChanged(isSetEqual$1)
4495
+ ).pipe(
4496
+ switchMap((ids) => {
4497
+ if (!ids.size) return EMPTY;
4498
+ const { query, params } = createPreviewQuery(ids), controller = new AbortController();
4499
+ return new Observable((observer) => {
4500
+ const { getCurrent, observable } = getQueryState(instance, query, {
4501
+ params,
4502
+ tag: PREVIEW_TAG,
4503
+ perspective: PREVIEW_PERSPECTIVE
4504
+ }), subscription = defer(() => getCurrent() === void 0 ? from(
4505
+ resolveQuery(instance, query, {
4506
+ params,
4344
4507
  tag: PREVIEW_TAG,
4345
- lastLiveEventId
4346
- }).pipe(map((response) => ({ ...response, ids })));
4347
- }),
4348
- map(({ ids, result, syncTags }) => ({
4349
- syncTags,
4350
- values: processPreviewQuery({
4351
- projectId: instance.identity.projectId,
4352
- dataset: instance.identity.dataset,
4353
- ids,
4354
- results: result
4508
+ perspective: PREVIEW_PERSPECTIVE,
4509
+ signal: controller.signal
4355
4510
  })
4356
- }))
4357
- ).subscribe({
4358
- next: ({ syncTags = [], values }) => {
4359
- state.set("updateResult", (prev) => ({
4360
- values: { ...prev.values, ...values },
4361
- syncTags: syncTags.reduce((acc, next) => (acc[next] = !0, acc), {})
4362
- }));
4363
- }
4364
- });
4511
+ ).pipe(switchMap(() => observable)) : observable).pipe(filter((result) => result !== void 0)).subscribe(observer);
4512
+ return () => {
4513
+ controller.signal.aborted || controller.abort(), subscription.unsubscribe();
4514
+ };
4515
+ }).pipe(map((data) => ({ data, ids })));
4516
+ }),
4517
+ map(({ ids, data }) => ({
4518
+ values: processPreviewQuery({
4519
+ projectId: instance.config.projectId,
4520
+ dataset: instance.config.dataset,
4521
+ ids,
4522
+ results: data
4523
+ })
4524
+ }))
4525
+ ).subscribe({
4526
+ next: ({ values }) => {
4527
+ state.set("updateResult", (prev) => ({ values: { ...prev.values, ...values } }));
4365
4528
  }
4366
- ), previewStore = {
4529
+ }), previewStore = {
4367
4530
  name: "Preview",
4368
4531
  getInitialState() {
4369
4532
  return {
4370
- documentTypes: {},
4371
- lastLiveEventId: null,
4372
4533
  subscriptions: {},
4373
- syncTags: {},
4374
4534
  values: {}
4375
4535
  };
4376
4536
  },
4377
- initialize() {
4378
- const subscribeToLiveAndSetLastLiveEventId = createLiveEventSubscriber(PREVIEW_TAG), stateSubscriptionForBatches = subscribeToStateAndFetchBatches$1(this), liveSubscription = subscribeToLiveAndSetLastLiveEventId(this);
4379
- return () => {
4380
- stateSubscriptionForBatches.unsubscribe(), liveSubscription.unsubscribe();
4381
- };
4537
+ initialize: (context) => {
4538
+ const subscription = subscribeToStateAndFetchBatches$1(context);
4539
+ return () => subscription.unsubscribe;
4382
4540
  }
4383
- }, _getPreviewState = createStateSourceAction(
4541
+ };
4542
+ function getPreviewState(...args) {
4543
+ return _getPreviewState(...args);
4544
+ }
4545
+ const _getPreviewState = bindActionByDataset(
4384
4546
  previewStore,
4385
- (state, { document }) => state.values[document._id] ?? STABLE_EMPTY_PREVIEW
4386
- ), getPreviewState = createAction(previewStore, ({ state }) => function({ document }) {
4387
- const { _id, _type: documentType } = document, documentId = getPublishedId(_id), previewState = _getPreviewState(this, { document });
4388
- return {
4389
- ...previewState,
4390
- subscribe: (subscriber) => {
4391
- const subscriptionId = insecureRandomId();
4392
- state.set("addSubscription", (prev) => ({
4393
- documentTypes: {
4394
- ...prev.documentTypes,
4395
- [documentId]: documentType
4396
- },
4547
+ createStateSourceAction({
4548
+ selector: ({ state }, docHandle) => state.values[docHandle.documentId] ?? STABLE_EMPTY_PREVIEW,
4549
+ onSubscribe: ({ state }, docHandle) => {
4550
+ const subscriptionId = insecureRandomId(), documentId = getPublishedId(docHandle.documentId);
4551
+ return state.set("addSubscription", (prev) => ({
4397
4552
  subscriptions: {
4398
4553
  ...prev.subscriptions,
4399
4554
  [documentId]: {
@@ -4401,10 +4556,8 @@ const BATCH_DEBOUNCE_TIME$1 = 50, subscribeToStateAndFetchBatches$1 = createInte
4401
4556
  [subscriptionId]: !0
4402
4557
  }
4403
4558
  }
4404
- }));
4405
- const unsubscribe = previewState.subscribe(subscriber);
4406
- return () => {
4407
- unsubscribe(), state.set("removeSubscription", (prev) => {
4559
+ })), () => {
4560
+ state.set("removeSubscription", (prev) => {
4408
4561
  const documentSubscriptions = omit(prev.subscriptions[documentId], subscriptionId), hasSubscribers = !!Object.keys(documentSubscriptions).length, prevValue = prev.values[documentId], previewValue = prevValue?.data ? prevValue.data : null;
4409
4562
  return {
4410
4563
  subscriptions: hasSubscribers ? { ...prev.subscriptions, [documentId]: documentSubscriptions } : omit(prev.subscriptions, documentId),
@@ -4413,22 +4566,34 @@ const BATCH_DEBOUNCE_TIME$1 = 50, subscribeToStateAndFetchBatches$1 = createInte
4413
4566
  });
4414
4567
  };
4415
4568
  }
4416
- };
4417
- }), resolvePreview = createAction(previewStore, () => function({ document }) {
4418
- const { getCurrent, subscribe } = getPreviewState(this, { document });
4419
- return new Promise((resolve) => {
4420
- const unsubscribe = subscribe(() => {
4421
- const current = getCurrent();
4422
- current?.data && (resolve(current), unsubscribe());
4423
- });
4424
- });
4425
- }), project = createFetcherStore({
4569
+ })
4570
+ ), resolvePreview = bindActionByDataset(
4571
+ previewStore,
4572
+ ({ instance }, docHandle) => firstValueFrom(getPreviewState(instance, docHandle).observable.pipe(filter((i2) => !!i2.data)))
4573
+ ), API_VERSION$2 = "v2025-02-19", project = createFetcherStore({
4426
4574
  name: "Project",
4427
- getKey: (projectId) => projectId,
4428
- fetcher: (instance) => (projectId) => getClientState(instance, { apiVersion: "vX", scope: "global" }).observable.pipe(
4429
- switchMap((client) => client.observable.projects.getById(projectId))
4430
- )
4431
- }), getProjectState = project.getState, resolveProject = project.resolveState, PROJECTION_TAG = "sdk.projection", STABLE_EMPTY_PROJECTION = {
4575
+ getKey: (instance, options) => {
4576
+ const projectId = options?.projectId ?? instance.config.projectId;
4577
+ if (!projectId)
4578
+ throw new Error("A projectId is required to use the project API.");
4579
+ return projectId;
4580
+ },
4581
+ fetcher: (instance) => (options = {}) => {
4582
+ const projectId = options.projectId ?? instance.config.projectId;
4583
+ return getClientState(instance, {
4584
+ apiVersion: API_VERSION$2,
4585
+ scope: "global",
4586
+ projectId
4587
+ }).observable.pipe(
4588
+ switchMap(
4589
+ (client) => client.observable.projects.getById(
4590
+ // non-null assertion is fine with the above throwing
4591
+ projectId ?? instance.config.projectId
4592
+ )
4593
+ )
4594
+ );
4595
+ }
4596
+ }), getProjectState = project.getState, resolveProject = project.resolveState, PROJECTION_TAG = "sdk.projection", PROJECTION_PERSPECTIVE = "drafts", PROJECTION_STATE_CLEAR_DELAY = 1e3, STABLE_EMPTY_PROJECTION = {
4432
4597
  data: null,
4433
4598
  isPending: !1
4434
4599
  };
@@ -4474,99 +4639,92 @@ function processProjectionQuery({ ids, results }) {
4474
4639
  })
4475
4640
  );
4476
4641
  }
4477
- const BATCH_DEBOUNCE_TIME = 50, subscribeToStateAndFetchBatches = createInternalAction(
4478
- ({ state, instance }) => function() {
4479
- const client$ = new Observable(
4480
- (observer) => getClientState(instance, { apiVersion: "vX" }).observable.subscribe(observer)
4481
- ), documentProjections$ = state.observable.pipe(
4482
- map((i2) => i2.documentProjections),
4483
- distinctUntilChanged()
4484
- ), lastLiveEventId$ = state.observable.pipe(
4485
- map((i2) => i2.lastLiveEventId),
4486
- distinctUntilChanged()
4487
- ), newSubscriberIds$ = state.observable.pipe(
4488
- map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
4489
- distinctUntilChanged(
4490
- (a2, b2) => a2.size !== b2.size ? !1 : Array.from(a2).every((i2) => b2.has(i2))
4491
- ),
4492
- debounceTime(BATCH_DEBOUNCE_TIME),
4493
- startWith$1(/* @__PURE__ */ new Set()),
4494
- pairwise$1(),
4495
- tap$1(([prevIds, currIds]) => {
4496
- const newIds = [...currIds].filter((element) => !prevIds.has(element));
4497
- state.set("updatingPending", (prev) => {
4498
- const pendingValues = newIds.reduce((acc, id) => {
4499
- const prevValue = prev.values[id], value = prevValue?.data ? prevValue.data : null;
4500
- return acc[id] = { data: value, isPending: !0 }, acc;
4501
- }, {});
4502
- return { values: { ...prev.values, ...pendingValues } };
4503
- });
4504
- }),
4505
- withLatestFrom(documentProjections$),
4506
- map(([[, ids], documentProjections]) => ({ ids, documentProjections }))
4507
- );
4508
- return combineLatest([newSubscriberIds$, lastLiveEventId$, client$]).pipe(
4509
- switchMap(([{ ids, documentProjections }, lastLiveEventId, client]) => {
4510
- if (!ids.size) return EMPTY;
4511
- const { query, params } = createProjectionQuery(ids, documentProjections);
4512
- return client.observable.fetch(query, params, {
4513
- filterResponse: !1,
4514
- returnQuery: !1,
4515
- perspective: "drafts",
4642
+ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a2, b2) => a2.size === b2.size && Array.from(a2).every((i2) => b2.has(i2)), subscribeToStateAndFetchBatches = ({
4643
+ state,
4644
+ instance
4645
+ }) => {
4646
+ const documentProjections$ = state.observable.pipe(
4647
+ map((i2) => i2.documentProjections),
4648
+ distinctUntilChanged()
4649
+ ), newSubscriberIds$ = state.observable.pipe(
4650
+ map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
4651
+ distinctUntilChanged(isSetEqual),
4652
+ debounceTime(BATCH_DEBOUNCE_TIME),
4653
+ startWith$1(/* @__PURE__ */ new Set()),
4654
+ pairwise$1(),
4655
+ tap$1(([prevIds, currIds]) => {
4656
+ const newIds = [...currIds].filter((element) => !prevIds.has(element));
4657
+ state.set("updatingPending", (prev) => {
4658
+ const pendingValues = newIds.reduce((acc, id) => {
4659
+ const prevValue = prev.values[id], value = prevValue?.data ? prevValue.data : null;
4660
+ return acc[id] = { data: value, isPending: !0 }, acc;
4661
+ }, {});
4662
+ return { values: { ...prev.values, ...pendingValues } };
4663
+ });
4664
+ }),
4665
+ map(([, ids]) => ids),
4666
+ distinctUntilChanged(isSetEqual)
4667
+ );
4668
+ return combineLatest([newSubscriberIds$, documentProjections$]).pipe(
4669
+ distinctUntilChanged(isEqual),
4670
+ switchMap(([ids, documentProjections]) => {
4671
+ if (!ids.size) return EMPTY;
4672
+ const { query, params } = createProjectionQuery(ids, documentProjections), controller = new AbortController();
4673
+ return new Observable((observer) => {
4674
+ const { getCurrent, observable } = getQueryState(instance, query, {
4675
+ params,
4516
4676
  tag: PROJECTION_TAG,
4517
- lastLiveEventId
4518
- }).pipe(map((response) => ({ ...response, ids })));
4519
- }),
4520
- map(({ ids, result, syncTags }) => ({
4521
- syncTags,
4522
- values: processProjectionQuery({
4523
- ids,
4524
- results: result
4525
- })
4526
- }))
4527
- ).subscribe({
4528
- next: ({ syncTags = [], values }) => {
4529
- state.set("updateResult", (prev) => ({
4530
- values: { ...prev.values, ...values },
4531
- syncTags: syncTags.reduce((acc, next) => (acc[next] = !0, acc), {})
4532
- }));
4533
- }
4534
- });
4535
- }
4536
- ), projectionStore = {
4677
+ perspective: PROJECTION_PERSPECTIVE
4678
+ }), subscription = defer(() => getCurrent() === void 0 ? from(
4679
+ resolveQuery(instance, query, {
4680
+ params,
4681
+ tag: PROJECTION_TAG,
4682
+ perspective: PROJECTION_PERSPECTIVE,
4683
+ signal: controller.signal
4684
+ })
4685
+ ).pipe(switchMap(() => observable)) : observable).pipe(filter((result) => result !== void 0)).subscribe(observer);
4686
+ return () => {
4687
+ controller.signal.aborted || controller.abort(), subscription.unsubscribe();
4688
+ };
4689
+ }).pipe(map((data) => ({ data, ids })));
4690
+ }),
4691
+ map(({ ids, data }) => ({
4692
+ values: processProjectionQuery({
4693
+ ids,
4694
+ results: data
4695
+ })
4696
+ }))
4697
+ ).subscribe({
4698
+ next: ({ values }) => {
4699
+ state.set("updateResult", (prev) => ({
4700
+ values: { ...prev.values, ...values }
4701
+ }));
4702
+ }
4703
+ });
4704
+ }, projectionStore = {
4537
4705
  name: "Projection",
4538
4706
  getInitialState() {
4539
4707
  return {
4540
4708
  values: {},
4541
4709
  documentProjections: {},
4542
- subscriptions: {},
4543
- syncTags: {},
4544
- lastLiveEventId: null
4710
+ subscriptions: {}
4545
4711
  };
4546
4712
  },
4547
- initialize() {
4548
- const liveSubscription = createLiveEventSubscriber(PROJECTION_TAG)(this), batchSubscription = subscribeToStateAndFetchBatches(this);
4549
- return () => {
4550
- liveSubscription.unsubscribe(), batchSubscription.unsubscribe();
4551
- };
4713
+ initialize(context) {
4714
+ const batchSubscription = subscribeToStateAndFetchBatches(context);
4715
+ return () => batchSubscription.unsubscribe();
4552
4716
  }
4553
- }, getProjectStateSourceAction = createStateSourceAction(
4554
- projectionStore,
4555
- (state, { document }) => state.values[document._id] ?? STABLE_EMPTY_PROJECTION
4556
- );
4717
+ };
4557
4718
  function getProjectionState(...args) {
4558
4719
  return _getProjectionState(...args);
4559
4720
  }
4560
- const _getProjectionState = createAction(projectionStore, ({ state }) => function({
4561
- document,
4562
- projection
4563
- }) {
4564
- const { _id } = document, documentId = getPublishedId(_id), projectionState = getProjectStateSourceAction(this, { document, projection });
4565
- return {
4566
- ...projectionState,
4567
- subscribe: (subscriber) => {
4568
- const subscriptionId = insecureRandomId();
4569
- state.set("addSubscription", (prev) => ({
4721
+ const _getProjectionState = bindActionByDataset(
4722
+ projectionStore,
4723
+ createStateSourceAction({
4724
+ selector: ({ state }, options) => state.values[options.documentId] ?? STABLE_EMPTY_PROJECTION,
4725
+ onSubscribe: ({ state }, { projection, ...docHandle }) => {
4726
+ const subscriptionId = insecureRandomId(), documentId = getPublishedId(docHandle.documentId);
4727
+ return state.set("addSubscription", (prev) => ({
4570
4728
  documentProjections: {
4571
4729
  ...prev.documentProjections,
4572
4730
  [documentId]: validateProjection(projection)
@@ -4578,275 +4736,180 @@ const _getProjectionState = createAction(projectionStore, ({ state }) => functio
4578
4736
  [subscriptionId]: !0
4579
4737
  }
4580
4738
  }
4581
- }));
4582
- const unsubscribe = projectionState.subscribe(subscriber);
4583
- return () => {
4584
- unsubscribe(), state.set("removeSubscription", (prev) => {
4585
- const documentSubscriptions = omit(prev.subscriptions[documentId], subscriptionId), hasSubscribers = !!Object.keys(documentSubscriptions).length, prevValue = prev.values[documentId], projectionValue = prevValue?.data ? prevValue.data : null;
4586
- return {
4587
- subscriptions: hasSubscribers ? { ...prev.subscriptions, [documentId]: documentSubscriptions } : omit(prev.subscriptions, documentId),
4588
- values: hasSubscribers ? prev.values : { ...prev.values, [documentId]: { data: projectionValue, isPending: !1 } }
4589
- };
4590
- });
4739
+ })), () => {
4740
+ setTimeout(() => {
4741
+ state.set("removeSubscription", (prev) => {
4742
+ const documentSubscriptions = omit(prev.subscriptions[documentId], subscriptionId), hasSubscribers = !!Object.keys(documentSubscriptions).length, prevValue = prev.values[documentId], projectionValue = prevValue?.data ? prevValue.data : null;
4743
+ return {
4744
+ subscriptions: hasSubscribers ? { ...prev.subscriptions, [documentId]: documentSubscriptions } : omit(prev.subscriptions, documentId),
4745
+ values: hasSubscribers ? prev.values : { ...prev.values, [documentId]: { data: projectionValue, isPending: !1 } }
4746
+ };
4747
+ });
4748
+ }, PROJECTION_STATE_CLEAR_DELAY);
4591
4749
  };
4592
4750
  }
4593
- };
4594
- }), resolveProjection = createAction(projectionStore, () => function({ document, projection }) {
4595
- const { getCurrent, subscribe } = getProjectionState(this, { document, projection });
4596
- return new Promise((resolve) => {
4597
- const unsubscribe = subscribe(() => {
4598
- const current = getCurrent();
4599
- current?.data && (resolve(current), unsubscribe());
4600
- });
4601
- });
4602
- }), projects = createFetcherStore({
4751
+ })
4752
+ ), resolveProjection = bindActionByDataset(
4753
+ projectionStore,
4754
+ ({ instance }, { projection, ...docHandle }) => firstValueFrom(
4755
+ getProjectionState(instance, { ...docHandle, projection }).observable.pipe(
4756
+ filter((i2) => !!i2.data)
4757
+ )
4758
+ )
4759
+ ), API_VERSION$1 = "v2025-02-19", projects = createFetcherStore({
4603
4760
  name: "Projects",
4604
4761
  getKey: () => "projects",
4605
- fetcher: (instance) => () => getClientState(instance, { apiVersion: "vX", scope: "global" }).observable.pipe(
4762
+ fetcher: (instance) => () => getClientState(instance, {
4763
+ apiVersion: API_VERSION$1,
4764
+ scope: "global"
4765
+ }).observable.pipe(
4606
4766
  switchMap((client) => client.observable.projects.list({ includeMembers: !1 }))
4607
4767
  )
4608
- }), getProjectsState = projects.getState, resolveProjects = projects.resolveState, QUERY_STATE_CLEAR_DELAY = 1e3, setQueryError = (key, error) => (prev) => {
4609
- const prevQuery = prev.queries[key];
4610
- return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, error } } } : prev;
4611
- }, setQueryData = (key, result, syncTags) => (prev) => {
4612
- const prevQuery = prev.queries[key];
4613
- return prevQuery ? {
4614
- ...prev,
4615
- queries: { ...prev.queries, [key]: { ...prevQuery, result: result ?? null, syncTags } }
4616
- } : prev;
4617
- }, setLastLiveEventId = (key, lastLiveEventId) => (prev) => {
4618
- const prevQuery = prev.queries[key];
4619
- return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, lastLiveEventId } } } : prev;
4620
- }, addSubscriber = (key, subscriptionId) => (prev) => {
4621
- const prevQuery = prev.queries[key], subscribers = [...prevQuery?.subscribers ?? [], subscriptionId];
4622
- return { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } };
4623
- }, removeSubscriber = (key, subscriptionId) => (prev) => {
4624
- const prevQuery = prev.queries[key];
4625
- if (!prevQuery) return prev;
4626
- const subscribers = prevQuery.subscribers.filter((id) => id !== subscriptionId);
4627
- return subscribers.length ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } } : { ...prev, queries: omit(prev.queries, key) };
4628
- }, cancelQuery = (key) => (prev) => {
4629
- const prevQuery = prev.queries[key];
4630
- return !prevQuery || prevQuery.subscribers.length ? prev : { ...prev, queries: omit(prev.queries, key) };
4631
- }, initializeQuery = (key) => (prev) => prev.queries[key] ? prev : { ...prev, queries: { ...prev.queries, [key]: { subscribers: [] } } }, EMPTY_ARRAY = [], getQueryKey = (query, options = {}) => JSON.stringify({ query, options }), parseQueryKey = (key) => JSON.parse(key), queryStore = {
4632
- name: "QueryStore",
4633
- getInitialState: () => ({ queries: {} }),
4634
- initialize() {
4635
- const subscriptions = [
4636
- listenForNewSubscribersAndFetch(this),
4637
- listenToLiveClientAndSetLastLiveEventIds(this)
4638
- ];
4639
- return () => {
4640
- for (const subscription of subscriptions)
4641
- subscription.unsubscribe();
4642
- };
4643
- }
4644
- }, errorHandler = createInternalAction(({ state }) => function() {
4645
- return (error) => state.set("setError", { error });
4646
- }), listenForNewSubscribersAndFetch = createInternalAction(
4647
- ({ state, instance }) => function() {
4648
- return state.observable.pipe(
4649
- map((s2) => new Set(Object.keys(s2.queries))),
4650
- distinctUntilChanged((curr, next) => curr.size !== next.size ? !1 : Array.from(next).every((i2) => curr.has(i2))),
4651
- startWith$1(/* @__PURE__ */ new Set()),
4652
- pairwise$1(),
4653
- mergeMap$1(([curr, next]) => {
4654
- const added = Array.from(next).filter((i2) => !curr.has(i2)), removed = Array.from(curr).filter((i2) => !next.has(i2));
4655
- return [
4656
- ...added.map((key) => ({ key, added: !0 })),
4657
- ...removed.map((key) => ({ key, added: !1 }))
4658
- ];
4659
- }),
4660
- groupBy$1((i2) => i2.key),
4661
- mergeMap$1(
4662
- (group$) => group$.pipe(
4663
- switchMap((e3) => {
4664
- if (!e3.added) return EMPTY;
4665
- const lastLiveEventId$ = state.observable.pipe(
4666
- map((s2) => s2.queries[group$.key]?.lastLiveEventId),
4667
- distinctUntilChanged()
4668
- ), { query, options: { params, scope, ...options } = {} } = parseQueryKey(group$.key), client$ = getClientState(instance, { apiVersion: "vX", scope }).observable;
4669
- return combineLatest([lastLiveEventId$, client$]).pipe(
4670
- switchMap(
4671
- ([lastLiveEventId, client]) => client.observable.fetch(query, params, {
4672
- ...options,
4673
- filterResponse: !1,
4674
- returnQuery: !1,
4675
- lastLiveEventId
4676
- })
4677
- )
4678
- );
4679
- }),
4680
- catchError$1((error) => (state.set("setQueryError", setQueryError(group$.key, error)), EMPTY)),
4681
- tap$1(({ result, syncTags }) => {
4682
- state.set("setQueryData", setQueryData(group$.key, result, syncTags));
4683
- })
4684
- )
4685
- )
4686
- ).subscribe({ error: errorHandler(this) });
4768
+ }), getProjectsState = projects.getState, resolveProjects = projects.resolveState, API_VERSION = "vX", USERS_STATE_CLEAR_DELAY = 5e3, DEFAULT_USERS_BATCH_SIZE = 100, getUsersKey = (instance, {
4769
+ resourceType,
4770
+ organizationId,
4771
+ batchSize = DEFAULT_USERS_BATCH_SIZE,
4772
+ projectId = instance.config.projectId
4773
+ } = {}) => JSON.stringify({ resourceType, organizationId, batchSize, projectId }), parseUsersKey = (key) => JSON.parse(key), addSubscription = (subscriptionId, key) => (prev) => {
4774
+ const group = prev.users[key], subscriptions = [...group?.subscriptions ?? [], subscriptionId];
4775
+ return { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } };
4776
+ }, removeSubscription = (subscriptionId, key) => (prev) => {
4777
+ const group = prev.users[key];
4778
+ if (!group) return prev;
4779
+ const subscriptions = group.subscriptions.filter((id) => id !== subscriptionId);
4780
+ return subscriptions.length ? { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } } : { ...prev, users: omit(prev.users, key) };
4781
+ }, setUsersData = (key, { data, nextCursor, totalCount }) => (prev) => {
4782
+ const group = prev.users[key];
4783
+ if (!group) return prev;
4784
+ const users = [...group.users ?? [], ...data];
4785
+ return { ...prev, users: { ...prev.users, [key]: { ...group, users, totalCount, nextCursor } } };
4786
+ }, updateLastLoadMoreRequest = (timestamp, key) => (prev) => {
4787
+ const group = prev.users[key];
4788
+ return group ? { ...prev, users: { ...prev.users, [key]: { ...group, lastLoadMoreRequest: timestamp } } } : prev;
4789
+ }, setUsersError = (key, error) => (prev) => {
4790
+ const group = prev.users[key];
4791
+ return group ? { ...prev, users: { ...prev.users, [key]: { ...group, error } } } : prev;
4792
+ }, cancelRequest = (key) => (prev) => {
4793
+ const group = prev.users[key];
4794
+ return !group || group.subscriptions.length ? prev : { ...prev, users: omit(prev.users, key) };
4795
+ }, initializeRequest = (key) => (prev) => prev.users[key] ? prev : { ...prev, users: { ...prev.users, [key]: { subscriptions: [] } } }, usersStore = {
4796
+ name: "UsersStore",
4797
+ getInitialState: () => ({ users: {} }),
4798
+ initialize: (context) => {
4799
+ const subscription = listenForLoadMoreAndFetch(context);
4800
+ return () => subscription.unsubscribe();
4687
4801
  }
4688
- ), listenToLiveClientAndSetLastLiveEventIds = createInternalAction(
4689
- ({ state, instance }) => function() {
4690
- const liveMessages$ = getClientState(instance, { apiVersion: "vX" }).observable.pipe(
4691
- switchMap(
4692
- (client) => client.live.events({ includeDrafts: !!client.config().token, tag: "query-store" })
4693
- ),
4694
- share(),
4695
- filter((e3) => e3.type === "message")
4696
- );
4697
- return state.observable.pipe(
4698
- mergeMap$1((s2) => Object.entries(s2.queries)),
4699
- groupBy$1(([key]) => key),
4700
- mergeMap$1((group$) => {
4701
- const syncTags$ = group$.pipe(
4702
- map(([, queryState]) => queryState),
4703
- map((i2) => i2?.syncTags ?? EMPTY_ARRAY),
4802
+ }, errorHandler = (state) => (error) => state.set("setError", { error }), listenForLoadMoreAndFetch = ({ state, instance }) => state.observable.pipe(
4803
+ map((s2) => new Set(Object.keys(s2.users))),
4804
+ distinctUntilChanged((curr, next) => curr.size !== next.size ? !1 : Array.from(next).every((i2) => curr.has(i2))),
4805
+ startWith$1(/* @__PURE__ */ new Set()),
4806
+ pairwise$1(),
4807
+ mergeMap$1(([curr, next]) => {
4808
+ const added = Array.from(next).filter((i2) => !curr.has(i2)), removed = Array.from(curr).filter((i2) => !next.has(i2));
4809
+ return [
4810
+ ...added.map((key) => ({ key, added: !0 })),
4811
+ ...removed.map((key) => ({ key, added: !1 }))
4812
+ ];
4813
+ }),
4814
+ groupBy$1((i2) => i2.key),
4815
+ mergeMap$1(
4816
+ (group$) => group$.pipe(
4817
+ switchMap((e3) => {
4818
+ if (!e3.added) return EMPTY;
4819
+ const { batchSize, ...options } = parseUsersKey(group$.key), projectId = options.projectId ?? instance.config.projectId, resourceType = options.resourceType ?? (options.organizationId ? "organization" : projectId ? "project" : "organization"), organizationId$ = options.organizationId ? of(options.organizationId) : getDashboardOrganizationId(instance).observable.pipe(
4820
+ filter((i2) => typeof i2 == "string")
4821
+ ), resource$ = resourceType === "project" ? projectId ? of({ type: "project", id: projectId }) : throwError(() => new Error("Project ID required for this API.")) : organizationId$.pipe(map((id) => ({ type: "organization", id }))), client$ = getClientState(instance, {
4822
+ scope: "global",
4823
+ apiVersion: API_VERSION
4824
+ }).observable, loadMore$ = state.observable.pipe(
4825
+ map((s2) => s2.users[group$.key]?.lastLoadMoreRequest),
4704
4826
  distinctUntilChanged()
4827
+ ), cursor$ = state.observable.pipe(
4828
+ map((s2) => s2.users[group$.key]?.nextCursor),
4829
+ distinctUntilChanged(),
4830
+ filter((cursor) => cursor !== null)
4705
4831
  );
4706
- return combineLatest([liveMessages$, syncTags$]).pipe(
4707
- filter(([message, syncTags]) => message.tags.some((tag) => syncTags.includes(tag))),
4708
- tap$1(([message]) => {
4709
- state.set("setLastLiveEventId", setLastLiveEventId(group$.key, message.id));
4710
- })
4832
+ return combineLatest([resource$, client$, loadMore$]).pipe(
4833
+ withLatestFrom(cursor$),
4834
+ switchMap(
4835
+ ([[resource, client], cursor]) => client.observable.request({
4836
+ method: "GET",
4837
+ uri: `access/${resource.type}/${resource.id}/users`,
4838
+ query: cursor ? { nextCursor: cursor, limit: batchSize.toString() } : { limit: batchSize.toString() }
4839
+ })
4840
+ ),
4841
+ catchError$1((error) => (state.set("setUsersError", setUsersError(group$.key, error)), EMPTY)),
4842
+ tap$1((response) => state.set("setUsersData", setUsersData(group$.key, response)))
4711
4843
  );
4712
4844
  })
4713
- ).subscribe({ error: errorHandler(this) });
4714
- }
4715
- );
4716
- function getQueryState(...args) {
4717
- return _getQueryState(...args);
4718
- }
4719
- const _getQueryState = createStateSourceAction(queryStore, {
4720
- selector: (state, query, options) => {
4721
- if (state.error) throw state.error;
4722
- const key = getQueryKey(query, options), queryState = state.queries[key];
4723
- if (queryState?.error) throw queryState.error;
4724
- return queryState?.result;
4725
- },
4726
- onSubscribe: ({ state }, query, options) => {
4727
- const subscriptionId = insecureRandomId(), key = getQueryKey(query, options);
4728
- return state.set("addSubscriber", addSubscriber(key, subscriptionId)), () => {
4729
- setTimeout(
4730
- () => state.set("removeSubscriber", removeSubscriber(key, subscriptionId)),
4731
- QUERY_STATE_CLEAR_DELAY
4732
- );
4733
- };
4734
- }
4735
- });
4736
- function resolveQuery(...args) {
4737
- return _resolveQuery(...args);
4738
- }
4739
- const _resolveQuery = createAction(queryStore, ({ state }) => function(query, { signal, ...options } = {}) {
4740
- const { getCurrent } = getQueryState(this, query, options), key = getQueryKey(query, options), aborted$ = signal ? new Observable((observer) => {
4741
- const cleanup = () => {
4742
- signal.removeEventListener("abort", listener);
4743
- }, listener = () => {
4744
- observer.error(new DOMException("The operation was aborted.", "AbortError")), observer.complete(), cleanup();
4745
- };
4746
- return signal.addEventListener("abort", listener), cleanup;
4747
- }).pipe(
4748
- catchError$1((error) => {
4749
- throw error instanceof Error && error.name === "AbortError" && state.set("cancelQuery", cancelQuery(key)), error;
4750
- })
4751
- ) : NEVER;
4752
- state.set("initializeQuery", initializeQuery(key));
4753
- const resolved$ = state.observable.pipe(
4754
- map(getCurrent),
4755
- first$1((i2) => i2 !== void 0)
4756
- );
4757
- return firstValueFrom(race([resolved$, aborted$]));
4758
- });
4759
- function createStore(resource, actions) {
4760
- return function(dependencies) {
4761
- const instance = "instance" in dependencies ? dependencies.instance : dependencies, { state, dispose } = "state" in dependencies ? { state: dependencies.state, dispose: noop } : initializeResource(instance, resource), boundActions = Object.entries(actions).reduce((acc, [key, action]) => (acc[key] = action.bind(null, { state, instance }), acc), {});
4762
- return { dispose, ...boundActions };
4763
- };
4764
- }
4765
- const API_VERSION = "vX", usersStore = {
4766
- name: "users",
4767
- getInitialState: () => ({
4768
- users: [],
4769
- totalCount: 0,
4770
- nextCursor: null,
4771
- hasMore: !1,
4772
- initialFetchCompleted: !1,
4773
- options: {
4774
- resourceType: "",
4775
- resourceId: "",
4776
- limit: 100
4845
+ )
4846
+ )
4847
+ ).subscribe({ error: errorHandler(state) }), getUsersState = bindActionGlobally(
4848
+ usersStore,
4849
+ createStateSourceAction({
4850
+ selector: createSelector(
4851
+ [
4852
+ ({ instance, state }, options) => state.error ?? state.users[getUsersKey(instance, options)]?.error,
4853
+ ({ instance, state }, options) => state.users[getUsersKey(instance, options)]?.users,
4854
+ ({ instance, state }, options) => state.users[getUsersKey(instance, options)]?.totalCount,
4855
+ ({ instance, state }, options) => state.users[getUsersKey(instance, options)]?.nextCursor
4856
+ ],
4857
+ (error, data, totalCount, nextCursor) => {
4858
+ if (error) throw error;
4859
+ if (!(data === void 0 || totalCount === void 0 || nextCursor === void 0))
4860
+ return { data, totalCount, hasMore: nextCursor !== null };
4861
+ }
4862
+ ),
4863
+ onSubscribe: ({ instance, state }, options) => {
4864
+ const subscriptionId = insecureRandomId(), key = getUsersKey(instance, options);
4865
+ return state.set("addSubscription", addSubscription(subscriptionId, key)), () => {
4866
+ setTimeout(
4867
+ () => state.set("removeSubscription", removeSubscription(subscriptionId, key)),
4868
+ USERS_STATE_CLEAR_DELAY
4869
+ );
4870
+ };
4777
4871
  }
4778
- }),
4779
- initialize() {
4780
- return () => {
4781
- };
4872
+ })
4873
+ ), resolveUsers = bindActionGlobally(
4874
+ usersStore,
4875
+ async ({ state, instance }, { signal, ...options }) => {
4876
+ const key = getUsersKey(instance, options), { getCurrent } = getUsersState(instance, options), aborted$ = signal ? new Observable((observer) => {
4877
+ const cleanup = () => {
4878
+ signal.removeEventListener("abort", listener);
4879
+ }, listener = () => {
4880
+ observer.error(new DOMException("The operation was aborted.", "AbortError")), observer.complete(), cleanup();
4881
+ };
4882
+ return signal.addEventListener("abort", listener), cleanup;
4883
+ }).pipe(
4884
+ catchError$1((error) => {
4885
+ throw error instanceof Error && error.name === "AbortError" && state.set("cancelRequest", cancelRequest(key)), error;
4886
+ })
4887
+ ) : NEVER;
4888
+ state.set("initializeRequest", initializeRequest(key));
4889
+ const resolved$ = state.observable.pipe(
4890
+ map(getCurrent),
4891
+ first$1((i2) => i2 !== void 0)
4892
+ );
4893
+ return firstValueFrom(race([resolved$, aborted$]));
4782
4894
  }
4783
- }, getState = createStateSourceAction(
4895
+ ), loadMoreUsers = bindActionGlobally(
4784
4896
  usersStore,
4785
- createSelector(
4786
- [
4787
- (state) => state.users,
4788
- (state) => state.totalCount,
4789
- (state) => state.nextCursor,
4790
- (state) => state.hasMore,
4791
- (state) => state.initialFetchCompleted,
4792
- (state) => state.options
4793
- ],
4794
- (users, totalCount, nextCursor, hasMore, initialFetchCompleted, options) => ({
4795
- users,
4796
- totalCount,
4797
- nextCursor,
4798
- hasMore,
4799
- options,
4800
- initialFetchCompleted
4801
- })
4802
- )
4803
- ), fetchUsers = (instance, params) => {
4804
- const { resourceType, resourceId, nextCursor, limit = 100 } = params;
4805
- return getClient(instance, { scope: "global", apiVersion: API_VERSION }).request({
4806
- method: "GET",
4807
- uri: `access/${resourceType}/${resourceId}/users`,
4808
- query: nextCursor ? { nextCursor, limit: limit.toString() } : { limit: limit.toString() },
4809
- tag: "users"
4810
- });
4811
- }, loadMore = createAction(usersStore, ({ state, instance }) => async function() {
4812
- const { users, nextCursor, options } = state.get(), { resourceType, resourceId, limit } = options;
4813
- if (!resourceType || !resourceId)
4814
- throw new Error("Resource type and ID are required to load more users");
4815
- const response = await fetchUsers(instance, { resourceType, resourceId, nextCursor, limit }), allUsers = [...users, ...response.data], hasMore = allUsers.length < response.totalCount;
4816
- state.set("loadMore", {
4817
- users: allUsers,
4818
- totalCount: response.totalCount,
4819
- nextCursor: response.nextCursor,
4820
- hasMore
4821
- });
4822
- }), resolveUsers = createAction(usersStore, ({ state, instance }) => async function() {
4823
- const { options } = state.get(), { resourceType, resourceId, limit } = options;
4824
- if (!resourceType || !resourceId)
4825
- throw new Error("Resource type and ID are required to resolve users");
4826
- const response = await fetchUsers(instance, { resourceType, resourceId, limit }), hasMore = response.data.length < response.totalCount;
4827
- return state.set("resolveUsers", {
4828
- users: response.data,
4829
- totalCount: response.totalCount,
4830
- nextCursor: response.nextCursor,
4831
- hasMore,
4832
- initialFetchCompleted: !0
4833
- }), response;
4834
- }), setOptions = createAction(usersStore, ({ state }) => function(options) {
4835
- state.set("options", {
4836
- ...state.get(),
4837
- options: {
4838
- ...state.get().options,
4839
- resourceType: options.resourceType,
4840
- resourceId: options.resourceId
4841
- }
4842
- });
4843
- }), createUsersStore = createStore(usersStore, {
4844
- getState,
4845
- loadMore,
4846
- resolveUsers,
4847
- setOptions
4848
- });
4849
- var version = "0.0.0-alpha.21";
4897
+ async ({ state, instance }, options) => {
4898
+ const key = getUsersKey(instance, options), users = getUsersState(instance, options), usersState = users.getCurrent();
4899
+ if (!usersState)
4900
+ throw new Error("Users not loaded for specified resource. Please call resolveUsers first.");
4901
+ if (!usersState.hasMore)
4902
+ throw new Error("No more users available to load for this resource.");
4903
+ const promise = firstValueFrom(
4904
+ users.observable.pipe(
4905
+ filter((i2) => i2 !== void 0),
4906
+ skip(1)
4907
+ )
4908
+ ), timestamp = (/* @__PURE__ */ new Date()).toISOString();
4909
+ return state.set("updateLastLoadMoreRequest", updateLastLoadMoreRequest(timestamp, key)), await promise;
4910
+ }
4911
+ );
4912
+ var version = "0.0.0-alpha.23";
4850
4913
  const CORE_SDK_VERSION = getEnv("PKG_VERSION") || `${version}-development`;
4851
4914
  export {
4852
4915
  AuthStateType,
@@ -4854,12 +4917,10 @@ export {
4854
4917
  applyDocumentActions,
4855
4918
  createDocument,
4856
4919
  createSanityInstance,
4857
- createUsersStore,
4858
4920
  deleteDocument,
4859
4921
  destroyController,
4860
4922
  discardDocument,
4861
4923
  editDocument,
4862
- fetchLoginUrls,
4863
4924
  getAuthState,
4864
4925
  getClient,
4865
4926
  getClientState,
@@ -4868,7 +4929,7 @@ export {
4868
4929
  getDatasetsState,
4869
4930
  getDocumentState,
4870
4931
  getDocumentSyncStatus,
4871
- getLoginUrlsState,
4932
+ getLoginUrlState,
4872
4933
  getOrCreateChannel,
4873
4934
  getOrCreateController,
4874
4935
  getOrCreateNode,
@@ -4879,12 +4940,15 @@ export {
4879
4940
  getProjectsState,
4880
4941
  getQueryKey,
4881
4942
  getQueryState,
4882
- getResourceId,
4883
4943
  getTokenState,
4944
+ getUsersKey,
4945
+ getUsersState,
4884
4946
  handleAuthCallback,
4885
4947
  jsonMatch,
4948
+ loadMoreUsers,
4886
4949
  logout,
4887
4950
  parseQueryKey,
4951
+ parseUsersKey,
4888
4952
  publishDocument,
4889
4953
  releaseChannel,
4890
4954
  releaseNode,
@@ -4896,6 +4960,7 @@ export {
4896
4960
  resolveProjection,
4897
4961
  resolveProjects,
4898
4962
  resolveQuery,
4963
+ resolveUsers,
4899
4964
  subscribeDocumentEvents,
4900
4965
  unpublishDocument
4901
4966
  };