{"version":3,"file":"userStorage.mjs","sources":["../../../src/utils/userStorage.tsx"],"sourcesContent":["import { get } from 'lodash';\nimport { lastValueFrom } from 'rxjs';\n\nimport { usePluginContext, type UserStorage as UserStorageType } from '@grafana/data';\n\nimport { config } from '../config';\nimport { BackendSrvRequest, getBackendSrv } from '../services';\n\nconst baseURL = `/apis/userstorage.grafana.app/v0alpha1/namespaces/${config.namespace}/user-storage`;\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\nexport type 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  private storageSpec: UserStorageSpec | null | undefined;\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  private async init() {\n    if (this.storageSpec !== undefined) {\n      return;\n    }\n    const userStorage = await apiRequest<{ spec: UserStorageSpec }>({\n      url: `/${this.resourceName}`,\n      method: 'GET',\n      manageError: (error) => {\n        if (get(error, 'status') === 404) {\n          this.storageSpec = null;\n          return { error: null };\n        }\n        return { error };\n      },\n    });\n    if ('error' in userStorage) {\n      return userStorage.error;\n    }\n    this.storageSpec = userStorage.data.spec;\n    return;\n  }\n\n  async getItem(key: string): Promise<string | null> {\n    if (!this.canUseUserStorage) {\n      // Fallback to localStorage\n      return localStorage.getItem(`${this.resourceName}:${key}`);\n    }\n    // Ensure this.storageSpec is initialized\n    await this.init();\n    if (!this.storageSpec) {\n      // Also, fallback to localStorage for backward compatibility\n      return localStorage.getItem(`${this.resourceName}:${key}`);\n    }\n    return this.storageSpec.data[key];\n  }\n\n  async setItem(key: string, value: string): Promise<void> {\n    if (!this.canUseUserStorage) {\n      // Fallback to localStorage\n      localStorage.setItem(`${this.resourceName}:${key}`, value);\n      return;\n    }\n\n    const newData = { data: { [key]: value } };\n    // Ensure this.storageSpec is initialized\n    const error = await this.init();\n    if (error) {\n      // Fallback to localStorage\n      localStorage.setItem(`${this.resourceName}:${key}`, value);\n      return;\n    }\n\n    if (!this.storageSpec) {\n      // No user storage found, create a new one\n      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          localStorage.setItem(`${this.resourceName}:${key}`, value);\n          return { error };\n        },\n      });\n      this.storageSpec = newData;\n      return;\n    }\n\n    // Update existing user storage\n    this.storageSpec.data[key] = value;\n    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        localStorage.setItem(`${this.resourceName}:${key}`, value);\n        return { error };\n      },\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"],"names":["error"],"mappings":"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"}