{"version":3,"file":"userStorage.mjs","sources":["../../../src/utils/userStorage.tsx"],"sourcesContent":["import { get } from 'lodash';\nimport { useRef } from 'react';\nimport { lastValueFrom } from 'rxjs';\n\nimport { usePluginContext, type UserStorage as UserStorageType, store } from '@grafana/data';\n\nimport { config } from '../config';\nimport { type BackendSrvRequest, getBackendSrv } from '../services';\n\nconst baseURL = `/apis/userstorage.grafana.app/v0alpha1/namespaces/${config.namespace}/user-storage`;\n\n// Global cache for user storage initialization requests\n// Cache key: resourceName (e.g., \"plugin-id:user-uid\")\n// Cache value: Promise<UserStorageSpec | null> | UserStorageSpec | null\nconst storageCache = new Map<string, Promise<UserStorageSpec | null> | UserStorageSpec | null>();\n\n// Lock map to serialize operations per resourceName\n// Cache key: resourceName\n// Cache value: Promise that resolves when the lock is available\nconst operationLocks = new Map<string, Promise<void>>();\n\n/**\n * Clears the global storage cache. Used for testing purposes.\n * @internal\n */\nexport function _clearStorageCache() {\n  if (process.env.NODE_ENV !== 'test') {\n    throw new Error('clearStorageCache() function can only be called from tests.');\n  }\n  storageCache.clear();\n  operationLocks.clear();\n}\n\ninterface RequestOptions extends BackendSrvRequest {\n  manageError?: (err: unknown) => { error: unknown };\n  showErrorAlert?: boolean;\n\n  // rtk codegen sets this\n  body?: BackendSrvRequest['data'];\n}\n\ntype UserStorageSpec = {\n  data: { [key: string]: string };\n};\n\nasync function apiRequest<T>(requestOptions: RequestOptions) {\n  try {\n    const { data: responseData, ...meta } = await lastValueFrom(\n      getBackendSrv().fetch<T>({\n        ...requestOptions,\n        url: baseURL + requestOptions.url,\n        data: requestOptions.body,\n        showErrorAlert: false,\n      })\n    );\n    return { data: responseData, meta };\n  } catch (error) {\n    return requestOptions.manageError ? requestOptions.manageError(error) : { error };\n  }\n}\n\n/**\n * A class for interacting with the backend user storage.\n * Exposed internally only to avoid misuse (wrong service name)..\n */\nexport class UserStorage implements UserStorageType {\n  private service: string;\n  private resourceName: string;\n  private userUID: string;\n  private canUseUserStorage: boolean;\n\n  constructor(service: string) {\n    this.service = service;\n    this.userUID = config.bootData.user.uid === '' ? config.bootData.user.id.toString() : config.bootData.user.uid;\n    this.resourceName = `${service}:${this.userUID}`;\n    this.canUseUserStorage = config.bootData.user.isSignedIn;\n  }\n\n  /**\n   * Acquires a lock for this resourceName to serialize operations.\n   * Returns a function to release the lock when done.\n   */\n  private async acquireLock(): Promise<() => void> {\n    // Wait for any existing lock\n    let lockPromise = operationLocks.get(this.resourceName);\n    if (lockPromise) {\n      await lockPromise;\n    }\n\n    // Create a new lock promise that will be resolved when this operation completes\n    let resolveLock: (() => void) | undefined;\n    const newLockPromise = new Promise<void>((resolve) => {\n      resolveLock = resolve;\n    });\n    operationLocks.set(this.resourceName, newLockPromise);\n\n    // Return a function to release the lock\n    return () => {\n      if (resolveLock) {\n        resolveLock();\n      }\n      // Remove lock if it's still the current one (in case another operation started)\n      if (operationLocks.get(this.resourceName) === newLockPromise) {\n        operationLocks.delete(this.resourceName);\n      }\n    };\n  }\n\n  private async init(): Promise<unknown> {\n    // Check global cache first\n    const cached = storageCache.get(this.resourceName);\n    if (cached !== undefined) {\n      if (cached instanceof Promise) {\n        // Cache has a promise, await it\n        try {\n          await cached;\n          return;\n        } catch (error) {\n          // Promise rejected, return error to match original behavior\n          return error;\n        }\n      } else {\n        // Cache has a resolved result, already initialized\n        return;\n      }\n    }\n\n    // No cache entry, create the request promise and cache it atomically\n    // Use a double-check pattern to handle race conditions\n    let requestPromise = storageCache.get(this.resourceName);\n    if (requestPromise instanceof Promise) {\n      // Another instance created the promise between our check and now, use it\n      try {\n        await requestPromise;\n        return;\n      } catch (error) {\n        return error;\n      }\n    }\n\n    // Create new promise\n    requestPromise = (async (): Promise<UserStorageSpec | null> => {\n      const userStorage = await apiRequest<{ spec: UserStorageSpec }>({\n        url: `/${this.resourceName}`,\n        method: 'GET',\n        manageError: (error) => {\n          if (get(error, 'status') === 404) {\n            return { error: null };\n          }\n          return { error };\n        },\n      });\n      if ('error' in userStorage) {\n        if (userStorage.error === null) {\n          // 404 - storage doesn't exist\n          return null;\n        }\n        // Other error, throw so it can be caught and returned\n        throw userStorage.error;\n      }\n      return userStorage.data.spec;\n    })();\n\n    // Atomically set the promise only if cache is still empty\n    const existing = storageCache.get(this.resourceName);\n    if (existing === undefined) {\n      storageCache.set(this.resourceName, requestPromise);\n    } else if (existing instanceof Promise) {\n      // Another instance set a promise, use it instead\n      requestPromise = existing;\n    } else {\n      // Another instance already resolved, we're done\n      return;\n    }\n\n    try {\n      const result = await requestPromise;\n      // Replace promise with resolved result in cache\n      storageCache.set(this.resourceName, result);\n    } catch (error) {\n      // Remove failed promise from cache so it can be retried\n      storageCache.delete(this.resourceName);\n      return error;\n    }\n    return;\n  }\n\n  async getItem(key: string): Promise<string | null> {\n    if (!this.canUseUserStorage) {\n      // Fallback to localStorage\n      return store.get(`${this.resourceName}:${key}`) ?? null;\n    }\n\n    // Acquire lock to serialize operations\n    const releaseLock = await this.acquireLock();\n    try {\n      // Ensure storage is initialized\n      await this.init();\n      const storageSpec = storageCache.get(this.resourceName);\n      if (!storageSpec) {\n        // Storage doesn't exist or still loading, fallback to localStorage\n        return store.get(`${this.resourceName}:${key}`) ?? null;\n      }\n      if (storageSpec instanceof Promise) {\n        const result = await storageSpec;\n        return result?.data[key] ?? null;\n      }\n      return storageSpec.data[key];\n    } finally {\n      releaseLock();\n    }\n  }\n\n  async setItem(key: string, value: string): Promise<void> {\n    if (!this.canUseUserStorage) {\n      // Fallback to localStorage\n      store.set(`${this.resourceName}:${key}`, value);\n      return;\n    }\n\n    // Acquire lock to serialize operations\n    const releaseLock = await this.acquireLock();\n    try {\n      const newData = { data: { [key]: value } };\n      // Ensure storage is initialized\n      const error = await this.init();\n      if (error) {\n        // Fallback to localStorage\n        store.set(`${this.resourceName}:${key}`, value);\n        return;\n      }\n\n      let storageSpec = storageCache.get(this.resourceName);\n      if (storageSpec instanceof Promise) {\n        storageSpec = await storageSpec;\n      }\n      if (!storageSpec) {\n        // No user storage found, create a new one\n        const createResult = await apiRequest<UserStorageSpec>({\n          url: `/`,\n          method: 'POST',\n          body: {\n            metadata: { name: this.resourceName, labels: { user: this.userUID, service: this.service } },\n            spec: newData,\n          },\n          manageError: (error) => {\n            // Fallback to localStorage\n            store.set(`${this.resourceName}:${key}`, value);\n            return { error };\n          },\n        });\n        if ('error' in createResult && createResult.error) {\n          // Error occurred, fallback already handled in manageError\n          return;\n        }\n        // Update global cache with the new storage\n        storageCache.set(this.resourceName, newData);\n        return;\n      }\n\n      // Clone the storage spec to avoid mutating the cached object directly\n      // This prevents race conditions where multiple setItem calls modify the same object\n      const updatedSpec: UserStorageSpec = {\n        data: { ...storageSpec.data, [key]: value },\n      };\n\n      const updateResult = await apiRequest<UserStorageSpec>({\n        headers: { 'Content-Type': 'application/merge-patch+json' },\n        url: `/${this.resourceName}`,\n        method: 'PATCH',\n        body: { spec: newData },\n        manageError: (error) => {\n          // Fallback to localStorage\n          store.set(`${this.resourceName}:${key}`, value);\n          return { error };\n        },\n      });\n      if ('error' in updateResult && updateResult.error) {\n        // Error occurred, fallback already handled in manageError\n        return;\n      }\n      // Update global cache with the modified storage (using cloned object)\n      storageCache.set(this.resourceName, updatedSpec);\n    } finally {\n      releaseLock();\n    }\n  }\n}\n\n// This is a type alias to avoid breaking changes\nexport interface PluginUserStorage extends UserStorageType {}\n\n/**\n * A hook for interacting with the backend user storage (or local storage if not enabled).\n * @returns An scoped object for a plugin and a user with getItem and setItem functions.\n * @alpha Experimental\n */\nexport function usePluginUserStorage(): PluginUserStorage {\n  const context = usePluginContext();\n  if (!context) {\n    throw new Error(`No PluginContext found. The usePluginUserStorage() hook can only be used from a plugin.`);\n  }\n  return new UserStorage(context?.meta.id);\n}\n\n/**\n * Internal Grafana-core only interface for constructing a UserStorage instance in a\n * react component.\n */\nexport function useUserStorage(service: string): UserStorageType {\n  const ref = useRef<[service: string, UserStorageType] | undefined>(undefined);\n\n  if (!ref.current || ref.current[0] !== service) {\n    ref.current = [service, new UserStorage(service)];\n  }\n\n  return ref.current[1];\n}\n"],"names":["error"],"mappings":"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"}