@sanity/sdk 2.18.0 → 3.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks-dts/createGroqSearchFilter.d.ts +233 -12
- package/dist/_chunks-dts/createGroqSearchFilter.d.ts.map +1 -1
- package/dist/_chunks-es/_internal.js +1 -0
- package/dist/_chunks-es/_internal.js.map +1 -1
- package/dist/_chunks-es/createGroqSearchFilter.js +284 -6
- package/dist/_chunks-es/createGroqSearchFilter.js.map +1 -1
- package/dist/_chunks-es/telemetryManager.js +2 -2
- package/dist/_exports/_internal.d.ts +2 -2
- package/dist/_exports/_internal.d.ts.map +1 -1
- package/dist/_exports/_internal.js +3 -1
- package/dist/index.d.ts +599 -185
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +492 -337
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/_exports/_internal.ts +11 -0
- package/src/_exports/index.ts +57 -12
- package/src/access/checkPermissions.test.ts +55 -0
- package/src/access/checkPermissions.ts +54 -0
- package/src/applications/applications.test-d.ts +83 -0
- package/src/applications/applications.test.ts +130 -0
- package/src/applications/applications.ts +364 -0
- package/src/applications/userApplications.test.ts +126 -0
- package/src/applications/userApplications.ts +261 -0
- package/src/auth/getOrganizationVerificationState.test.ts +7 -7
- package/src/auth/getOrganizationVerificationState.ts +4 -4
- package/src/document/documentStore.concurrency.test.ts +313 -22
- package/src/installations/installations.test-d.ts +68 -0
- package/src/installations/installations.test.ts +62 -0
- package/src/installations/installations.ts +202 -0
- package/src/organization/organization.test-d.ts +18 -84
- package/src/organization/organization.test.ts +11 -11
- package/src/organization/organization.ts +26 -54
- package/src/organizations/organizations.test-d.ts +11 -32
- package/src/organizations/organizations.test.ts +8 -8
- package/src/organizations/organizations.ts +29 -54
- package/src/project/project.test-d.ts +19 -75
- package/src/project/project.test.ts +57 -10
- package/src/project/project.ts +33 -52
- package/src/projects/projects.test-d.ts +15 -21
- package/src/projects/projects.test.ts +8 -8
- package/src/projects/projects.ts +25 -49
- package/src/store/fetcherStore.test-d.ts +121 -0
- package/src/store/fetcherStore.test.ts +299 -0
- package/src/store/fetcherStore.ts +801 -0
- package/src/utils/buildQuery.test.ts +14 -0
- package/src/utils/buildQuery.ts +17 -0
- package/src/utils/includeShape.ts +36 -0
- package/src/utils/setCleanupTimeout.ts +21 -8
- package/dist/_chunks-es/version.js +0 -7
- package/dist/_chunks-es/version.js.map +0 -1
- package/src/utils/defineIntent.test.ts +0 -477
- package/src/utils/defineIntent.ts +0 -244
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ClientConfig, ClientError, ClientPerspective, ResponseQueryOptions, SanityClient, StackablePerspective } from "@sanity/client";
|
|
2
2
|
import { CurrentUser } from "@sanity/types";
|
|
3
3
|
import { Observable } from "rxjs";
|
|
4
|
+
import "zustand/middleware";
|
|
4
5
|
import { SanityQueryResult } from "groq";
|
|
5
6
|
/**
|
|
6
7
|
* Configuration for an authentication provider
|
|
@@ -635,7 +636,9 @@ interface PreviewValue {
|
|
|
635
636
|
* The status of the document.
|
|
636
637
|
*/
|
|
637
638
|
_status?: {
|
|
638
|
-
/** The date of the last published edit */
|
|
639
|
+
/** The date of the last published edit */
|
|
640
|
+
lastEditedPublishedAt?: string;
|
|
641
|
+
/** The date of the last draft edit */
|
|
639
642
|
lastEditedDraftAt?: string;
|
|
640
643
|
};
|
|
641
644
|
}
|
|
@@ -659,8 +662,8 @@ type ValuePending<T> = {
|
|
|
659
662
|
* Preview state is now stored in the projection store.
|
|
660
663
|
*/
|
|
661
664
|
interface PreviewStoreState {
|
|
662
|
-
values: { [TDocumentId in string]?: ValuePending<PreviewValue
|
|
663
|
-
subscriptions: { [TDocumentId in string]?: { [TSubscriptionId in string]?: true } };
|
|
665
|
+
values: { [TDocumentId in string]?: ValuePending<PreviewValue>; };
|
|
666
|
+
subscriptions: { [TDocumentId in string]?: { [TSubscriptionId in string]?: true; }; };
|
|
664
667
|
}
|
|
665
668
|
/**
|
|
666
669
|
* Transforms a projection result (with titleCandidates, subtitleCandidates, media)
|
|
@@ -801,6 +804,230 @@ declare function getQueryState(instance: SanityInstance, queryOptions: QueryOpti
|
|
|
801
804
|
declare function resolveQuery<TQuery extends string = string, TDataset extends string = string, TProjectId extends string = string>(instance: SanityInstance, queryOptions: ResolveQueryOptions<TQuery, TDataset, TProjectId>): Promise<SanityQueryResult<TQuery, `${TProjectId}.${TDataset}`>>;
|
|
802
805
|
/** @beta */
|
|
803
806
|
declare function resolveQuery<TData>(instance: SanityInstance, queryOptions: ResolveQueryOptions): Promise<TData>;
|
|
807
|
+
/**
|
|
808
|
+
* Identifies cached data for invalidation, matched across the whole store.
|
|
809
|
+
* A fetcher declares the tags each of its entries carries (via
|
|
810
|
+
* {@link FetcherDefinition.tags}); a mutation declares the tags it invalidates
|
|
811
|
+
* (via {@link MutationDefinition.invalidates}).
|
|
812
|
+
*
|
|
813
|
+
* When invalidating,`{type: 'organization'}` matches every entry carrying any `organization` tag;
|
|
814
|
+
* `{type: 'organization', id: 'abc'}` matches only entries carrying that exact pair.
|
|
815
|
+
* List entries carry a `{type, id: 'LIST'}` sentinel plus one tag per item, so a
|
|
816
|
+
* "create" mutation can refetch lists without touching unrelated detail entries.
|
|
817
|
+
*
|
|
818
|
+
* @internal
|
|
819
|
+
*/
|
|
820
|
+
interface CacheTag {
|
|
821
|
+
type: string;
|
|
822
|
+
/** Specific id, or the `'LIST'` sentinel for list entries */
|
|
823
|
+
id?: string | number;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* The reactive value of one cache entry, as exposed by
|
|
827
|
+
* {@link Fetcher.getState}. React hooks consume this envelope directly.
|
|
828
|
+
* Discriminated on `status`, so narrowing gives correctly-typed `data`:
|
|
829
|
+
* `'success'` is the only arm carrying data, and a background failure while
|
|
830
|
+
* data still renders surfaces on the `'success'` arm's `error`.
|
|
831
|
+
*
|
|
832
|
+
* `isFetching` is common to all arms: a fetch for this entry is in flight
|
|
833
|
+
* (initial load, revalidation, or poll).
|
|
834
|
+
*
|
|
835
|
+
* @internal
|
|
836
|
+
*/
|
|
837
|
+
type FetcherSnapshot<TData> = {
|
|
838
|
+
/** No data yet — initial fetch in flight or not started */
|
|
839
|
+
status: 'pending';
|
|
840
|
+
data: undefined;
|
|
841
|
+
error: undefined;
|
|
842
|
+
isFetching: boolean;
|
|
843
|
+
dataUpdatedAt: undefined;
|
|
844
|
+
} | {
|
|
845
|
+
/** Data available — possibly stale, possibly revalidating */
|
|
846
|
+
status: 'success';
|
|
847
|
+
data: TData;
|
|
848
|
+
/** Most recent background-fetch failure, cleared by the next successful fetch */
|
|
849
|
+
error: unknown;
|
|
850
|
+
isFetching: boolean;
|
|
851
|
+
/** Epoch ms of the fetch that produced `data` */
|
|
852
|
+
dataUpdatedAt: number;
|
|
853
|
+
} | {
|
|
854
|
+
/** The last fetch failed and no data exists to serve */
|
|
855
|
+
status: 'error';
|
|
856
|
+
data: undefined;
|
|
857
|
+
error: unknown;
|
|
858
|
+
isFetching: boolean;
|
|
859
|
+
dataUpdatedAt: undefined;
|
|
860
|
+
};
|
|
861
|
+
/**
|
|
862
|
+
* A typed description of one cached, parameterised read of an API response —
|
|
863
|
+
* here is a single cache per {@link SanityInstance}; every definition registers
|
|
864
|
+
* into it and its `name` namespaces its keys. A list and a detail read are two
|
|
865
|
+
* definitions over the one cache, not two caches.
|
|
866
|
+
*
|
|
867
|
+
* Entry lifecycle: fresh → stale → collected. Fresh entries are served from
|
|
868
|
+
* cache with no fetch; stale entries are served immediately and revalidated in
|
|
869
|
+
* the background (stale-while-revalidate); collected entries are removed once
|
|
870
|
+
* their `gcTime` elapses after the last unsubscribe, so the next subscriber
|
|
871
|
+
* suspends.
|
|
872
|
+
*
|
|
873
|
+
* @internal
|
|
874
|
+
*/
|
|
875
|
+
interface FetcherDefinition<TParams extends unknown[], TData> {
|
|
876
|
+
/** Namespaces this fetcher's keys in the shared cache; used for devtools and request-tag derivation */
|
|
877
|
+
name: string;
|
|
878
|
+
/**
|
|
879
|
+
* Fetches the data once. Return an observable that emits the result and
|
|
880
|
+
* completes.
|
|
881
|
+
*/
|
|
882
|
+
fetch: (instance: SanityInstance) => (...params: TParams) => Observable<TData>;
|
|
883
|
+
/** Converts params into the cache key that identifies an entry (unique within `name`) */
|
|
884
|
+
getKey: (instance: SanityInstance, ...params: TParams) => string;
|
|
885
|
+
/**
|
|
886
|
+
* Cache tags each entry carries, for cache-wide invalidation. A static array,
|
|
887
|
+
* or a function of the fetched data when tags depend on the response (e.g. one
|
|
888
|
+
* tag per list item).
|
|
889
|
+
*/
|
|
890
|
+
tags?: CacheTag[] | ((data: TData, ...params: TParams) => CacheTag[]);
|
|
891
|
+
/**
|
|
892
|
+
* How long fetched data is fresh, in ms. Fresh entries never refetch;
|
|
893
|
+
* stale entries serve cached data and revalidate in the background.
|
|
894
|
+
* @defaultValue 30_000
|
|
895
|
+
*/
|
|
896
|
+
staleTime?: number;
|
|
897
|
+
/**
|
|
898
|
+
* How long an entry survives after its last unsubscribe before it is garbage
|
|
899
|
+
* collected, in ms. The clock starts at the last unsubscribe — entries with
|
|
900
|
+
* active subscribers are never collected.
|
|
901
|
+
* @defaultValue 300_000
|
|
902
|
+
*/
|
|
903
|
+
gcTime?: number;
|
|
904
|
+
/**
|
|
905
|
+
* Refetch on this interval (ms) while the entry has at least one subscriber,
|
|
906
|
+
* independent of staleness. Ticks are skipped while `document.hidden`. Off by default.
|
|
907
|
+
*/
|
|
908
|
+
refetchInterval?: number;
|
|
909
|
+
/**
|
|
910
|
+
* Consulted once, when an entry is being created and no cached data exists for
|
|
911
|
+
* it. Return data pulled from another fetcher in the same cache — read via its
|
|
912
|
+
* ordinary `getState(instance, ...).getCurrent()`, e.g. a detail entry pulling
|
|
913
|
+
* its item out of the cached list — to skip or soften the initial fetch.
|
|
914
|
+
* `dataUpdatedAt` must be when the source data was fetched, not "now": staleness
|
|
915
|
+
* is measured from it. Return `undefined` to fetch as normal.
|
|
916
|
+
*/
|
|
917
|
+
initialData?: (instance: SanityInstance, ...params: TParams) => {
|
|
918
|
+
data: TData;
|
|
919
|
+
dataUpdatedAt: number;
|
|
920
|
+
} | undefined;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* A typed handle over the shared fetcher cache, returned by
|
|
924
|
+
* {@link defineFetcher}. It is a view onto the entries under its definition's
|
|
925
|
+
* `name`, not a cache of its own.
|
|
926
|
+
*
|
|
927
|
+
* @internal
|
|
928
|
+
*/
|
|
929
|
+
interface Fetcher<TParams extends unknown[], TData> {
|
|
930
|
+
/** Reactive envelope for one entry. Subscribing triggers fetching per staleness rules. */
|
|
931
|
+
getState: (instance: SanityInstance, ...params: TParams) => StateSource<FetcherSnapshot<TData>>;
|
|
932
|
+
/**
|
|
933
|
+
* Resolves with the entry's first available data — the promise a suspending
|
|
934
|
+
* component throws. Rejects if the initial fetch fails.
|
|
935
|
+
*/
|
|
936
|
+
resolveState: (instance: SanityInstance, ...params: TParams) => Promise<TData>;
|
|
937
|
+
/**
|
|
938
|
+
* Marks the entry stale. If it has active subscribers it refetches immediately;
|
|
939
|
+
* otherwise it refetches on next subscribe.
|
|
940
|
+
*/
|
|
941
|
+
invalidate: (instance: SanityInstance, ...params: TParams) => void;
|
|
942
|
+
/** {@link Fetcher.invalidate} for every entry under this fetcher's `name`. */
|
|
943
|
+
invalidateAll: (instance: SanityInstance) => void;
|
|
944
|
+
/**
|
|
945
|
+
* Imperative fetch, bypassing staleness. Dedupes against an in-flight fetch.
|
|
946
|
+
* Resolves with the entry's data as held by the cache once the fetch settles.
|
|
947
|
+
*/
|
|
948
|
+
refetch: (instance: SanityInstance, ...params: TParams) => Promise<TData>;
|
|
949
|
+
/**
|
|
950
|
+
* Writes an entry's data directly. Returns an undo handle — inside a
|
|
951
|
+
* mutation's `onMutate` these writes are recorded and rolled back automatically
|
|
952
|
+
* on failure.
|
|
953
|
+
*/
|
|
954
|
+
setData: (instance: SanityInstance, params: TParams, updater: TData | ((current: TData | undefined) => TData)) => {
|
|
955
|
+
undo: () => void;
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Writes an entry's data in any fetcher. Passed to {@link MutationDefinition}
|
|
960
|
+
* callbacks — mutations are the only holders of arbitrary write access; read
|
|
961
|
+
* fetchers pull their data (see {@link FetcherDefinition.initialData}). Inside
|
|
962
|
+
* `onMutate`, every write is recorded and undone automatically if the mutation
|
|
963
|
+
* fails.
|
|
964
|
+
*
|
|
965
|
+
* @internal
|
|
966
|
+
*/
|
|
967
|
+
type CacheWriter = <TParams extends unknown[], TData>(fetcher: Fetcher<TParams, TData>, params: TParams, updater: TData | ((current: TData | undefined) => TData)) => void;
|
|
968
|
+
/**
|
|
969
|
+
* Resolves when the mutation settles on the server. `invalidated` tracks the
|
|
970
|
+
* background reconciliation — the refetches triggered by
|
|
971
|
+
* {@link MutationDefinition.invalidates} — for the rare caller that must wait for
|
|
972
|
+
* full reconvergence rather than server settlement.
|
|
973
|
+
*
|
|
974
|
+
* @internal
|
|
975
|
+
*/
|
|
976
|
+
interface MutationResult<TResult> {
|
|
977
|
+
/** The server response */
|
|
978
|
+
data: TResult;
|
|
979
|
+
/** Settles when the refetches of matched active entries complete */
|
|
980
|
+
invalidated: Promise<void>;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Defines a mutation with optimistic cache updates. Lifecycle:
|
|
984
|
+
*
|
|
985
|
+
* 1. `onMutate` applies optimistic writes synchronously — the UI updates before
|
|
986
|
+
* the request leaves. Each entry carries a version counter that increments on
|
|
987
|
+
* every write. An optimistic write bumps the counter, so a revalidation already
|
|
988
|
+
* in flight lands "out of date" and is discarded rather than clobbering the
|
|
989
|
+
* optimistic write.
|
|
990
|
+
* 2. The request runs. On failure, recorded writes are rolled back automatically
|
|
991
|
+
* — the cache is restored exactly, so failure ends the lifecycle here.
|
|
992
|
+
* 3. On success, `onSuccess` may write the server response into the cache directly.
|
|
993
|
+
* 4. On success, `invalidates` tags mark matching entries across the cache
|
|
994
|
+
* stale (active entries refetch), so the cache reconverges on server truth
|
|
995
|
+
* even if the optimistic shape was wrong.
|
|
996
|
+
*
|
|
997
|
+
* @internal
|
|
998
|
+
*/
|
|
999
|
+
interface MutationDefinition<TInput, TResult> {
|
|
1000
|
+
/** Unique mutation name, used for devtools and request-tag derivation */
|
|
1001
|
+
name: string;
|
|
1002
|
+
/** Creates the observable that performs the server mutation */
|
|
1003
|
+
mutationFn: (instance: SanityInstance) => (input: TInput) => Observable<TResult>;
|
|
1004
|
+
/** Optimistic cache writes, applied synchronously before the request */
|
|
1005
|
+
onMutate?: (write: CacheWriter, input: TInput) => void;
|
|
1006
|
+
/** Reconcile the cache with the server response, avoiding a refetch round-trip */
|
|
1007
|
+
onSuccess?: (write: CacheWriter, result: TResult, input: TInput) => void;
|
|
1008
|
+
/**
|
|
1009
|
+
* Cache tags to invalidate on success. Failure invalidates nothing: recorded
|
|
1010
|
+
* optimistic writes roll back to the exact pre-mutation cache, and any
|
|
1011
|
+
* server-side ambiguity (e.g. timeout after commit) heals via `staleTime`.
|
|
1012
|
+
* A static array, or a function of the result/input.
|
|
1013
|
+
*/
|
|
1014
|
+
invalidates?: CacheTag[] | ((result: TResult, input: TInput) => CacheTag[]);
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Registers a fetcher definition against the shared cache and returns its typed
|
|
1018
|
+
* handle.
|
|
1019
|
+
*
|
|
1020
|
+
* @internal
|
|
1021
|
+
*/
|
|
1022
|
+
declare function defineFetcher<TParams extends unknown[], TData>(definition: FetcherDefinition<TParams, TData>): Fetcher<TParams, TData>;
|
|
1023
|
+
/**
|
|
1024
|
+
* Creates a bound mutation from its definition. The returned action resolves at
|
|
1025
|
+
* server settlement — not after invalidation refetches, which run as background
|
|
1026
|
+
* reconciliation (see {@link MutationResult.invalidated}).
|
|
1027
|
+
*
|
|
1028
|
+
* @internal
|
|
1029
|
+
*/
|
|
1030
|
+
declare function defineMutation<TInput, TResult>(definition: MutationDefinition<TInput, TResult>): (instance: SanityInstance, input: TInput) => Promise<MutationResult<TResult>>;
|
|
804
1031
|
/**
|
|
805
1032
|
* @public
|
|
806
1033
|
*/
|
|
@@ -869,7 +1096,7 @@ interface SanityUserResponse {
|
|
|
869
1096
|
* @public
|
|
870
1097
|
*/
|
|
871
1098
|
interface UsersStoreState {
|
|
872
|
-
users: { [TUsersKey in string]?: UsersGroupState };
|
|
1099
|
+
users: { [TUsersKey in string]?: UsersGroupState; };
|
|
873
1100
|
error?: unknown;
|
|
874
1101
|
}
|
|
875
1102
|
/**
|
|
@@ -893,13 +1120,7 @@ interface ResolveUserOptions extends GetUserOptions {
|
|
|
893
1120
|
signal?: AbortSignal;
|
|
894
1121
|
}
|
|
895
1122
|
/** @internal */
|
|
896
|
-
declare const getUsersKey: (instance: SanityInstance, {
|
|
897
|
-
resourceType,
|
|
898
|
-
organizationId,
|
|
899
|
-
batchSize,
|
|
900
|
-
projectId,
|
|
901
|
-
userId
|
|
902
|
-
}?: GetUsersOptions) => string;
|
|
1123
|
+
declare const getUsersKey: (instance: SanityInstance, { resourceType, organizationId, batchSize, projectId, userId }?: GetUsersOptions) => string;
|
|
903
1124
|
/** @internal */
|
|
904
1125
|
declare const parseUsersKey: (key: string) => {
|
|
905
1126
|
batchSize: number;
|
|
@@ -922,5 +1143,5 @@ declare const parseUsersKey: (key: string) => {
|
|
|
922
1143
|
* @internal
|
|
923
1144
|
*/
|
|
924
1145
|
declare function createGroqSearchFilter(query: string): string;
|
|
925
|
-
export {
|
|
1146
|
+
export { getIsInDashboardState as $, transformProjectionToPreview as A, isDatasetSource as At, getClientErrorApiBody as B, QueryOptions as C, ReleasePerspective as Ct, resolveQuery as D, isCanvasResource as Dt, parseQueryKey as E, TokenSource as Et, ValuePending as F, AuthStoreState as G, getClientErrorApiType as H, ProjectionValuePending as I, LoggedOutAuthState as J, ErrorAuthState as K, ValidProjection as L, PreviewQueryResult as M, isMediaLibrarySource as Mt, PreviewStoreState as N, AuthConfig as Nt, Selector as O, isCanvasSource as Ot, PreviewValue as P, AuthProvider as Pt, getDashboardOrganizationId as Q, PREVIEW_PROJECTION as R, defineMutation as S, ReleaseHandle as St, getQueryState as T, StudioConfig as Tt, isProjectUserNotFoundClientError as U, getClientErrorApiDescription as V, AuthState as W, getAuthState as X, LoggingInAuthState as Y, getCurrentUserState as Z, FetcherDefinition as _, DocumentTypeHandle as _t, GetUsersOptions as a, StoreAction as at, MutationResult as b, PerspectiveHandle as bt, ResolveUsersOptions as c, isStudioConfig as ct, UserProfile as d, DatasetHandle as dt, getLoginUrlState as et, UsersGroupState as f, DatasetResource as ft, Fetcher as g, DocumentSource as gt, CacheWriter as h, DocumentResource as ht, GetUserOptions as i, BoundStoreAction as it, PreviewMedia as j, isMediaLibraryResource as jt, StateSource as k, isDatasetResource as kt, SanityUser as l, CanvasResource as lt, CacheTag as m, DocumentHandle as mt, getUsersKey as n, setAuthToken as nt, Membership as o, SanityInstance as ot, UsersStoreState as p, DatasetSource as pt, LoggedInAuthState as q, parseUsersKey as r, AuthStateType as rt, ResolveUserOptions as s, createSanityInstance as st, createGroqSearchFilter as t, getTokenState as tt, SanityUserResponse as u, CanvasSource as ut, FetcherSnapshot as v, MediaLibraryResource as vt, getQueryKey as w, SanityConfig as wt, defineFetcher as x, ProjectHandle as xt, MutationDefinition as y, MediaLibrarySource as yt, ApiErrorBody as z };
|
|
926
1147
|
//# sourceMappingURL=createGroqSearchFilter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createGroqSearchFilter.d.ts","names":[],"sources":["../../src/config/authConfig.ts","../../src/config/sanityConfig.ts","../../src/auth/authMode.ts","../../src/store/createSanityInstance.ts","../../src/store/createStoreState.ts","../../src/store/defineStore.ts","../../src/store/createActionBinder.ts","../../src/auth/authStateType.ts","../../src/auth/authStore.ts","../../src/auth/utils.ts","../../src/preview/previewConstants.ts","../../src/projection/types.ts","../../src/preview/types.ts","../../src/preview/previewProjectionUtils.ts","../../src/store/createStateSourceAction.ts","../../src/query/queryStore.ts","../../src/users/types.ts","../../src/users/reducers.ts","../../src/utils/createGroqSearchFilter.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"createGroqSearchFilter.d.ts","names":[],"sources":["../../src/config/authConfig.ts","../../src/config/sanityConfig.ts","../../src/auth/authMode.ts","../../src/store/createSanityInstance.ts","../../src/store/createStoreState.ts","../../src/store/defineStore.ts","../../src/store/createActionBinder.ts","../../src/auth/authStateType.ts","../../src/auth/authStore.ts","../../src/auth/utils.ts","../../src/preview/previewConstants.ts","../../src/projection/types.ts","../../src/preview/types.ts","../../src/preview/previewProjectionUtils.ts","../../src/store/createStateSourceAction.ts","../../src/query/queryStore.ts","../../src/store/fetcherStore.ts","../../src/users/types.ts","../../src/users/reducers.ts","../../src/utils/createGroqSearchFilter.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_internal.js","sources":["../../src/telemetry/environment.ts","../../src/telemetry/events.ts","../../src/telemetry/initTelemetry.ts"],"sourcesContent":["/**\n * Telemetry environment classification.\n *\n * - `'development'` — the SDK is running on the local developer's machine\n * (`localhost` / `127.0.0.1` in the browser, or `NODE_ENV=development`\n * in Node). These are the original dev-only telemetry sessions.\n *\n * - `'production'` — the SDK is running on a production Sanity-controlled\n * domain (Studio deployments on `*.sanity.studio`, the dashboard on\n * `*.sanity.io`) where end users are authenticated Sanity users with\n * Populus consent records. Production telemetry is gated to this\n * allowlist; SDK apps deployed to customer-controlled domains do not\n * emit telemetry. Staging (`*.sanity.work`) and preview\n * (`*.sanity.dev`) hosts are deliberately excluded.\n *\n * @internal\n */\nexport type TelemetryEnvironment = 'development' | 'production'\n\n/**\n * Hostname suffixes that count as Sanity-controlled for the purposes of\n * production telemetry. A user reaching one of these hosts in the\n * browser is authenticated against Sanity and has a Populus consent\n * record, so we apply the same telemetry rules as the Studio's\n * `telemetry-sink`.\n *\n * The leading `.` is required: it ensures suffix matches hit a real\n * subdomain boundary, so apex matches (`sanity.io`, `sanity.studio`)\n * and lookalikes (`evilsanity.studio`) are excluded. Only production\n * hosts are listed; staging (`*.sanity.work`) and preview\n * (`*.sanity.dev`) hosts are excluded by omission.\n *\n * @internal\n */\nconst SANITY_CONTROLLED_HOST_SUFFIXES = ['.sanity.studio', '.sanity.io'] as const\n\nfunction getBrowserHostname(win: Window): string | null {\n const hostname = win.location?.hostname\n return typeof hostname === 'string' && hostname.length > 0 ? hostname.toLowerCase() : null\n}\n\nfunction isLocalHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1'\n}\n\nfunction isSanityControlledHostname(hostname: string): boolean {\n return SANITY_CONTROLLED_HOST_SUFFIXES.some((suffix) => hostname.endsWith(suffix))\n}\n\n/**\n * Returns the telemetry environment for the current runtime, or `null`\n * when telemetry should not run at all.\n *\n * Browser:\n * - `localhost` / `127.0.0.1` → `'development'`\n * - host matches the Sanity-controlled allowlist → `'production'`\n * - anything else (customer domains, unknown contexts) → `null`\n *\n * Node (scripts, SSR, tests):\n * - `NODE_ENV=development` → `'development'`\n * - otherwise → `null`. Production-side server runtimes don't carry the\n * browser-authenticated user/consent assumption, so we don't enable\n * them under the production gate.\n *\n * Bracket-notation `process.env['NODE_ENV']` is used to avoid bundler\n * dead-code replacement.\n *\n * @internal\n */\nexport function getTelemetryEnvironment(): TelemetryEnvironment | null {\n if (typeof window !== 'undefined') {\n const hostname = getBrowserHostname(window)\n if (!hostname) return null\n if (isLocalHostname(hostname)) return 'development'\n if (isSanityControlledHostname(hostname)) return 'production'\n return null\n }\n\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] === 'development') {\n return 'development'\n }\n return null\n}\n\n/**\n * Convenience predicate for \"telemetry can run in this environment\".\n *\n * @internal\n */\nexport function isTelemetryEnabled(): boolean {\n return getTelemetryEnvironment() !== null\n}\n","import {defineEvent} from '@sanity/telemetry'\n\n/** @internal */\nexport const SDKSessionStarted = defineEvent<{\n version: string\n projectId: string\n perspective: string\n authMethod: string\n}>({\n name: 'SDK Session Started',\n version: 1,\n description: 'SDK instance created (environment is recorded in the event context)',\n})\n\n/** @internal */\nexport const SDKHookMounted = defineEvent<{\n hookName: string\n}>({\n name: 'SDK Hook Mounted',\n version: 1,\n description: 'An SDK hook was mounted for the first time in this session',\n})\n\n/** @internal */\nexport const SDKSessionEnded = defineEvent<{\n durationSeconds: number\n hooksUsed: string[]\n}>({\n name: 'SDK Session Ended',\n version: 1,\n description: 'SDK instance disposed (environment is recorded in the event context)',\n})\n\n/** @internal */\nexport const SDKError = defineEvent<{\n errorType: string\n hookName: string\n}>({\n name: 'SDK Error',\n version: 1,\n description: 'Runtime error caught in the SDK',\n})\n","import {type SanityInstance} from '../store/createSanityInstance'\nimport {createLogger} from '../utils/logger'\nimport {getTelemetryEnvironment} from './environment'\nimport {type TelemetryManager} from './telemetryManager'\n\nconst DEFAULT_TELEMETRY_API_VERSION = '2024-11-12'\n\nconst logger = createLogger('telemetry')\n\n/**\n * Per-instance map of active telemetry managers. Allows the React\n * package (and other consumers) to look up the manager for a given\n * instance and log hook usage / errors without importing the full\n * telemetry module themselves.\n *\n * @internal\n */\nconst telemetryManagers = new WeakMap<SanityInstance, TelemetryManager>()\nconst pendingHooks = new WeakMap<SanityInstance, Set<string>>()\nconst initInFlight = new WeakSet<SanityInstance>()\n\n/**\n * Initializes telemetry for a SDK instance if the runtime environment\n * qualifies. The environment is resolved by `getTelemetryEnvironment()`:\n *\n * - `'development'` — local dev servers (`localhost` / `127.0.0.1`, or\n * Node with `NODE_ENV=development`). This is the original opt-in\n * surface.\n * - `'production'` — apps deployed to Sanity-controlled domains\n * (e.g. `*.sanity.studio`, the dashboard). End users are\n * authenticated Sanity users with Populus consent records, so we\n * apply the same consent gate as the Studio's `telemetry-sink`.\n *\n * Apps on customer-controlled domains return `null` and skip telemetry\n * entirely.\n *\n * `telemetryManager` and `clientStore` are dynamically imported so the\n * telemetry code path stays out of production bundles for apps that\n * don't qualify. Only the lightweight environment check runs at boot.\n *\n * The `projectId` must be passed explicitly because the resource\n * configuration is typically set by the React layer after the\n * instance has already been created.\n *\n * @internal\n */\nexport function initTelemetry(instance: SanityInstance, projectId: string): void {\n const environment = getTelemetryEnvironment()\n if (!environment) {\n logger.trace('initTelemetry skipped: environment not eligible', {internal: true})\n return\n }\n if (!projectId) {\n logger.trace('initTelemetry skipped: no projectId', {internal: true})\n return\n }\n if (telemetryManagers.has(instance) || initInFlight.has(instance)) {\n return\n }\n initInFlight.add(instance)\n\n logger.debug('initializing telemetry', {projectId, environment})\n\n Promise.all([\n import('./telemetryManager'),\n import('../client/clientStore'),\n import('../auth/authStore'),\n ])\n .then(async ([{createTelemetryManager}, {getClient}, {getTokenState}]) => {\n if (instance.isDisposed()) {\n initInFlight.delete(instance)\n logger.debug('telemetry skipped: instance disposed before imports resolved')\n return\n }\n\n // Wait for the auth store to resolve a token. The client needs a\n // Bearer token for the consent check and batch POSTs. If the token\n // is already available (e.g. static token config), this resolves\n // immediately. For OAuth/localStorage discovery it waits for the\n // first emission. For unauthenticated apps the promise never\n // resolves, which is fine since telemetry requires auth anyway.\n const token = getTokenState(instance).getCurrent()\n logger.trace('auth token check', {tokenPresent: !!token, internal: true})\n\n if (!token) {\n logger.debug('waiting for auth token')\n const hasToken = await new Promise<boolean>((resolve) => {\n if (instance.isDisposed()) return resolve(false)\n const cleanup = {unsubscribe: () => {}}\n const unsub = instance.onDispose(() => {\n cleanup.unsubscribe()\n resolve(false)\n })\n // The token observable is a `shareReplay({bufferSize: 1, refCount: true})`\n // (see `createStateSourceAction`), so it can deliver a buffered value\n // synchronously while we're still inside `.subscribe(cb)`. At that\n // moment `sub` is in the TDZ, so the callback can't reach it. We\n // gate on a `received` flag and let the post-subscribe block do the\n // unsubscribe in the sync-emission case.\n let received = false\n const sub = getTokenState(instance).observable.subscribe((t) => {\n if (received || !t) return\n received = true\n logger.debug('auth token received')\n unsub()\n resolve(true)\n cleanup.unsubscribe()\n })\n cleanup.unsubscribe = () => sub.unsubscribe()\n if (received) cleanup.unsubscribe()\n })\n if (!hasToken || instance.isDisposed()) {\n initInFlight.delete(instance)\n logger.debug('telemetry skipped: no token resolved or instance disposed')\n return\n }\n }\n\n const manager = createTelemetryManager({\n sessionId: instance.instanceId,\n getClient: () => getClient(instance, {apiVersion: DEFAULT_TELEMETRY_API_VERSION}),\n projectId,\n environment,\n })\n\n const consented = await manager.checkConsent()\n logger.debug('consent check complete', {consented})\n if (!consented || instance.isDisposed()) {\n initInFlight.delete(instance)\n manager.dispose()\n return\n }\n\n initInFlight.delete(instance)\n telemetryManagers.set(instance, manager)\n\n const buffered = pendingHooks.get(instance)\n if (buffered) {\n logger.debug('flushing buffered hooks', {hooks: Array.from(buffered)})\n for (const hookName of buffered) {\n manager.logHookFirstUsed(hookName)\n }\n pendingHooks.delete(instance)\n }\n\n const config = instance.config\n const perspective = typeof config.perspective === 'string' ? config.perspective : 'published'\n const authMethod = config.auth?.token\n ? 'token'\n : config.studio?.auth?.token\n ? 'studio'\n : 'default'\n\n logger.info('telemetry session started', {projectId, perspective, authMethod, environment})\n manager.logSessionStarted({\n projectId,\n perspective,\n authMethod,\n })\n\n instance.onDispose(() => {\n manager.endSession()\n telemetryManagers.delete(instance)\n logger.debug('telemetry session ended')\n })\n })\n .catch((err) => {\n initInFlight.delete(instance)\n logger.warn('telemetry init failed', {error: err})\n })\n}\n\n/**\n * Retrieves the telemetry manager for an instance, if one exists.\n * Returns undefined when telemetry is disabled or not yet initialized.\n *\n * @internal\n */\nexport function getTelemetryManager(instance: SanityInstance): TelemetryManager | undefined {\n return telemetryManagers.get(instance)\n}\n\n/**\n * Record a hook name for an instance. If the telemetry manager is\n * already initialized the event is logged immediately. Otherwise\n * the name is buffered and flushed when init completes.\n *\n * @internal\n */\nexport function trackHookMounted(instance: SanityInstance, hookName: string): void {\n if (!getTelemetryEnvironment()) return\n\n const manager = findManager(instance)\n if (manager) {\n logger.trace('hook mounted (logged)', {hookName, internal: true})\n manager.logHookFirstUsed(hookName)\n return\n }\n\n const root = getRootInstance(instance)\n let hooks = pendingHooks.get(root)\n if (!hooks) {\n hooks = new Set()\n pendingHooks.set(root, hooks)\n }\n if (!hooks.has(hookName)) {\n logger.trace('hook mounted (buffered)', {hookName, internal: true})\n }\n hooks.add(hookName)\n}\n\nfunction findManager(instance: SanityInstance): TelemetryManager | undefined {\n return telemetryManagers.get(instance)\n}\n\nfunction getRootInstance(instance: SanityInstance): SanityInstance {\n return instance\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_internal.js","sources":["../../src/telemetry/environment.ts","../../src/telemetry/events.ts","../../src/telemetry/initTelemetry.ts"],"sourcesContent":["/**\n * Telemetry environment classification.\n *\n * - `'development'` — the SDK is running on the local developer's machine\n * (`localhost` / `127.0.0.1` in the browser, or `NODE_ENV=development`\n * in Node). These are the original dev-only telemetry sessions.\n *\n * - `'production'` — the SDK is running on a production Sanity-controlled\n * domain (Studio deployments on `*.sanity.studio`, the dashboard on\n * `*.sanity.io`) where end users are authenticated Sanity users with\n * Populus consent records. Production telemetry is gated to this\n * allowlist; SDK apps deployed to customer-controlled domains do not\n * emit telemetry. Staging (`*.sanity.work`) and preview\n * (`*.sanity.dev`) hosts are deliberately excluded.\n *\n * @internal\n */\nexport type TelemetryEnvironment = 'development' | 'production'\n\n/**\n * Hostname suffixes that count as Sanity-controlled for the purposes of\n * production telemetry. A user reaching one of these hosts in the\n * browser is authenticated against Sanity and has a Populus consent\n * record, so we apply the same telemetry rules as the Studio's\n * `telemetry-sink`.\n *\n * The leading `.` is required: it ensures suffix matches hit a real\n * subdomain boundary, so apex matches (`sanity.io`, `sanity.studio`)\n * and lookalikes (`evilsanity.studio`) are excluded. Only production\n * hosts are listed; staging (`*.sanity.work`) and preview\n * (`*.sanity.dev`) hosts are excluded by omission.\n *\n * @internal\n */\nconst SANITY_CONTROLLED_HOST_SUFFIXES = ['.sanity.studio', '.sanity.io'] as const\n\nfunction getBrowserHostname(win: Window): string | null {\n const hostname = win.location?.hostname\n return typeof hostname === 'string' && hostname.length > 0 ? hostname.toLowerCase() : null\n}\n\nfunction isLocalHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1'\n}\n\nfunction isSanityControlledHostname(hostname: string): boolean {\n return SANITY_CONTROLLED_HOST_SUFFIXES.some((suffix) => hostname.endsWith(suffix))\n}\n\n/**\n * Returns the telemetry environment for the current runtime, or `null`\n * when telemetry should not run at all.\n *\n * Browser:\n * - `localhost` / `127.0.0.1` → `'development'`\n * - host matches the Sanity-controlled allowlist → `'production'`\n * - anything else (customer domains, unknown contexts) → `null`\n *\n * Node (scripts, SSR, tests):\n * - `NODE_ENV=development` → `'development'`\n * - otherwise → `null`. Production-side server runtimes don't carry the\n * browser-authenticated user/consent assumption, so we don't enable\n * them under the production gate.\n *\n * Bracket-notation `process.env['NODE_ENV']` is used to avoid bundler\n * dead-code replacement.\n *\n * @internal\n */\nexport function getTelemetryEnvironment(): TelemetryEnvironment | null {\n if (typeof window !== 'undefined') {\n const hostname = getBrowserHostname(window)\n if (!hostname) return null\n if (isLocalHostname(hostname)) return 'development'\n if (isSanityControlledHostname(hostname)) return 'production'\n return null\n }\n\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] === 'development') {\n return 'development'\n }\n return null\n}\n\n/**\n * Convenience predicate for \"telemetry can run in this environment\".\n *\n * @internal\n */\nexport function isTelemetryEnabled(): boolean {\n return getTelemetryEnvironment() !== null\n}\n","import {defineEvent} from '@sanity/telemetry'\n\n/** @internal */\nexport const SDKSessionStarted = defineEvent<{\n version: string\n projectId: string\n perspective: string\n authMethod: string\n}>({\n name: 'SDK Session Started',\n version: 1,\n description: 'SDK instance created (environment is recorded in the event context)',\n})\n\n/** @internal */\nexport const SDKHookMounted = defineEvent<{\n hookName: string\n}>({\n name: 'SDK Hook Mounted',\n version: 1,\n description: 'An SDK hook was mounted for the first time in this session',\n})\n\n/** @internal */\nexport const SDKSessionEnded = defineEvent<{\n durationSeconds: number\n hooksUsed: string[]\n}>({\n name: 'SDK Session Ended',\n version: 1,\n description: 'SDK instance disposed (environment is recorded in the event context)',\n})\n\n/** @internal */\nexport const SDKError = defineEvent<{\n errorType: string\n hookName: string\n}>({\n name: 'SDK Error',\n version: 1,\n description: 'Runtime error caught in the SDK',\n})\n","import {type SanityInstance} from '../store/createSanityInstance'\nimport {createLogger} from '../utils/logger'\nimport {getTelemetryEnvironment} from './environment'\nimport {type TelemetryManager} from './telemetryManager'\n\nconst DEFAULT_TELEMETRY_API_VERSION = '2024-11-12'\n\nconst logger = createLogger('telemetry')\n\n/**\n * Per-instance map of active telemetry managers. Allows the React\n * package (and other consumers) to look up the manager for a given\n * instance and log hook usage / errors without importing the full\n * telemetry module themselves.\n *\n * @internal\n */\nconst telemetryManagers = new WeakMap<SanityInstance, TelemetryManager>()\nconst pendingHooks = new WeakMap<SanityInstance, Set<string>>()\nconst initInFlight = new WeakSet<SanityInstance>()\n\n/**\n * Initializes telemetry for a SDK instance if the runtime environment\n * qualifies. The environment is resolved by `getTelemetryEnvironment()`:\n *\n * - `'development'` — local dev servers (`localhost` / `127.0.0.1`, or\n * Node with `NODE_ENV=development`). This is the original opt-in\n * surface.\n * - `'production'` — apps deployed to Sanity-controlled domains\n * (e.g. `*.sanity.studio`, the dashboard). End users are\n * authenticated Sanity users with Populus consent records, so we\n * apply the same consent gate as the Studio's `telemetry-sink`.\n *\n * Apps on customer-controlled domains return `null` and skip telemetry\n * entirely.\n *\n * `telemetryManager` and `clientStore` are dynamically imported so the\n * telemetry code path stays out of production bundles for apps that\n * don't qualify. Only the lightweight environment check runs at boot.\n *\n * The `projectId` must be passed explicitly because the resource\n * configuration is typically set by the React layer after the\n * instance has already been created.\n *\n * @internal\n */\nexport function initTelemetry(instance: SanityInstance, projectId: string): void {\n const environment = getTelemetryEnvironment()\n if (!environment) {\n logger.trace('initTelemetry skipped: environment not eligible', {internal: true})\n return\n }\n if (!projectId) {\n logger.trace('initTelemetry skipped: no projectId', {internal: true})\n return\n }\n if (telemetryManagers.has(instance) || initInFlight.has(instance)) {\n return\n }\n initInFlight.add(instance)\n\n logger.debug('initializing telemetry', {projectId, environment})\n\n Promise.all([\n import('./telemetryManager'),\n import('../client/clientStore'),\n import('../auth/authStore'),\n ])\n .then(async ([{createTelemetryManager}, {getClient}, {getTokenState}]) => {\n if (instance.isDisposed()) {\n initInFlight.delete(instance)\n logger.debug('telemetry skipped: instance disposed before imports resolved')\n return\n }\n\n // Wait for the auth store to resolve a token. The client needs a\n // Bearer token for the consent check and batch POSTs. If the token\n // is already available (e.g. static token config), this resolves\n // immediately. For OAuth/localStorage discovery it waits for the\n // first emission. For unauthenticated apps the promise never\n // resolves, which is fine since telemetry requires auth anyway.\n const token = getTokenState(instance).getCurrent()\n logger.trace('auth token check', {tokenPresent: !!token, internal: true})\n\n if (!token) {\n logger.debug('waiting for auth token')\n const hasToken = await new Promise<boolean>((resolve) => {\n if (instance.isDisposed()) return resolve(false)\n const cleanup = {unsubscribe: () => {}}\n const unsub = instance.onDispose(() => {\n cleanup.unsubscribe()\n resolve(false)\n })\n // The token observable is a `shareReplay({bufferSize: 1, refCount: true})`\n // (see `createStateSourceAction`), so it can deliver a buffered value\n // synchronously while we're still inside `.subscribe(cb)`. At that\n // moment `sub` is in the TDZ, so the callback can't reach it. We\n // gate on a `received` flag and let the post-subscribe block do the\n // unsubscribe in the sync-emission case.\n let received = false\n const sub = getTokenState(instance).observable.subscribe((t) => {\n if (received || !t) return\n received = true\n logger.debug('auth token received')\n unsub()\n resolve(true)\n cleanup.unsubscribe()\n })\n cleanup.unsubscribe = () => sub.unsubscribe()\n if (received) cleanup.unsubscribe()\n })\n if (!hasToken || instance.isDisposed()) {\n initInFlight.delete(instance)\n logger.debug('telemetry skipped: no token resolved or instance disposed')\n return\n }\n }\n\n const manager = createTelemetryManager({\n sessionId: instance.instanceId,\n getClient: () => getClient(instance, {apiVersion: DEFAULT_TELEMETRY_API_VERSION}),\n projectId,\n environment,\n })\n\n const consented = await manager.checkConsent()\n logger.debug('consent check complete', {consented})\n if (!consented || instance.isDisposed()) {\n initInFlight.delete(instance)\n manager.dispose()\n return\n }\n\n initInFlight.delete(instance)\n telemetryManagers.set(instance, manager)\n\n const buffered = pendingHooks.get(instance)\n if (buffered) {\n logger.debug('flushing buffered hooks', {hooks: Array.from(buffered)})\n for (const hookName of buffered) {\n manager.logHookFirstUsed(hookName)\n }\n pendingHooks.delete(instance)\n }\n\n const config = instance.config\n const perspective = typeof config.perspective === 'string' ? config.perspective : 'published'\n const authMethod = config.auth?.token\n ? 'token'\n : config.studio?.auth?.token\n ? 'studio'\n : 'default'\n\n logger.info('telemetry session started', {projectId, perspective, authMethod, environment})\n manager.logSessionStarted({\n projectId,\n perspective,\n authMethod,\n })\n\n instance.onDispose(() => {\n manager.endSession()\n telemetryManagers.delete(instance)\n logger.debug('telemetry session ended')\n })\n })\n .catch((err) => {\n initInFlight.delete(instance)\n logger.warn('telemetry init failed', {error: err})\n })\n}\n\n/**\n * Retrieves the telemetry manager for an instance, if one exists.\n * Returns undefined when telemetry is disabled or not yet initialized.\n *\n * @internal\n */\nexport function getTelemetryManager(instance: SanityInstance): TelemetryManager | undefined {\n return telemetryManagers.get(instance)\n}\n\n/**\n * Record a hook name for an instance. If the telemetry manager is\n * already initialized the event is logged immediately. Otherwise\n * the name is buffered and flushed when init completes.\n *\n * @internal\n */\nexport function trackHookMounted(instance: SanityInstance, hookName: string): void {\n if (!getTelemetryEnvironment()) return\n\n const manager = findManager(instance)\n if (manager) {\n logger.trace('hook mounted (logged)', {hookName, internal: true})\n manager.logHookFirstUsed(hookName)\n return\n }\n\n const root = getRootInstance(instance)\n let hooks = pendingHooks.get(root)\n if (!hooks) {\n hooks = new Set()\n pendingHooks.set(root, hooks)\n }\n if (!hooks.has(hookName)) {\n logger.trace('hook mounted (buffered)', {hookName, internal: true})\n }\n hooks.add(hookName)\n}\n\nfunction findManager(instance: SanityInstance): TelemetryManager | undefined {\n return telemetryManagers.get(instance)\n}\n\nfunction getRootInstance(instance: SanityInstance): SanityInstance {\n return instance\n}\n"],"names":[],"mappings":"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"}
|