{"mappings":"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","sources":["index.ts","src/index.ts","src/client.ts","client.ts","src/utilities/index.ts"],"sourcesContent":[null,"export {HollowClient} from './client';\nexport type {HollowClientOptions} from './client';\n","import {getToken} from './utilities';\n\n/**\n * To authenticate yourself, you need to provide the following:\n *\n * - `apiKey` belonging to your team.\n * - `db` database name to connect to.\n *\n * To create a new API key or a database, go to <https://developer.hollowdb.xyz/>\n */\nexport type HollowClientOptions = {\n  apiKey: string;\n  db: string;\n  region?: string;\n  provider?: string;\n};\n\ntype BlockchainOption = {\n  /**\n   * Specify whether to store the value on blockchain (Arweave).\n   *\n   * If `undefined`, it defaults to storing the value on blockchain.\n   */\n  blockchain?: 'arweave' | 'none';\n};\n\ntype ExpireOption = {\n  /** Specify an expiration time (seconds) for your data. */\n  expire?: number;\n};\n\n/**\n * **[HollowDB Client](https://docs.hollowdb.xyz/hollowdb/hollowdb-as-a-service#hollowdb-client)**\n *\n * HollowDB client provides a very simple interface, abstracting everything behind\n * the scenes. Create a new client with `new` static function:\n *\n * ```ts\n * const client = await HollowClient.new({\n *   apiKey: 'your-api-key',\n *   db: 'your-database-name',\n * });\n * ```\n *\n *\n * You can do the 4 basic CRUD operations as shown below:\n *\n * ```ts\n * await client.get(KEY);\n * await client.put(KEY, VALUE);\n * await client.update(KEY, VALUE);\n * await client.remove(KEY);\n * ```\n *\n * You can also do a multi-get:\n *\n * ```ts\n * await client.getMulti([KEY1, KEY2, ...]);\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class HollowClient<T = any> {\n  protected readonly apiKey: string;\n  protected readonly db: string;\n  protected authToken: string;\n  protected readonly apiVersion = 'v0';\n\n  protected BASE_URL: string;\n\n  // auth token is retrieved by the client code, so it is not provided within `opt`\n  private constructor(opt: HollowClientOptions, authToken: string) {\n    this.apiKey = opt.apiKey;\n    this.authToken = authToken;\n    this.db = opt.db;\n\n    if (!opt.region) opt.region = 'eu-central-1';\n    if (!opt.provider) opt.provider = 'aws';\n\n    this.BASE_URL = `https://${opt.provider}-${opt.region}.hollowdb.xyz/db/${this.apiVersion}`;\n    /** Base API url. */\n  }\n\n  /**\n   * Creates & authenticates a HollowDB client.\n   *\n   * ```ts\n   * type ValueType = {foo: number, bar: string};\n   *\n   * client = await HollowClient.new<ValueType>({\n   *   apiKey: 'your-api-key',\n   *   db: 'your-database-name',\n   * });\n   * ```\n   *\n   * You can provide a value type to the function to make all functions treat that type\n   * as the value type for your key-value database.\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  static async new<T = any>(\n    options: HollowClientOptions\n  ): Promise<HollowClient<T>> {\n    const authToken = await getToken(options.db, options.apiKey);\n    return new HollowClient<T>(options, authToken);\n  }\n\n  /**\n   * **Returns the value at the given key.**\n   *\n   * This operation does not require proofs.\n   *\n   * If the key does not exist, `null` will be returned.\n   */\n  public async get(key: string): Promise<T | null> {\n    const encodedKey = encodeURIComponent(key);\n    const response = await this.fetch<{result: T | null}>(\n      `${this.BASE_URL}/get/${encodedKey}`,\n      'GET'\n    );\n\n    if (!response.data) {\n      throw new Error('Expected data in response.');\n    }\n\n    return response.data.result;\n  }\n\n  /**\n   * **Returns the value at the given keys.**\n   *\n   * This operation does not require proofs.\n   *\n   * The returned array is an array of values where `value[i]` is\n   * belongs to `key[i]`. If a key does not exist, `null` is returned\n   * for that key.\n   */\n  public async getMulti(keys: string[]): Promise<(T | null)[]> {\n    const response = await this.fetch<{result: (T | null)[]}>(\n      `${this.BASE_URL}/mget`,\n      'POST',\n      JSON.stringify({keys})\n    );\n\n    return response.data.result;\n  }\n\n  /**\n   * **Puts a value at the given key.**\n   *\n   * The target key must be empty, i.e. this is not an upsert operation.\n   *\n   * This operation does not require proofs even if zero-knowledge is enabled.\n   */\n  public async put(\n    key: string,\n    value: T,\n    options?: ExpireOption\n  ): Promise<void>;\n  public async put(\n    key: string,\n    value: T,\n    options?: BlockchainOption\n  ): Promise<void>;\n  public async put(\n    key: string,\n    value: T,\n    options?: ExpireOption | BlockchainOption\n  ): Promise<void> {\n    await this.fetch(\n      `${this.BASE_URL}/put`,\n      'POST',\n      JSON.stringify({key, value, options})\n    );\n  }\n\n  /**\n   * **Puts an array of key-value pairs.**\n   *\n   * The target keys must be empty, i.e. this is not an upsert operation.\n   *\n   * This operation does not require proofs even if zero-knowledge is enabled.\n   *\n   * Returns an array of booleans that indicate whether each key-value pair has\n   * been succesfully put or not.\n   *\n   */\n  public async putMulti(\n    pairs: {key: string; value: T; options?: ExpireOption}[]\n  ): Promise<boolean[]>;\n  public async putMulti(\n    pairs: {key: string; value: T; options?: BlockchainOption}[]\n  ): Promise<boolean[]>;\n  public async putMulti(\n    pairs: {key: string; value: T; options?: BlockchainOption | ExpireOption}[]\n  ): Promise<boolean[]> {\n    const response = await this.fetch<{result: boolean[]}>(\n      `${this.BASE_URL}/mput`,\n      'POST',\n      JSON.stringify({pairs})\n    );\n\n    return response.data.result;\n  }\n\n  /** **Updates a value at the given key.**\n   *\n   * A zero-knowledge proof is optionally provided, which the service\n   * expects if the connected database has proofs enabled.\n   */\n  public async update(\n    key: string,\n    value: T,\n    proof?: object,\n    options?: BlockchainOption\n  ): Promise<void>;\n  public async update(\n    key: string,\n    value: T,\n    proof?: object,\n    options?: ExpireOption\n  ): Promise<void>;\n  public async update(\n    key: string,\n    value: T,\n    proof?: object,\n    options?: BlockchainOption | ExpireOption\n  ) {\n    await this.fetch(\n      `${this.BASE_URL}/update`,\n      'POST',\n      JSON.stringify({\n        key,\n        value,\n        proof,\n        options,\n      })\n    );\n  }\n\n  /** **Removes a value at the given key.**\n   *\n   * Subsequent `get` calls to this key shall return `null`.\n   *\n   * A zero-knowledge proof is optionally provided, which the service\n   * expects if the connected database has proofs enabled.\n   */\n  public async remove(key: string, proof?: object, options?: BlockchainOption) {\n    await this.fetch(\n      `${this.BASE_URL}/remove`,\n      'POST',\n      JSON.stringify({\n        key,\n        proof,\n        options,\n      })\n    );\n  }\n\n  /** Fetch utility for internal use. */\n  private async fetch<Data = undefined>(\n    url: string,\n    method: 'GET' | 'POST',\n    body?: BodyInit\n  ): Promise<{\n    message: string;\n    data: Data;\n    newBearer?: string;\n  }> {\n    const init: RequestInit = {\n      headers: {\n        'Content-Type': 'application/json',\n        'x-api-key': this.apiKey,\n        authorization: `Bearer ${this.authToken}`,\n      },\n      method,\n    };\n    if (body) init.body = body;\n\n    const response = await fetch(url, init);\n    const json = await response.json();\n\n    if (response.status === 200) {\n      // new bearer has been created due to expiration of previous bearer\n      if (json.newBearer !== undefined) {\n        this.authToken = json.newBearer;\n      }\n      return json;\n    } else if (json.message === 'token expired') {\n      // token has expired, client must initiate the new token request\n      this.authToken = await getToken(this.db, this.apiKey);\n      return json;\n    }\n\n    throw new Error(`${url} got status ${response.status}: ${json.message}`);\n  }\n}\n",null,"/**\n * Given a database name `db` and an api-key `apiKey`, fetches the\n * bearer token to be used in header as `authorization: \"Bearer ${token}\"`.\n *\n * If `db` or `apiKey` is invalid, throws an error.\n */\nexport async function getToken(db: string, apiKey: string): Promise<string> {\n  const url = `https://auth.firstbatch.xyz/hollow/create_bearer?db=${db}`;\n  const response = await fetch(url, {\n    method: 'GET',\n    headers: {\n      'Content-Type': 'application/json',\n      'x-api-key': apiKey,\n    },\n  });\n\n  const authResponse = (await response.json()) as {\n    message?: string;\n    bearerToken?: string;\n  };\n  if (!response.ok) {\n    throw new Error(\n      `${url} got status ${response.status}: ${authResponse.message}`\n    );\n  }\n\n  if (!authResponse.bearerToken) {\n    throw new Error('Server did not provide a bearer token.');\n  }\n\n  return authResponse.bearerToken;\n}\n"],"names":[],"version":3,"file":"index.mjs.map","sourceRoot":"../"}