import { Client } from "@olenbetong/appframe-data"; import inquirer from "inquirer"; import type { Store } from "tough-cookie"; import { getSavedPassword, savePassword } from "./auth.js"; export class PersistentClient extends Client { #username: string; #password: string; #cookieStore: Store | undefined; constructor(hostname: string, cookieStore: Store | undefined, username: string, password: string) { super(hostname, cookieStore); this.#username = username; this.#password = password; this.#cookieStore = cookieStore; } async promptForCredentials() { // ask for credentials using inquirer const answers = await inquirer.prompt([ { type: "input", name: "username", message: "Username", default: this.#username, }, { type: "password", name: "password", message: "Password", default: this.#password, }, ]); this.#username = answers.username; this.#password = answers.password; } override async fetch(input: any, init?: any) { let response = await super.fetch(input, init); if (response.status === 401 || response.status === 403) { try { if (!this.#password && this.#username) { this.#password = (await getSavedPassword(this.hostname, this.#username)) ?? this.#password; } if (!this.#username || !this.#password) { await this.promptForCredentials(); } await this.#cookieStore?.removeCookie(this.hostname, "/", "AppframeWebSession"); await this.#cookieStore?.removeCookie(this.hostname, "/", "AppframeWebAuth"); await super.login(this.#username, this.#password, { remember: true }); await savePassword(this.hostname, this.#username, this.#password); response = await super.fetch(input, init); } catch (error) { // ignore, but invalidate the credentials this.#username = ""; this.#password = ""; throw error; } } return response; } }