{"version":3,"sources":["../../../src/classes/client/index.ts"],"sourcesContent":["import type { Types } from \"../..\";\nimport type { Events, Game as GameTypes } from \"../../types\";\nimport { API, CONSTANTS, parseToken } from \"../../utils\";\nimport { Game } from \"../game\";\nimport { Ribbon } from \"../ribbon\";\nimport { Room } from \"../room\";\nimport { Social } from \"../social\";\nimport { ClientUtils } from \"../utils\";\nimport type { ClientOptions, ClientUser } from \"./types\";\n\nexport type * from \"./types\";\n\nexport class Client {\n  /** User information */\n  public user: ClientUser;\n  /** Whether the client has been disconnected. If true, the client needs to be reconnected with `.reconnect()` or destroyed */\n  public disconnected: boolean = false;\n  /**\n   * Utils for the client.\n   * @deprecated - functionality has been moved to other sections. This may be removed in the future.\n   */\n  public utils: ClientUtils;\n  /** The client's token */\n  public token: string;\n  /** @hidden */\n  private _handling: GameTypes.Handling;\n\n  /** Raw ribbon client, the backbone of TETR.IO multiplayer. You probably don't want to touch this unless you know what you are doing. */\n  public ribbon: Ribbon;\n  /** A helpful manager for all things social on TETR.IO (friends, dms etc.) */\n  public social!: Social;\n  /** The room the client is in (if it is in a room). You can make it non-nullable with `client.room!` */\n  public room?: Room;\n  /** The game the client is currently in if it is in a game. */\n  public game?: Game;\n\n  /** Useful for connecting to the main game API when none of the client helpers have the request you want to send. You can use `client.api.get` and `client.api.post` to easily send GET and POST requests. */\n  public api: API;\n\n  public rooms: {\n    list(): ReturnType<API[\"rooms\"]>;\n    join(id: string): Promise<Room>;\n    create(type?: \"public\" | \"private\"): Promise<Room>;\n  };\n\n  /**\n   * Raw ribbon handler.\n   * @example\n   * client.on('social.dm', () => console.log('DM received!'));\n   */\n  public on: typeof this.ribbon.emitter.on;\n  /** Raw ribbon handler. */\n  public off: typeof this.ribbon.emitter.off;\n  /** Raw ribbon handler. You likely want to use `client.wait` instead. */\n  public once: typeof this.ribbon.emitter.once;\n  /** Raw ribbon handler for sending messages. */\n  public emit: typeof this.ribbon.emit;\n\n  /** @hideconstructor */\n  private constructor(\n    token: string,\n    sessionID: string,\n    ribbon: Ribbon,\n    me: Awaited<ReturnType<API[\"users\"][\"me\"]>>,\n    userAgent: string = CONSTANTS.userAgent,\n    handling: GameTypes.Handling\n  ) {\n    this.token = token;\n    this.ribbon = ribbon;\n    this.on = ribbon.emitter.on.bind(ribbon.emitter);\n    this.off = ribbon.emitter.off.bind(ribbon.emitter);\n    this.once = ribbon.emitter.once.bind(ribbon.emitter);\n    this.emit = ribbon.emit.bind(ribbon);\n\n    this.user = {\n      id: me._id,\n      role: me.role,\n      sessionID,\n      username: me.username,\n      userAgent\n    };\n\n    this._handling = handling;\n\n    this.utils = new ClientUtils(this);\n\n    this.api = new API({ token: this.token, userAgent });\n\n    this.rooms = {\n      list: () => this.api.rooms(),\n      join: async (id: string) => {\n        return await this.wrap(\n          \"room.join\",\n          id.toUpperCase(),\n          \"client.room.join\"\n        );\n      },\n      create: async (type = \"private\") => {\n        return await this.wrap(\n          \"room.create\",\n          type === \"public\",\n          \"client.room.join\"\n        );\n      }\n    };\n\n    this.init();\n  }\n\n  /**\n   * Create a new client\n   * @example\n   * const client = await Client.connect({ token: 'your.jwt.token' });\n   * @example\n   * const client = await Client.connect({ username: 'halp', password: 'password' });\n   * @example\n   * // If playing games, pass in handling\n   * const client = await Client.connect({\n   *   // ...login info\n   *   handling: {\n   *     arr: 0,\n   *     cancel: false,\n   *     das: 5,\n   *     dcd: 0,\n   *     safelock: false,\n   *     may20g: true,\n   *     sdf: 41\n   *   };\n   * });\n   * @example\n   * // You can pass in a custom user agent\n   * const client = await Client.connect({\n   *   // ...login info\n   *   userAgent: \"v8/001\"\n   * });\n   */\n  static async connect(options: ClientOptions) {\n    const api = new API();\n    if (options.userAgent) {\n      api.update({ userAgent: options.userAgent });\n    }\n    if (options.turnstile) {\n      api.update({ turnstile: options.turnstile });\n    }\n\n    const sessionID = `SESS-${Math.floor(\n      Math.random() * Number.MAX_SAFE_INTEGER\n    )}`;\n    let self: { id: string; token: string };\n    if (\"token\" in options) {\n      if (!options.token) throw new Error(\"No valid token was provided\");\n      self = {\n        token: options.token,\n        id: parseToken(options.token)\n      };\n    } else if (\"username\" in options) {\n      self = await api.users.authenticate(options.username, options.password);\n    } else {\n      throw new Error(\"Invalid client options\");\n    }\n\n    const token = self.token;\n\n    api.update({ token });\n    const me = api.users.me();\n\n    const handling: Types.Game.Handling = options.handling || {\n      arr: 0,\n      cancel: false,\n      das: 5,\n      dcd: 0,\n      safelock: false,\n      may20g: true,\n      sdf: 41,\n      irs: \"tap\",\n      ihs: \"tap\"\n    };\n\n    const ribbon = await Ribbon.create({\n      token,\n      handling,\n      userAgent: options.userAgent || CONSTANTS.userAgent,\n      ...(options.ribbon ?? {})\n    });\n\n    const data = await new Promise<Events.in.Client[\"client.ready\"]>(\n      (resolve, reject) => {\n        const t = setTimeout(() => {\n          ribbon.destroy();\n          reject(\"Failed to connect\");\n        }, 5000);\n        ribbon.emitter.once(\"client.ready\", (d) => {\n          if (d) {\n            clearTimeout(t);\n            resolve(d);\n          }\n        });\n      }\n    );\n\n    const client = new Client(\n      token,\n      sessionID,\n      ribbon,\n      await me,\n      options.userAgent || CONSTANTS.userAgent,\n      handling\n    );\n\n    client.social = await Social.create(client, data.social);\n\n    return client;\n  }\n\n  /**\n   * Wait for an event to occur. Wraps `client.once` into a typed Promise.\n   * @returns the data from the event\n   * @example\n   * // wait for a notification (although you probably want to use `client.on` for this instead)\n   * console.log(await client.wait('social.notification'));\n   */\n  wait<T extends keyof Events.in.all>(event: T) {\n    return new Promise<Events.in.all[T]>((resolve) =>\n      this.once(event, resolve)\n    );\n  }\n\n  /**\n   * Send a message and then wait for another message. Throws an error if a 'err' message is received before the response message\n   * @param event - the `command` of the event to send\n   * @param data - the data to send along with the command. For void (no) data, just pass in `undefined`\n   * @param listen - the event to wait for before resolving.\n   * @param error - a list of custom error events to listen for. Defaults to `[client.error]`.\n   * @returns the data sent by the `listen` event\n   * @throws an error if the error event provided (or `client.error`) is received from TETR.IO\n   * @example\n   * // This is just for example, use `client.room!.chat` instead\n   * await client.wrap('room.chat', { content: 'Hello', pinned: false }, 'room.chat');\n   */\n  wrap<O extends keyof Events.out.all, I extends keyof Events.in.all>(\n    event: O,\n    data: Events.out.all[O],\n    listen: I,\n    error: (keyof Events.in.all)[] = [\"client.error\"]\n  ) {\n    return new Promise<Events.in.all[I]>((resolve, reject) => {\n      const disband = () => {\n        this.off(listen, rs);\n        error.forEach((err) => this.off(err, rj));\n      };\n      const rs = (data: Events.in.all[I]) => {\n        disband();\n        resolve(data);\n      };\n\n      const rj = (error: string) => {\n        disband();\n        reject(error);\n      };\n\n      this.on(listen, rs);\n      error.forEach((err) => this.on(err, rj));\n\n      // @ts-expect-error\n      this.emit(event, data);\n    });\n  }\n\n  /** @hidden */\n  private init() {\n    this.on(\"room.join\", async () => {\n      const data = await this.wait(\"room.update\");\n      this.room = new Room(this, data);\n      this.emit(\"client.room.join\", this.room!);\n    });\n\n    this.on(\"notify\", (notif) => {\n      if (typeof notif === \"string\") {\n        return this.emit(\"client.notify\", { msg: notif });\n      } else if (\"type\" in notif) {\n        switch (notif.type) {\n          case \"deny\":\n            this.emit(\"client.notify\", {\n              msg: notif.msg,\n              color: \"#FF2200\",\n              icon: \"denied\",\n              timeout: notif.timeout\n            });\n            break;\n          case \"warn\":\n            this.emit(\"client.notify\", {\n              msg: notif.msg,\n              color: \"#FFF43C\",\n              icon: \"warning\"\n            });\n            break;\n          case \"err\":\n            this.emit(\"client.error\", notif.msg);\n            this.emit(\"client.notify\", {\n              msg: notif.msg,\n              color: \"#FF4200\",\n              icon: \"error\"\n            });\n            break;\n          case \"announce\":\n            this.emit(\"client.notify\", {\n              msg: notif.msg,\n              color: \"#FFCC00\",\n              icon: \"announcement\",\n              timeout: 1e4\n            });\n            break;\n          case \"ok\":\n            this.emit(\"client.notify\", {\n              msg: notif.msg,\n              color: \"#6AFF3C\",\n              icon: \"ok\"\n            });\n            break;\n        }\n      } else {\n        this.emit(\"client.notify\", notif);\n      }\n    });\n\n    this.on(\"client.dead\", async () => {\n      this.disconnected = true;\n    });\n  }\n\n  /**\n   * Reconnect the client to TETR.IO.\n   * @throws {Error} if the client is already connected\n   */\n  async reconnect() {\n    if (!this.disconnected) {\n      throw new Error(\"Client is not disconnected.\");\n    }\n\n    const newRibbon = await this.ribbon.clone();\n    this.ribbon.destroy();\n    this.ribbon = newRibbon;\n\n    const data = await new Promise<Events.in.Client[\"client.ready\"]>(\n      (resolve, reject) => {\n        const t = setTimeout(() => {\n          newRibbon.destroy();\n          reject(\"Failed to connect\");\n        }, 5000);\n        this.ribbon.emitter.once(\"client.ready\", (d) => {\n          if (d) {\n            clearTimeout(t);\n            resolve(d);\n          }\n        });\n      }\n    );\n\n    this.social = await Social.create(this, data.social);\n  }\n\n  /** The client's current handling. */\n  get handling() {\n    return this._handling;\n  }\n\n  /** Change the client's current handling (do not use while in a room) */\n  set handling(handling: GameTypes.Handling) {\n    if (this.room)\n      throw new Error(\n        \"Do not set the handling in a room (you will be banned)!\"\n      );\n    this._handling = handling;\n    this.emit(\"config.handling\", handling);\n  }\n\n  /** Clean up the client. Leaves any rooms first. */\n  async destroy() {\n    if (this.room) {\n      try {\n        await this.room.leave();\n      } catch (e) {}\n    }\n    this.ribbon.destroy();\n    if (this.room) delete this.room;\n    if (this.game) delete this.game;\n  }\n}\n"],"names":["API","CONSTANTS","parseToken","Ribbon","Room","Social","ClientUtils","Client","user","disconnected","utils","token","_handling","ribbon","social","room","game","api","rooms","on","off","once","emit","sessionID","me","userAgent","handling","emitter","bind","id","_id","role","username","list","join","wrap","toUpperCase","create","type","init","connect","options","update","turnstile","Math","floor","random","Number","MAX_SAFE_INTEGER","self","Error","users","authenticate","password","arr","cancel","das","dcd","safelock","may20g","sdf","irs","ihs","data","Promise","resolve","reject","t","setTimeout","destroy","d","clearTimeout","client","wait","event","listen","error","disband","rs","forEach","err","rj","notif","msg","color","icon","timeout","reconnect","newRibbon","clone","leave","e"],"mappings":"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"}