@sanity/sdk 3.0.0-rc.2 → 3.1.0

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 (102) hide show
  1. package/dist/_exports/_internal.d.ts +25 -3
  2. package/dist/_exports/_internal.d.ts.map +1 -1
  3. package/dist/_exports/_internal.js +127 -9
  4. package/dist/_exports/_internal.js.map +1 -1
  5. package/dist/_exports/agent.d.ts +1 -1
  6. package/dist/_exports/agent.js +1 -1
  7. package/dist/_exports/comlink.d.ts +1 -1
  8. package/dist/_exports/comlink.js +2 -3
  9. package/dist/_exports/comlink.js.map +1 -1
  10. package/dist/{authStore-DKFX8fn7.d.ts → authStore-C-OEkGaM.d.ts} +30 -44
  11. package/dist/authStore-C-OEkGaM.d.ts.map +1 -0
  12. package/dist/{authStore-CtE9bLHW.js → clientStore-gUALQ0qW.js} +269 -11
  13. package/dist/{authStore-CtE9bLHW.js.map → clientStore-gUALQ0qW.js.map} +1 -1
  14. package/dist/{createSanityInstance-DUI1bGIg.d.ts → createSanityInstance-DCePpBYW.d.ts} +2 -2
  15. package/dist/{createSanityInstance-DUI1bGIg.d.ts.map → createSanityInstance-DCePpBYW.d.ts.map} +1 -1
  16. package/dist/{getNodeState-CR3__B2D.js → getNodeState-E0hjqFOo.js} +2 -3
  17. package/dist/{getNodeState-CR3__B2D.js.map → getNodeState-E0hjqFOo.js.map} +1 -1
  18. package/dist/index.d.ts +3 -3
  19. package/dist/index.js +168 -176
  20. package/dist/index.js.map +1 -1
  21. package/dist/{createStateSourceAction-BOKtqFNm.js → object-BwynGPRZ.js} +87 -3
  22. package/dist/object-BwynGPRZ.js.map +1 -0
  23. package/dist/{queryStore-DPf9sN3V.js → version-C90rNWaX.js} +48 -16
  24. package/dist/version-C90rNWaX.js.map +1 -0
  25. package/package.json +4 -4
  26. package/src/_exports/_internal.ts +1 -0
  27. package/src/_exports/index.ts +7 -4
  28. package/src/access/checkPermissions.test.ts +1 -1
  29. package/src/access/checkPermissions.ts +1 -1
  30. package/src/applications/applications.test.ts +4 -4
  31. package/src/applications/applications.ts +4 -4
  32. package/src/auth/handleAuthCallback.test.ts +2 -2
  33. package/src/auth/handleAuthCallback.ts +1 -1
  34. package/src/auth/logout.test.ts +1 -1
  35. package/src/auth/logout.ts +1 -1
  36. package/src/auth/refreshStampedToken.ts +1 -1
  37. package/src/auth/studioModeAuth.test.ts +1 -1
  38. package/src/auth/studioModeAuth.ts +1 -1
  39. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +2 -2
  40. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +1 -1
  41. package/src/comments/addonDatasetStore.test.ts +2 -2
  42. package/src/comments/addonDatasetStore.ts +2 -2
  43. package/src/comments/commentActions.ts +6 -5
  44. package/src/comments/commentsStore.ts +4 -4
  45. package/src/datasets/datasets.test.ts +44 -9
  46. package/src/datasets/datasets.ts +24 -23
  47. package/src/document/applyDocumentActions.ts +2 -6
  48. package/src/document/documentConstants.ts +9 -0
  49. package/src/document/documentStore.concurrency.test.ts +2 -1
  50. package/src/document/documentStore.test.ts +87 -17
  51. package/src/document/documentStore.ts +5 -5
  52. package/src/document/permissions.ts +2 -1
  53. package/src/document/processActions.test.ts +2 -1
  54. package/src/document/processMutations.ts +3 -2
  55. package/src/document/reducers.test.ts +224 -0
  56. package/src/document/reducers.ts +110 -27
  57. package/src/favorites/favorites.test.ts +64 -24
  58. package/src/favorites/favorites.ts +73 -22
  59. package/src/installations/installations.test.ts +2 -2
  60. package/src/installations/installations.ts +2 -2
  61. package/src/organization/organization.test.ts +2 -2
  62. package/src/organization/organization.ts +1 -1
  63. package/src/organizations/organizations.test.ts +2 -2
  64. package/src/organizations/organizations.ts +1 -1
  65. package/src/presence/presenceStore.test.ts +15 -22
  66. package/src/presence/presenceStore.ts +3 -2
  67. package/src/project/project.test.ts +3 -3
  68. package/src/project/project.ts +1 -1
  69. package/src/projection/getProjectionState.test.ts +6 -4
  70. package/src/projection/getProjectionState.ts +2 -2
  71. package/src/projects/projects.test.ts +2 -2
  72. package/src/projects/projects.ts +1 -1
  73. package/src/query/queryStore.ts +3 -3
  74. package/src/store/createSanityInstance.test.ts +1 -1
  75. package/src/store/createSanityInstance.ts +4 -4
  76. package/src/store/createStoreInstance.test.ts +0 -5
  77. package/src/store/fetcherStore.test.ts +23 -1
  78. package/src/store/fetcherStore.ts +3 -3
  79. package/src/telemetry/telemetryManager.test.ts +1 -1
  80. package/src/telemetry/telemetryManager.ts +2 -2
  81. package/src/users/usersStore.test.ts +1 -1
  82. package/src/users/usersStore.ts +5 -5
  83. package/src/utils/ids.test.ts +40 -15
  84. package/src/utils/ids.ts +47 -2
  85. package/dist/authStore-DKFX8fn7.d.ts.map +0 -1
  86. package/dist/clientStore-BtE2-q2i.js +0 -90
  87. package/dist/clientStore-BtE2-q2i.js.map +0 -1
  88. package/dist/createStateSourceAction-BOKtqFNm.js.map +0 -1
  89. package/dist/getEnv-D5RGkQLu.js +0 -8
  90. package/dist/getEnv-D5RGkQLu.js.map +0 -1
  91. package/dist/logger-DAtJb5RQ.js +0 -173
  92. package/dist/logger-DAtJb5RQ.js.map +0 -1
  93. package/dist/object-CxXlSVg7.js +0 -83
  94. package/dist/object-CxXlSVg7.js.map +0 -1
  95. package/dist/queryStore-DPf9sN3V.js.map +0 -1
  96. package/dist/rolldown-runtime-vyAXikos.js +0 -9
  97. package/dist/telemetryManager-Dq_qCkeI.js +0 -127
  98. package/dist/telemetryManager-Dq_qCkeI.js.map +0 -1
  99. package/dist/version-BChjsi4u.js +0 -9
  100. package/dist/version-BChjsi4u.js.map +0 -1
  101. package/src/utils/createFetcherStore.test.ts +0 -171
  102. package/src/utils/createFetcherStore.ts +0 -284
@@ -1,4 +1,3 @@
1
- import { t as getEnv } from "./getEnv-D5RGkQLu.js";
2
1
  import "@sanity/client";
3
2
  import { Observable, defer, distinctUntilChanged, finalize, map, shareReplay, skip } from "rxjs";
4
3
  import { devtools } from "zustand/middleware";
@@ -22,6 +21,11 @@ function isCanvasResource(resource) {
22
21
  return "canvasId" in resource;
23
22
  }
24
23
  const isReleasePerspective = (perspective) => typeof perspective == "object" && !!perspective && "releaseName" in perspective;
24
+ function getEnv(key) {
25
+ if (import.meta.env) return import.meta.env[key];
26
+ if (typeof process < "u" && process.env) return process.env[key];
27
+ if (typeof window < "u" && window.ENV) return window.ENV?.[key];
28
+ }
25
29
  /**
26
30
  * Creates a reactive store state container with multiple access patterns
27
31
  * @param initialState - Initial state value for the store
@@ -295,6 +299,86 @@ function withSubscribeHook(obs, fn) {
295
299
  return cleanup ? obs.pipe(finalize(() => cleanup())) : obs;
296
300
  });
297
301
  }
298
- export { defineStore as a, isDatasetResource as c, bindActionGlobally as i, isMediaLibraryResource as l, bindActionByResource as n, isReleasePerspective as o, bindActionByResourceAndPerspective as r, isCanvasResource as s, createStateSourceAction as t };
302
+ /**
303
+ * Returns true when the input is a non-null object.
304
+ *
305
+ * @internal
306
+ */
307
+ function isObject(value) {
308
+ return typeof value == "object" && !!value;
309
+ }
310
+ const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key), isPlainObject = (value) => {
311
+ if (!isObject(value)) return !1;
312
+ let prototype = Object.getPrototypeOf(value);
313
+ return prototype === Object.prototype || prototype === null;
314
+ };
315
+ /**
316
+ * Creates a shallow copy without the provided property.
317
+ *
318
+ * @internal
319
+ */
320
+ function omitProperty(value, key) {
321
+ if (!value) return {};
322
+ let { [key]: _omitted, ...rest } = value;
323
+ return rest;
324
+ }
325
+ /**
326
+ * Creates a shallow copy containing only the provided properties.
327
+ *
328
+ * @internal
329
+ */
330
+ function pickProperties(value, keys) {
331
+ let result = {};
332
+ for (let key of keys) hasOwn(value, key) && (result[key] = value[key]);
333
+ return result;
334
+ }
335
+ const areSetsEqual = (left, right) => {
336
+ if (left.size !== right.size) return !1;
337
+ let unmatched = [...right];
338
+ outer: for (let leftValue of left) {
339
+ for (let index = 0; index < unmatched.length; index++) if (isDeepEqual(leftValue, unmatched[index])) {
340
+ unmatched.splice(index, 1);
341
+ continue outer;
342
+ }
343
+ return !1;
344
+ }
345
+ return unmatched.length === 0;
346
+ }, areMapsEqual = (left, right) => {
347
+ if (left.size !== right.size) return !1;
348
+ let unmatched = [...right.entries()];
349
+ outer: for (let [leftKey, leftValue] of left) {
350
+ for (let index = 0; index < unmatched.length; index++) {
351
+ let [rightKey, rightValue] = unmatched[index];
352
+ if (isDeepEqual(leftKey, rightKey) && isDeepEqual(leftValue, rightValue)) {
353
+ unmatched.splice(index, 1);
354
+ continue outer;
355
+ }
356
+ }
357
+ return !1;
358
+ }
359
+ return unmatched.length === 0;
360
+ };
361
+ /**
362
+ * Compares values deeply across the plain object, array, map, and set shapes used by the SDK.
363
+ * This helper is intended for acyclic SDK data structures and does not guard against circular
364
+ * references.
365
+ *
366
+ * @internal
367
+ */
368
+ function isDeepEqual(left, right) {
369
+ if (Object.is(left, right)) return !0;
370
+ if (!isObject(left) || !isObject(right)) return !1;
371
+ if (left instanceof Date && right instanceof Date) return left.getTime() === right.getTime();
372
+ if (left instanceof RegExp && right instanceof RegExp) return left.source === right.source && left.flags === right.flags;
373
+ if (left instanceof Set && right instanceof Set) return areSetsEqual(left, right);
374
+ if (left instanceof Map && right instanceof Map) return areMapsEqual(left, right);
375
+ if (Array.isArray(left) || Array.isArray(right)) return !Array.isArray(left) || !Array.isArray(right) || left.length !== right.length ? !1 : left.every((value, index) => isDeepEqual(value, right[index]));
376
+ if (!isPlainObject(left) || !isPlainObject(right)) return !1;
377
+ let leftKeys = Object.keys(left), rightKeys = Object.keys(right);
378
+ if (leftKeys.length !== rightKeys.length) return !1;
379
+ for (let key of leftKeys) if (!hasOwn(right, key) || !isDeepEqual(left[key], right[key])) return !1;
380
+ return !0;
381
+ }
382
+ export { createStateSourceAction as a, bindActionGlobally as c, isReleasePerspective as d, isCanvasResource as f, pickProperties as i, defineStore as l, isMediaLibraryResource as m, isObject as n, bindActionByResource as o, isDatasetResource as p, omitProperty as r, bindActionByResourceAndPerspective as s, isDeepEqual as t, getEnv as u };
299
383
 
300
- //# sourceMappingURL=createStateSourceAction-BOKtqFNm.js.map
384
+ //# sourceMappingURL=object-BwynGPRZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-BwynGPRZ.js","names":[],"sources":["../src/config/sanityConfig.ts","../src/releases/utils/isReleasePerspective.ts","../src/utils/getEnv.ts","../src/store/createStoreState.ts","../src/store/defineStore.ts","../src/store/createStoreInstance.ts","../src/store/createActionBinder.ts","../src/store/createStateSourceAction.ts","../src/utils/object.ts"],"sourcesContent":["import {type ClientPerspective, type StackablePerspective} from '@sanity/client'\n\nimport {type AuthConfig} from './authConfig'\n\n/**\n * A minimal Observable-compatible interface for subscribing to token changes.\n * Any object with a `subscribe` method that follows this contract will work,\n * including RxJS Observables. This avoids coupling the SDK to a specific\n * reactive library.\n *\n * @public\n */\nexport interface TokenSource {\n /** Subscribe to token emissions. Emits `null` when logged out. */\n subscribe(observer: {next: (token: string | null) => void}): {unsubscribe(): void}\n}\n\n/**\n * Studio-specific configuration for the SDK.\n * When present, the SDK operates in studio mode and derives auth from the\n * provided token source instead of discovering tokens independently.\n *\n * @public\n */\nexport interface StudioConfig {\n /**\n * Whether the Studio has already determined the user is authenticated.\n * When `true` and the token source emits `null`, the SDK infers\n * cookie-based auth is in use rather than transitioning to logged-out.\n */\n authenticated?: boolean\n /** Reactive auth token source from the Studio's auth store. */\n auth?: {\n /**\n * A reactive token source. The SDK subscribes and stays in sync — the\n * Studio is the single authority for auth and handles token refresh.\n *\n * Optional because older Studios may not expose it. When absent, the\n * SDK falls back to localStorage/cookie discovery.\n */\n token?: TokenSource\n }\n}\n\n/**\n * Represents the minimal configuration required to identify a Sanity project.\n * @public\n */\nexport interface ProjectHandle<TProjectId extends string = string> {\n projectId?: TProjectId\n}\n\n/**\n * @public\n */\nexport type ReleasePerspective = {\n releaseName: string\n excludedPerspectives?: StackablePerspective[]\n}\n\n/**\n * @public\n */\nexport interface PerspectiveHandle {\n perspective?: ClientPerspective | ReleasePerspective\n}\n\n/**\n * @public\n */\nexport interface DatasetHandle<TDataset extends string = string, TProjectId extends string = string>\n extends ProjectHandle<TProjectId>, PerspectiveHandle {\n dataset?: TDataset\n /**\n * @beta\n * Explicit resource to use. On an individual operation this overrides any default;\n * on a `SanityConfig` it becomes the instance's default resource. Unlike\n * `projectId`/`dataset`, this can also be a media library or canvas resource.\n */\n resource?: DocumentResource\n}\n\n/**\n * Identifies a specific document type within a Sanity dataset and project.\n * Includes `projectId`, `dataset`, and `documentType`.\n * Optionally includes a `documentId` and `liveEdit` flag.\n * @public\n */\nexport interface DocumentTypeHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DatasetHandle<TDataset, TProjectId> {\n documentId?: string\n documentType: TDocumentType\n /**\n * Indicates whether this document uses liveEdit mode.\n * When `true`, the document does not use the draft/published model and edits are applied directly to the document.\n * @see https://www.sanity.io/docs/content-lake/drafts#ca0663a8f002\n */\n liveEdit?: boolean\n}\n\n/**\n * Uniquely identifies a specific document within a Sanity dataset and project.\n * Includes `projectId`, `dataset`, `documentType`, and the required `documentId`.\n * Commonly used by document-related hooks and components to reference a document without fetching its full content initially.\n * @public\n */\nexport interface DocumentHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentTypeHandle<TDocumentType, TDataset, TProjectId> {\n documentId: string\n}\n\n/**\n * Identifies a release within a Sanity dataset and project. `releaseId` is the\n * `name` parameter on the release document (e.g. `{name: 'r41035a4'}`).\n * The underlying release document ID is `_.releases.<releaseId>`.\n * It's also the `id` parameter sent to the Actions API.\n * (This type doesn't need to have ProjectId / Dataset generics since it's always the same shape)\n * @beta\n */\nexport interface ReleaseHandle extends DatasetHandle {\n releaseId: string\n}\n\n/**\n * Represents the complete configuration for a Sanity SDK instance\n * @public\n */\nexport interface SanityConfig extends DatasetHandle, PerspectiveHandle {\n /**\n * Authentication configuration for the instance\n */\n auth?: AuthConfig\n /**\n * Studio configuration provided by a Sanity Studio workspace.\n * When present, the SDK operates in studio mode and derives auth from the\n * workspace's reactive token source — no manual configuration needed.\n *\n * @remarks Typically set automatically by `SanityApp` when it detects an\n * `SDKStudioContext` provider. Can also be set explicitly for programmatic use.\n */\n studio?: StudioConfig\n}\n\n/**\n * A document resource can be used for querying.\n * This will soon be the default way to identify where you are querying from.\n *\n * @beta\n */\nexport type DocumentResource = DatasetResource | MediaLibraryResource | CanvasResource\n\n/**\n * @beta\n */\nexport type DatasetResource = {projectId: string; dataset: string}\n\n/**\n * @beta\n */\nexport type MediaLibraryResource = {mediaLibraryId: string}\n\n/**\n * @beta\n */\nexport type CanvasResource = {canvasId: string}\n\n/**\n * @beta\n */\nexport function isDatasetResource(resource: DocumentResource): resource is DatasetResource {\n return 'projectId' in resource && 'dataset' in resource\n}\n\n/**\n * @beta\n */\nexport function isMediaLibraryResource(\n resource: DocumentResource,\n): resource is MediaLibraryResource {\n return 'mediaLibraryId' in resource\n}\n\n/**\n * @beta\n */\nexport function isCanvasResource(resource: DocumentResource): resource is CanvasResource {\n return 'canvasId' in resource\n}\n","import {type PerspectiveHandle, type ReleasePerspective} from '../../config/sanityConfig'\n\nexport const isReleasePerspective = (\n perspective: PerspectiveHandle['perspective'],\n): perspective is ReleasePerspective => {\n return typeof perspective === 'object' && perspective !== null && 'releaseName' in perspective\n}\n","// Local type declaration for Remix\ntype WindowWithEnv = Window &\n typeof globalThis & {\n ENV?: Record<string, unknown>\n }\n\ntype KnownEnvVar = 'DEV' | 'PKG_VERSION'\n\nexport function getEnv(key: KnownEnvVar): unknown {\n if (typeof import.meta !== 'undefined' && import.meta.env) {\n // Vite environment variables\n return (import.meta.env as unknown as Record<string, unknown>)[key]\n } else if (typeof process !== 'undefined' && process.env) {\n // Node.js or server-side environment variables\n return process.env[key]\n } else if (typeof window !== 'undefined' && (window as WindowWithEnv).ENV) {\n // Remix-style client-side environment variables\n return (window as WindowWithEnv).ENV?.[key]\n }\n return undefined\n}\n","import {Observable} from 'rxjs'\nimport {devtools, type DevtoolsOptions} from 'zustand/middleware'\nimport {createStore} from 'zustand/vanilla'\n\n/**\n * Represents a reactive store state container with multiple access patterns\n */\nexport interface StoreState<TState> {\n /**\n * Gets the current state value\n *\n * @remarks\n * This is a direct synchronous accessor that doesn't trigger subscriptions\n */\n get: () => TState\n\n /**\n * Updates the store state\n * @param name - Action name for devtools tracking\n * @param updatedState - New state value or updater function\n *\n * @remarks\n * When providing a partial object, previous top-level keys not included in\n * the update will be preserved.\n */\n set: (name: string, updatedState: Partial<TState> | ((s: TState) => Partial<TState>)) => void\n\n /**\n * Observable stream of state changes\n * @remarks\n * - Emits immediately with current state on subscription\n * - Shares underlying subscription between observers\n * - Only emits when state reference changes\n * - Completes when store is disposed\n */\n observable: Observable<TState>\n}\n\n/**\n * Creates a reactive store state container with multiple access patterns\n * @param initialState - Initial state value for the store\n * @param devToolsOptions - Configuration for Zustand devtools integration\n * @returns StoreState instance with get/set/observable interface\n *\n * @example\n * ```typescript\n * // Create a simple counter store\n * const counterStore = createStoreState({ count: 0 });\n *\n * // Update state\n * counterStore.set('increment', { count: 1 });\n *\n * // Observe changes\n * counterStore.observable.subscribe(console.log);\n * ```\n *\n * @remarks\n * Uses Zustand for state management under the hood with RxJS for observable interface.\n * Designed to work with both imperative and reactive programming patterns.\n */\nexport function createStoreState<TState>(\n initialState: TState,\n devToolsOptions?: DevtoolsOptions,\n): StoreState<TState> {\n // Create underlying Zustand store with devtools integration\n const store = createStore<TState>()(devtools(() => initialState, devToolsOptions))\n\n return {\n get: store.getState,\n set: (actionKey, updatedState) => {\n const currentState = store.getState()\n const nextState =\n typeof updatedState === 'function' ? updatedState(currentState) : updatedState\n\n // Optimization: Skip update if state reference remains the same\n if (currentState !== nextState) {\n store.setState(nextState, false, actionKey)\n }\n },\n observable: new Observable((observer) => {\n // Emit current state immediately on subscription\n const emit = () => observer.next(store.getState())\n emit()\n\n // Subscribe to Zustand store changes\n const unsubscribe = store.subscribe(emit)\n\n // Cleanup when observable unsubscribed\n return () => unsubscribe()\n }),\n }\n}\n","import {type SanityInstance} from './createSanityInstance'\nimport {type StoreState} from './createStoreState'\n\n/**\n * Context object provided to store initialization functions\n */\nexport interface StoreContext<TState, TKey = unknown> {\n /**\n * Sanity instance associated with this store\n *\n * @remarks\n * Provides access to the Sanity configuration and instance lifecycle methods\n */\n instance: SanityInstance\n\n /**\n * Reactive store state management utilities\n *\n * @remarks\n * Contains methods for getting/setting state and observing changes\n */\n state: StoreState<TState>\n\n /**\n * The key used to instantiate the store.\n */\n key: TKey\n}\n\n/**\n * Defines the structure and behavior of a store\n *\n * @remarks\n * Stores are isolated state containers that can be associated with Sanity instances.\n * Each store definition creates a separate state instance per composite key.\n */\nexport interface StoreDefinition<TState, TKey = unknown> {\n /**\n * Unique name for the store\n *\n * @remarks\n * Used for debugging, devtools integration, and store identification\n */\n name: string\n\n /**\n * Creates the initial state for the store\n * @param instance - Sanity instance the store is being created for\n * @returns Initial state value\n *\n * @remarks\n * Called when a new store instance is created. Can use Sanity instance\n * configuration to determine initial state.\n */\n getInitialState: (instance: SanityInstance, key: TKey) => TState\n\n /**\n * Optional initialization function\n * @param context - Store context with state and instance access\n * @returns Optional cleanup function for store disposal\n *\n * @remarks\n * Use this for:\n * - Setting up event listeners\n * - Initial data fetching\n * - Connecting external services\n *\n * Return a cleanup function to:\n * - Remove event listeners\n * - Cancel pending operations\n * - Dispose external connections\n */\n initialize?: (context: StoreContext<TState, TKey>) => (() => void) | undefined\n}\n\n/**\n * Typescript helper function for creating store definitions\n *\n * @param storeDefinition - Configuration object defining the store\n * @returns The finalized store definition\n */\nexport function defineStore<TState, TKey = unknown>(\n storeDefinition: StoreDefinition<TState, TKey>,\n): StoreDefinition<TState, TKey> {\n return storeDefinition\n}\n","import {getEnv} from '../utils/getEnv'\nimport {type SanityInstance} from './createSanityInstance'\nimport {createStoreState, type StoreState} from './createStoreState'\nimport {type StoreDefinition} from './defineStore'\n\n/**\n * Represents a running instance of a store with its own state and lifecycle\n *\n * @remarks\n * Each StoreInstance is tied to a specific SanityInstance, manages its own state,\n * and can be independently disposed when no longer needed.\n */\nexport interface StoreInstance<TState> {\n /**\n * Access to the reactive state container for this store instance\n */\n state: StoreState<TState>\n\n /**\n * Checks if this store instance has been disposed\n * @returns Boolean indicating disposed state\n */\n isDisposed: () => void\n\n /**\n * Cleans up this store instance and runs any initialization cleanup functions\n * @remarks Triggers the cleanup function returned from the initialize method\n */\n dispose: () => void\n}\n\n/**\n * Creates a new instance of a store from a store definition\n *\n * @param instance - The Sanity instance this store will be associated with\n * @param storeDefinition - The store definition containing initial state and initialization logic\n * @returns A store instance with state management and lifecycle methods\n *\n * @remarks\n * The store instance maintains its own state that is scoped to the given Sanity instance.\n * If the store definition includes an initialize function, it will be called during\n * instance creation, and its cleanup function will be called during disposal.\n *\n * @example\n * ```ts\n * const counterStore = defineStore({\n * name: 'Counter',\n * getInitialState: () => ({ count: 0 }),\n * initialize: ({state}) => {\n * console.log('Counter store initialized')\n * return () => console.log('Counter store disposed')\n * }\n * })\n *\n * const instance = createStoreInstance(sanityInstance, counterStore)\n * // Later when done with the store:\n * instance.dispose()\n * ```\n */\nexport function createStoreInstance<TState, TKey extends {name: string}>(\n instance: SanityInstance,\n key: TKey,\n {name, getInitialState, initialize}: StoreDefinition<TState, TKey>,\n): StoreInstance<TState> {\n const state = createStoreState(getInitialState(instance, key), {\n enabled: !!getEnv('DEV'),\n name: `${name}-${key.name}`,\n })\n const dispose = initialize?.({state, instance, key})\n const disposed = {current: false}\n\n return {\n state,\n dispose: () => {\n if (disposed.current) return\n disposed.current = true\n dispose?.()\n },\n isDisposed: () => disposed.current,\n }\n}\n","import {type ClientPerspective} from '@sanity/client'\n\nimport {\n type DatasetHandle,\n type DocumentResource,\n isCanvasResource,\n isDatasetResource,\n isMediaLibraryResource,\n type ReleasePerspective,\n} from '../config/sanityConfig'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {type SanityInstance} from './createSanityInstance'\nimport {createStoreInstance, type StoreInstance} from './createStoreInstance'\nimport {type StoreState} from './createStoreState'\nimport {type StoreContext, type StoreDefinition} from './defineStore'\n\nexport interface BoundResourceKey {\n name: string\n resource: DocumentResource\n}\nexport interface BoundPerspectiveKey extends BoundResourceKey {\n perspective: ClientPerspective | ReleasePerspective\n}\n/**\n * Defines a store action that operates on a specific state type\n */\nexport type StoreAction<TState, TParams extends unknown[], TReturn, TKey = unknown> = (\n context: StoreContext<TState, TKey>,\n ...params: TParams\n) => TReturn\n\n/**\n * Represents a store action that has been bound to a specific store instance\n */\nexport type BoundStoreAction<_TState, TParams extends unknown[], TReturn> = (\n instance: SanityInstance,\n ...params: TParams\n) => TReturn\n\n/**\n * Creates an action binder function that uses the provided key function\n * to determine how store instances are shared between Sanity instances\n *\n * @param keyFn - Function that generates a key from a Sanity config\n * @returns A function that binds store actions to Sanity instances\n *\n * @remarks\n * Action binders determine how store instances are shared across multiple\n * Sanity instances. The key function determines which instances share state.\n *\n * @example\n * ```ts\n * // Create a custom binder that uses a tenant ID for isolation\n * const bindActionByTenant = createActionBinder(config => config.tenantId || 'default')\n *\n * // Use the custom binder with a store definition\n * const getTenantUsers = bindActionByTenant(\n * userStore,\n * ({state}) => state.get().users\n * )\n * ```\n */\nexport function createActionBinder<\n TKey extends {name: string},\n TKeyParams extends unknown[] = unknown[],\n>(keyFn: (instance: SanityInstance, ...params: TKeyParams) => TKey) {\n const instanceRegistry = new Map<string, Set<string>>()\n const storeRegistry = new Map<string, StoreInstance<unknown>>()\n\n /**\n * Binds a store action to a store definition\n *\n * @param storeDefinition - The store definition\n * @param action - The action to bind\n * @returns A function that executes the action with a Sanity instance\n */\n return function bindAction<TState, TParams extends TKeyParams, TReturn>(\n storeDefinition: StoreDefinition<TState, TKey>,\n action: StoreAction<TState, TParams, TReturn, TKey>,\n ): BoundStoreAction<TState, TParams, TReturn> {\n return function boundAction(instance: SanityInstance, ...params: TParams) {\n const key = keyFn(instance, ...params)\n const compositeKey = storeDefinition.name + (key.name ? `:${key.name}` : '')\n\n // Get or create instance set for this composite key\n let instances = instanceRegistry.get(compositeKey)\n if (!instances) {\n instances = new Set<string>()\n instanceRegistry.set(compositeKey, instances)\n }\n\n // Register instance for disposal tracking\n if (!instances.has(instance.instanceId)) {\n instances.add(instance.instanceId)\n instance.onDispose(() => {\n instances.delete(instance.instanceId)\n\n // Clean up when last instance is disposed\n if (instances.size === 0) {\n storeRegistry.get(compositeKey)?.dispose()\n storeRegistry.delete(compositeKey)\n instanceRegistry.delete(compositeKey)\n }\n })\n }\n\n // Get or create store instance\n let storeInstance = storeRegistry.get(compositeKey)\n if (!storeInstance) {\n storeInstance = createStoreInstance(instance, key, storeDefinition)\n storeRegistry.set(compositeKey, storeInstance)\n }\n\n // Execute action with store context\n return action({instance, state: storeInstance.state as StoreState<TState>, key}, ...params)\n }\n }\n}\n\nconst createResourceKey = (\n instance: SanityInstance,\n resource?: DocumentResource,\n): BoundResourceKey => {\n let name: string | undefined\n let resourceForKey: DocumentResource | undefined\n // A per-call resource wins; otherwise use the instance's default resource.\n const effectiveResource = resource ?? instance.config.resource\n if (effectiveResource) {\n resourceForKey = effectiveResource\n if (isDatasetResource(effectiveResource)) {\n name = `${effectiveResource.projectId}.${effectiveResource.dataset}`\n } else if (isMediaLibraryResource(effectiveResource)) {\n name = `media-library:${effectiveResource.mediaLibraryId}`\n } else if (isCanvasResource(effectiveResource)) {\n name = `canvas:${effectiveResource.canvasId}`\n } else {\n throw new Error(`Received invalid resource: ${JSON.stringify(effectiveResource)}`)\n }\n return {name, resource: resourceForKey}\n }\n\n // `projectId`/`dataset` on the config are shorthand for a dataset resource.\n const {projectId, dataset} = instance.config\n if (!projectId || !dataset) {\n throw new Error('This API requires a project ID and dataset configured.')\n }\n return {name: `${projectId}.${dataset}`, resource: {projectId, dataset}}\n}\n\n/**\n * Binds an action to a store that's scoped to a specific document resource.\n **/\nexport const bindActionByResource = createActionBinder<\n BoundResourceKey,\n // `resource` is optional because it falls back to the instance config in\n // `createResourceKey` — see the note there on why that fallback still exists.\n [{resource?: DocumentResource}, ...unknown[]]\n>((instance, {resource}) => {\n return createResourceKey(instance, resource)\n})\n\n/**\n * Binds an action to a store that's scoped to a specific document resource and perspective.\n *\n * @remarks\n * This creates actions that operate on state isolated to a specific document resource and perspective.\n * Different document resources and perspectives will have separate states.\n *\n * This is mostly useful for stores that do batch fetching operations, since the query store\n * can isolate single queries by perspective.\n *\n * @throws Error if resource or perspective is missing from the Sanity instance config\n *\n * @example\n * ```ts\n * // Define a store\n * const documentStore = defineStore<DocumentState>({\n * name: 'Document',\n * getInitialState: () => ({ documents: {} }),\n * // ...\n * })\n *\n * // Create resource-and-perspective-specific actions\n * export const fetchDocuments = bindActionByResourceAndPerspective(\n * documentStore,\n * ({instance, state}, documentId) => {\n * // This state is isolated to the specific document resource and perspective\n * // ...fetch logic...\n * }\n * )\n *\n * // Usage\n * fetchDocument(sanityInstance, 'doc123')\n * ```\n */\nexport const bindActionByResourceAndPerspective = createActionBinder<\n BoundPerspectiveKey,\n [DatasetHandle, ...unknown[]]\n>((instance, options): BoundPerspectiveKey => {\n const {resource, perspective} = options\n // Same trade-off as the resource fallback in `createResourceKey`: configured once on the\n // instance rather than passed to every call. Kept for the same reason.\n const utilizedPerspective = perspective ?? instance.config.perspective ?? 'drafts'\n let perspectiveKey: string\n if (isReleasePerspective(utilizedPerspective)) {\n perspectiveKey = utilizedPerspective.releaseName\n } else if (typeof utilizedPerspective === 'string') {\n perspectiveKey = utilizedPerspective\n } else {\n // \"StackablePerspective\", shouldn't be a common case, but just in case\n perspectiveKey = JSON.stringify(utilizedPerspective)\n }\n const sourceKey = createResourceKey(instance, resource)\n\n return {\n name: `${sourceKey.name}:${perspectiveKey}`,\n resource: sourceKey.resource,\n perspective: utilizedPerspective,\n }\n})\n\n/**\n * Binds an action to a global store that's shared across all Sanity instances\n *\n * @remarks\n * This creates actions that operate on state shared globally across all Sanity instances.\n * Use this for features like authentication where the state should be the same\n * regardless of which project or dataset is being used.\n *\n * @example\n * ```ts\n * // Define a store\n * const authStore = defineStore<AuthState>({\n * name: 'Auth',\n * getInitialState: () => ({\n * user: null,\n * isAuthenticated: false\n * }),\n * // ...\n * })\n *\n * // Create global actions\n * export const getCurrentUser = bindActionGlobally(\n * authStore,\n * ({state}) => state.get().user\n * )\n *\n * export const login = bindActionGlobally(\n * authStore,\n * ({state, instance}, credentials) => {\n * // Login logic that affects global state\n * // ...\n * }\n * )\n *\n * // Usage with any instance\n * getCurrentUser(sanityInstance)\n * ```\n */\nexport const bindActionGlobally = createActionBinder((..._rest) => ({name: 'global'}))\n","import {defer, distinctUntilChanged, finalize, map, Observable, shareReplay, skip} from 'rxjs'\n\nimport {type StoreAction} from './createActionBinder'\nimport {type SanityInstance} from './createSanityInstance'\nimport {type StoreContext} from './defineStore'\n\n/**\n * Represents a reactive state source that provides synchronized access to store data\n *\n * @remarks\n * Designed to work with React's useSyncExternalStore hook. Provides three ways to access data:\n * 1. `getCurrent()` for synchronous current value access\n * 2. `subscribe()` for imperative change notifications\n * 3. `observable` for reactive stream access\n *\n * @public\n */\nexport interface StateSource<T> {\n /**\n * Subscribes to state changes with optional callback\n * @param onStoreChanged - Called whenever relevant state changes occur\n * @returns Unsubscribe function to clean up the subscription\n */\n subscribe: (onStoreChanged?: () => void) => () => void\n\n /**\n * Gets the current derived state value\n *\n * @remarks\n * Safe to call without subscription. Will always return the latest value\n * based on the current store state and selector parameters.\n */\n getCurrent: () => T\n\n /**\n * Observable stream of state values\n *\n * @remarks\n * Shares a single underlying subscription between all observers. Emits:\n * - Immediately with current value on subscription\n * - On every relevant state change\n * - Errors if selector throws\n */\n observable: Observable<T>\n}\n\n/**\n * Context passed to selectors when deriving state\n *\n * @remarks\n * Provides access to both the current state value and the Sanity instance,\n * allowing selectors to use configuration values when computing derived state.\n * The context is memoized for each state object and instance combination\n * to optimize performance and prevent unnecessary recalculations.\n *\n * @example\n * ```ts\n * // Using both state and instance in a selector (psuedo example)\n * const getUserByProjectId = createStateSourceAction(\n * ({ state, instance }: SelectorContext<UsersState>, options?: ProjectHandle) => {\n * const allUsers = state.users\n * const projectId = options?.projectId ?? instance.config.projectId\n * return allUsers.filter(user => user.projectId === projectId)\n * }\n * )\n * ```\n */\nexport interface SelectorContext<TState> {\n /**\n * The current state object from the store\n */\n state: TState\n\n /**\n * The Sanity instance associated with this state\n */\n instance: SanityInstance\n}\n\n/**\n * Function type for selecting derived state from store state and parameters\n * @public\n */\nexport type Selector<TState, TParams extends unknown[], TReturn> = (\n context: SelectorContext<TState>,\n ...params: TParams\n) => TReturn\n\n/**\n * Configuration options for creating a state source action\n */\ninterface StateSourceOptions<TState, TParams extends unknown[], TReturn, TKey> {\n /**\n * Selector function that derives the desired value from store state\n *\n * @remarks\n * Will be called on every store change. Should be pure function.\n * Thrown errors will propagate to observable subscribers.\n */\n selector: Selector<TState, TParams, TReturn>\n\n /**\n * Optional setup/cleanup handler for subscriptions\n *\n * @param context - Store context containing state and instance\n * @param params - Action parameters provided during invocation\n * @returns Optional cleanup function called when subscription ends\n */\n onSubscribe?: (context: StoreContext<TState, TKey>, ...params: TParams) => void | (() => void)\n\n /**\n * Equality function to prevent unnecessary updates\n */\n isEqual?: (prev: TReturn, curr: TReturn) => boolean\n}\n\n/**\n * Creates a state source action that generates StateSource instances\n *\n * @remarks\n * The returned action can be bound to a store using createActionBinder.\n * When invoked, returns a StateSource that stays synchronized with the store.\n *\n * Key performance features:\n * - Memoizes selector contexts to prevent redundant object creation\n * - Only runs selectors when the underlying state changes\n *\n * For complex data transformations, consider using memoized selectors\n * (like those from Reselect) to prevent expensive recalculations.\n *\n * @example\n * ```ts\n * // Create a simple counter source\n * const getCount = createStateSourceAction(({state}: SelectorContext<CounterState>) => state.count)\n * ```\n *\n * @example\n * ```ts\n * // Create a parameterized source with setup/cleanup\n * const getItem = createStateSourceAction({\n * selector: ({state}, index: number) => state.items[index],\n * onSubscribe: (context, index) => {\n * trackItemSubscription(index)\n * return () => untrackItem(index)\n * }\n * })\n * ```\n *\n * @example\n * ```ts\n * // Binding a state source to a specific store\n * const documentStore = defineStore<DocumentState>({\n * name: 'Documents',\n * getInitialState: () => ({ documents: {} }),\n * // ...\n * })\n *\n * const getDocument = bindActionByResource(\n * documentStore,\n * createStateSourceAction(({state}, documentId: string) => state.documents[documentId])\n * )\n *\n * // Usage\n * const documentSource = getDocument(sanityInstance, 'doc123')\n * const doc = documentSource.getCurrent()\n * const subscription = documentSource.observable.subscribe(updatedDoc => {\n * console.log('Document changed:', updatedDoc)\n * })\n * ```\n */\nexport function createStateSourceAction<TState, TParams extends unknown[], TReturn, TKey = unknown>(\n options: Selector<TState, TParams, TReturn> | StateSourceOptions<TState, TParams, TReturn, TKey>,\n): StoreAction<TState, TParams, StateSource<TReturn>, TKey> {\n const selector = typeof options === 'function' ? options : options.selector\n const subscribeHandler = options && 'onSubscribe' in options ? options.onSubscribe : undefined\n const isEqual = options && 'isEqual' in options ? (options.isEqual ?? Object.is) : Object.is\n const selectorContextCache = new WeakMap<\n object,\n WeakMap<SanityInstance, SelectorContext<TState>>\n >()\n\n /**\n * The state source action implementation\n * @param context - Store context providing access to state and instance\n * @param params - Parameters provided when invoking the bound action\n */\n function stateSourceAction(context: StoreContext<TState, TKey>, ...params: TParams) {\n const {state, instance} = context\n\n const getCurrent = (currentState: TState) => {\n if (typeof currentState !== 'object' || currentState === null) {\n throw new Error(\n `Expected store state to be an object but got \"${typeof currentState}\" instead`,\n )\n }\n\n let instanceCache = selectorContextCache.get(currentState)\n if (!instanceCache) {\n instanceCache = new WeakMap<SanityInstance, SelectorContext<TState>>()\n selectorContextCache.set(currentState, instanceCache)\n }\n let selectorContext = instanceCache.get(instance)\n if (!selectorContext) {\n selectorContext = {state: currentState, instance}\n instanceCache.set(instance, selectorContext)\n }\n return selector(selectorContext, ...params)\n }\n\n // `state.observable` will emit the current value immediately and\n // hence we inherit the same behavior here.\n let values = state.observable.pipe(map(getCurrent), distinctUntilChanged(isEqual))\n\n if (subscribeHandler) {\n values = withSubscribeHook(values, () => subscribeHandler(context, ...params))\n }\n\n // Share but replay the latest value so every subscriber gets an\n // initial synchronous emission, matching `state.observable`. That keeps\n // `skip(1)` in `subscribe()` aligned with \"skip current snapshot\" rather than\n // silently eating the first real update after multicasting.\n const sharedValues = values.pipe(shareReplay({bufferSize: 1, refCount: true}))\n\n const subscribe = (onStoreChanged?: () => void) => {\n const subscription = sharedValues.pipe(skip(1)).subscribe({\n next: () => onStoreChanged?.(),\n // Propagate selector errors to both subscription types\n error: () => onStoreChanged?.(),\n })\n\n return () => {\n subscription.unsubscribe()\n }\n }\n\n return {\n getCurrent: () => getCurrent(state.get()),\n subscribe,\n observable: sharedValues,\n }\n }\n\n return stateSourceAction\n}\n\n/**\n * Creates a new Observable which wraps an existing Observable which will invoke\n * the function when a new subscriber appears.\n */\nfunction withSubscribeHook<T>(obs: Observable<T>, fn: () => void | (() => void)): Observable<T> {\n return defer(() => {\n const cleanup = fn()\n return cleanup ? obs.pipe(finalize(() => cleanup())) : obs\n })\n}\n","/**\n * Returns true when the input is a non-null object.\n *\n * @internal\n */\nexport function isObject(value: unknown): value is object {\n return typeof value === 'object' && value !== null\n}\n\nconst hasOwn = (value: object, key: PropertyKey) => Object.prototype.hasOwnProperty.call(value, key)\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (!isObject(value)) return false\n\n const prototype = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n}\n\n/**\n * Creates a shallow copy without the provided property.\n *\n * @internal\n */\nexport function omitProperty<T extends object, K extends keyof T>(\n value: T | null | undefined,\n key: K,\n): Omit<T, K> {\n if (!value) return {} as Omit<T, K>\n\n const {[key]: _omitted, ...rest} = value\n return rest\n}\n\n/**\n * Creates a shallow copy containing only the provided properties.\n *\n * @internal\n */\nexport function pickProperties<T extends object, K extends keyof T>(\n value: T,\n keys: readonly K[],\n): Pick<T, K> {\n const result = {} as Pick<T, K>\n\n for (const key of keys) {\n if (hasOwn(value, key)) {\n result[key] = value[key]\n }\n }\n\n return result\n}\n\nconst areSetsEqual = (left: Set<unknown>, right: Set<unknown>): boolean => {\n if (left.size !== right.size) return false\n\n const unmatched = [...right]\n\n outer: for (const leftValue of left) {\n for (let index = 0; index < unmatched.length; index++) {\n if (isDeepEqual(leftValue, unmatched[index])) {\n unmatched.splice(index, 1)\n continue outer\n }\n }\n\n return false\n }\n\n return unmatched.length === 0\n}\n\nconst areMapsEqual = (left: Map<unknown, unknown>, right: Map<unknown, unknown>): boolean => {\n if (left.size !== right.size) return false\n\n const unmatched = [...right.entries()]\n\n outer: for (const [leftKey, leftValue] of left) {\n for (let index = 0; index < unmatched.length; index++) {\n const [rightKey, rightValue] = unmatched[index]\n\n if (isDeepEqual(leftKey, rightKey) && isDeepEqual(leftValue, rightValue)) {\n unmatched.splice(index, 1)\n continue outer\n }\n }\n\n return false\n }\n\n return unmatched.length === 0\n}\n\n/**\n * Compares values deeply across the plain object, array, map, and set shapes used by the SDK.\n * This helper is intended for acyclic SDK data structures and does not guard against circular\n * references.\n *\n * @internal\n */\nexport function isDeepEqual<T>(left: T, right: T): boolean {\n if (Object.is(left, right)) return true\n\n if (!isObject(left) || !isObject(right)) return false\n\n if (left instanceof Date && right instanceof Date) {\n return left.getTime() === right.getTime()\n }\n\n if (left instanceof RegExp && right instanceof RegExp) {\n return left.source === right.source && left.flags === right.flags\n }\n\n if (left instanceof Set && right instanceof Set) {\n return areSetsEqual(left, right)\n }\n\n if (left instanceof Map && right instanceof Map) {\n return areMapsEqual(left, right)\n }\n\n if (Array.isArray(left) || Array.isArray(right)) {\n if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false\n\n return left.every((value, index) => isDeepEqual(value, right[index]))\n }\n\n if (!isPlainObject(left) || !isPlainObject(right)) return false\n\n const leftKeys = Object.keys(left)\n const rightKeys = Object.keys(right)\n\n if (leftKeys.length !== rightKeys.length) return false\n\n for (const key of leftKeys) {\n if (!hasOwn(right, key) || !isDeepEqual(left[key], right[key])) {\n return false\n }\n }\n\n return true\n}\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
- import { a as defineStore, c as isDatasetResource, i as bindActionGlobally, n as bindActionByResource, o as isReleasePerspective, t as createStateSourceAction } from "./createStateSourceAction-BOKtqFNm.js";
2
- import { r as omitProperty } from "./object-CxXlSVg7.js";
3
- import { n as getClient, r as getClientState } from "./clientStore-BtE2-q2i.js";
1
+ import { n as getClient, r as getClientState } from "./clientStore-gUALQ0qW.js";
2
+ import { a as createStateSourceAction, c as bindActionGlobally, d as isReleasePerspective, l as defineStore, o as bindActionByResource, p as isDatasetResource, r as omitProperty, u as getEnv } from "./object-BwynGPRZ.js";
4
3
  import { n as setCleanupTimeout, t as setCleanupInterval } from "./setCleanupTimeout-BiM6q1KF.js";
5
4
  import { ConnectionFailedError, CorsOriginError, DisconnectError } from "@sanity/client";
6
5
  import { BehaviorSubject, EMPTY, NEVER, Observable, Subscription, catchError, combineLatest, defer, distinctUntilChanged, filter, first, firstValueFrom, groupBy, map, mergeMap, of, pairwise, race, retry, share, startWith, switchMap, take, tap } from "rxjs";
@@ -9,8 +8,41 @@ import { DocumentId, getPublishedId } from "@sanity/id-utils";
9
8
  import { stringifyPath } from "@sanity/json-match";
10
9
  import "groq";
11
10
  import { createSelector } from "reselect";
12
- function insecureRandomId() {
13
- return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
11
+ /**
12
+ * Generates a random ID of the given length from the alphabet `[a-zA-Z0-9]`, the same shape
13
+ * `@sanity/client` and Sanity Studio use for short IDs such as release IDs.
14
+ *
15
+ * Ported from `@sanity/client`'s `generateReleaseId`, which uses rejection sampling to keep
16
+ * the output unbiased. Uses `crypto.getRandomValues`, which unlike `crypto.randomUUID` is
17
+ * also available on insecure origins (plain http).
18
+ *
19
+ * @internal
20
+ */
21
+ function randomId(length = 8) {
22
+ let id = "";
23
+ for (; id.length < length;) {
24
+ let bytes = crypto.getRandomValues(new Uint8Array(length - id.length));
25
+ for (let byte of bytes) {
26
+ let index = byte & 63;
27
+ index < 62 && (id += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(index));
28
+ }
29
+ }
30
+ return id;
31
+ }
32
+ /**
33
+ * Generates a random v4 UUID.
34
+ *
35
+ * Prefers the native `crypto.randomUUID`, which is only available in secure contexts
36
+ * (https, localhost). Falls back to deriving the UUID from `crypto.getRandomValues`,
37
+ * which has no such restriction, so ID generation also works when an app is served over
38
+ * plain http, e.g. when testing from a phone on a local network.
39
+ *
40
+ * @internal
41
+ */
42
+ function randomUuid() {
43
+ if (typeof crypto.randomUUID == "function") return crypto.randomUUID();
44
+ let bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16)), hex = Array.from(bytes, (byte, index) => (index === 6 && (byte = byte & 15 | 64), index === 8 && (byte = byte & 63 | 128), byte.toString(16).padStart(2, "0"))).join("");
45
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
14
46
  }
15
47
  const definitions = /* @__PURE__ */ new Map(), inflight = /* @__PURE__ */ new Map(), gcTimers = /* @__PURE__ */ new Map(), intervalTimers = /* @__PURE__ */ new Map(), snapshotCache = /* @__PURE__ */ new WeakMap(), PENDING_SNAPSHOT = {
16
48
  status: "pending",
@@ -107,7 +139,7 @@ const definitions = /* @__PURE__ */ new Map(), inflight = /* @__PURE__ */ new Ma
107
139
  resolve,
108
140
  reject,
109
141
  startVersion
110
- }), sub.add(def.fetch(instance)(...params).subscribe({
142
+ }), sub.add(def.fetch(instance)(...params).pipe(take(1)).subscribe({
111
143
  next: (data) => {
112
144
  let current = state.get().entries[key];
113
145
  if (current && current.version !== startVersion) {
@@ -340,7 +372,7 @@ function isMissingOrForbidden(error) {
340
372
  }
341
373
  function requestAddonDataset(client, { projectId, dataset }) {
342
374
  return client.observable.request({
343
- uri: `/projects/${projectId}/datasets?datasetProfile=comments&addonFor=${dataset}`,
375
+ url: `/projects/${projectId}/datasets?datasetProfile=comments&addonFor=${dataset}`,
344
376
  tag: "comments.addon-dataset.list"
345
377
  }).pipe(map((datasets) => datasets?.[0]?.name));
346
378
  }
@@ -388,7 +420,7 @@ const addonDatasetStore = defineStore({
388
420
  projectId: resource.projectId,
389
421
  useProjectHostname: !0
390
422
  }).request({
391
- uri: `/comments/${resource.dataset}/setup`,
423
+ url: `/comments/${resource.dataset}/setup`,
392
424
  method: "POST",
393
425
  tag: "comments.addon-dataset.setup"
394
426
  });
@@ -936,7 +968,7 @@ function selectCommentThreads(context, options) {
936
968
  const getCommentsState = bindActionByResource(commentsStore, createStateSourceAction({
937
969
  selector: selectComments,
938
970
  onSubscribe: ({ state, instance }, options) => {
939
- let key = getCommentsKey(toCommentsKeyParts(instance, options)), subscriptionId = insecureRandomId();
971
+ let key = getCommentsKey(toCommentsKeyParts(instance, options)), subscriptionId = randomId(16);
940
972
  return state.set("addSubscriber", addSubscriber$1(key, subscriptionId)), () => {
941
973
  setCleanupTimeout(() => state.set("removeSubscriber", removeSubscriber$1(key, subscriptionId)), COMMENTS_STATE_CLEAR_DELAY);
942
974
  };
@@ -944,14 +976,14 @@ const getCommentsState = bindActionByResource(commentsStore, createStateSourceAc
944
976
  })), getCommentThreadsState = bindActionByResource(commentsStore, createStateSourceAction({
945
977
  selector: selectCommentThreads,
946
978
  onSubscribe: ({ state, instance }, options) => {
947
- let key = getCommentsKey(toCommentsKeyParts(instance, options)), subscriptionId = insecureRandomId();
979
+ let key = getCommentsKey(toCommentsKeyParts(instance, options)), subscriptionId = randomId(16);
948
980
  return state.set("addSubscriber", addSubscriber$1(key, subscriptionId)), () => {
949
981
  setCleanupTimeout(() => state.set("removeSubscriber", removeSubscriber$1(key, subscriptionId)), COMMENTS_STATE_CLEAR_DELAY);
950
982
  };
951
983
  }
952
984
  })), resolveComments = bindActionByResource(commentsStore, ({ state, instance }, { signal, ...options }) => resolveList(state, instance, options, signal, getCommentsState)), resolveCommentThreads = bindActionByResource(commentsStore, ({ state, instance }, { signal, ...options }) => resolveList(state, instance, options, signal, getCommentThreadsState));
953
985
  function resolveList(state, instance, options, signal, getState) {
954
- let key = getCommentsKey(toCommentsKeyParts(instance, options)), { getCurrent } = getState(instance, options), subscriptionId = insecureRandomId();
986
+ let key = getCommentsKey(toCommentsKeyParts(instance, options)), { getCurrent } = getState(instance, options), subscriptionId = randomId(16);
955
987
  state.set("addSubscriber", addSubscriber$1(key, subscriptionId));
956
988
  let release = () => state.set("removeSubscriber", removeSubscriber$1(key, subscriptionId)), aborted$ = signal ? new Observable((observer) => {
957
989
  let listener = () => {
@@ -1312,7 +1344,7 @@ const _getQueryState = bindActionByResource(queryStore, createStateSourceAction(
1312
1344
  return queryState?.result;
1313
1345
  },
1314
1346
  onSubscribe: ({ state, instance }, options) => {
1315
- let subscriptionId = insecureRandomId(), key = getQueryKey(instance, options);
1347
+ let subscriptionId = randomId(16), key = getQueryKey(instance, options);
1316
1348
  return state.set("addSubscriber", addSubscriber(key, subscriptionId)), () => {
1317
1349
  setCleanupTimeout(() => state.set("removeSubscriber", removeSubscriber(key, subscriptionId)), QUERY_STATE_CLEAR_DELAY);
1318
1350
  };
@@ -1323,7 +1355,7 @@ function resolveQuery(...args) {
1323
1355
  return _resolveQuery(...args);
1324
1356
  }
1325
1357
  const _resolveQuery = bindActionByResource(queryStore, ({ state, instance }, { signal, ...options }) => {
1326
- let normalized = normalizeOptionsWithPerspective(instance, options), { getCurrent } = getQueryState(instance, normalized), key = getQueryKey(instance, normalized), subscriptionId = insecureRandomId();
1358
+ let normalized = normalizeOptionsWithPerspective(instance, options), { getCurrent } = getQueryState(instance, normalized), key = getQueryKey(instance, normalized), subscriptionId = randomId(16);
1327
1359
  state.set("addSubscriber", addSubscriber(key, subscriptionId));
1328
1360
  let aborted$ = signal ? new Observable((observer) => {
1329
1361
  let cleanup = () => {
@@ -1340,7 +1372,7 @@ const _resolveQuery = bindActionByResource(queryStore, ({ state, instance }, { s
1340
1372
  }, QUERY_STATE_CLEAR_DELAY);
1341
1373
  };
1342
1374
  return promise.then(releaseSubscriber, releaseSubscriber), promise;
1343
- });
1344
- export { getCommentsKey as A, getAddonDatasetState as B, parseCommentsOptionsKey as C, addComment as D, toCommentsKeyParts as E, setCommentCreateError as F, insecureRandomId as G, COMMENTS_API_VERSION as H, setPendingTransaction as I, normalizeComment as L, removeCommentById as M, restoreComments as N, applyCommentUpdate as O, rollbackCommentUpdate as P, toCommentFieldPath as R, getCommentsState as S, resolveComments as T, defineFetcher as U, provisionAddonDataset as V, defineMutation as W, PROJECT_API_VERSION as _, getPerspectiveState as a, getCommentThreadsState as b, addSubscription as c, initializeRequest as d, parseUsersKey as f, updateLastLoadMoreRequest as g, setUsersError as h, resolveQuery as i, receiveComment as j, clearPendingTransaction as k, cancelRequest as l, setUsersData as m, getQueryState as n, getActiveReleasesState as o, removeSubscription as p, parseQueryKey as r, getAllReleasesState as s, getQueryKey as t, getUsersKey as u, USERS_STATE_CLEAR_DELAY as v, resolveCommentThreads as w, getCommentsOptionsKey as x, commentsStore as y, assertDatasetResource as z };
1375
+ }), CORE_SDK_VERSION = getEnv("PKG_VERSION") || "3.1.0-development";
1376
+ export { clearPendingTransaction as A, assertDatasetResource as B, getCommentsState as C, toCommentsKeyParts as D, resolveComments as E, rollbackCommentUpdate as F, defineMutation as G, provisionAddonDataset as H, setCommentCreateError as I, randomId as K, setPendingTransaction as L, receiveComment as M, removeCommentById as N, addComment as O, restoreComments as P, normalizeComment as R, getCommentsOptionsKey as S, resolveCommentThreads as T, COMMENTS_API_VERSION as U, getAddonDatasetState as V, defineFetcher as W, updateLastLoadMoreRequest as _, resolveQuery as a, commentsStore as b, getAllReleasesState as c, getUsersKey as d, initializeRequest as f, setUsersError as g, setUsersData as h, parseQueryKey as i, getCommentsKey as j, applyCommentUpdate as k, addSubscription as l, removeSubscription as m, getQueryKey as n, getPerspectiveState as o, parseUsersKey as p, randomUuid as q, getQueryState as r, getActiveReleasesState as s, CORE_SDK_VERSION as t, cancelRequest as u, PROJECT_API_VERSION as v, parseCommentsOptionsKey as w, getCommentThreadsState as x, USERS_STATE_CLEAR_DELAY as y, toCommentFieldPath as z };
1345
1377
 
1346
- //# sourceMappingURL=queryStore-DPf9sN3V.js.map
1378
+ //# sourceMappingURL=version-C90rNWaX.js.map