AkurAI Build
Menu

popagent

public

Latest change 7f0ff66d6d9fb6468416c58bee46bd3d08169501 - Checkpoint browser channels and memory work by AkurAI Build

import type { BrowserProfile } from "./api-types";
import { retryableInit } from "./retryable-init";
import { secrets } from "./secrets";
import { storage } from "./storage";

const RESOURCE_ID = "popagent-browser";
const PROFILE_COLUMNS = `id,name,enabled,created_at::text AS "createdAt",updated_at::text AS "updatedAt"`;

function validStorageState(value: unknown): value is Record<string, unknown> {
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
  const state = value as { cookies?: unknown; origins?: unknown };
  return Array.isArray(state.cookies) && Array.isArray(state.origins);
}

export class BrowserProfileStore {
  readonly storage = storage;
  private readonly initializeOnce = retryableInit(() => this.initialize());
  init() { return this.initializeOnce(); }

  private async initialize() {
    await this.storage.init();
    await this.storage.db.none(await Bun.file(new URL("./browser-profiles.sql", import.meta.url)).text());
  }

  async list(): Promise<BrowserProfile[]> {
    await this.init();
    return this.storage.db.any<BrowserProfile>(`SELECT ${PROFILE_COLUMNS} FROM popagent_browser_profiles ORDER BY name`);
  }

  async create(input: { name: string; enabled: boolean; state: unknown }): Promise<BrowserProfile> {
    if (!validStorageState(input.state)) throw new Error("Invalid Playwright storage state");
    await this.init();
    const id = crypto.randomUUID();
    const profile = await this.storage.db.tx(async (db) => {
      if (input.enabled) await db.none("UPDATE popagent_browser_profiles SET enabled=FALSE,updated_at=NOW() WHERE enabled");
      return db.one<BrowserProfile>(
        `INSERT INTO popagent_browser_profiles (id,name,enabled) VALUES ($1,$2,$3) RETURNING ${PROFILE_COLUMNS}`,
        [id, input.name, input.enabled],
      );
    });
    try {
      if (!await secrets.store(RESOURCE_ID, `profile:${id}`, JSON.stringify(input.state))) throw new Error("Unable to store browser profile secret");
      return profile;
    } catch (error) {
      await this.storage.db.none("DELETE FROM popagent_browser_profiles WHERE id=$1", [id]);
      throw error;
    }
  }

  async update(id: string, input: { name: string; enabled: boolean; state?: unknown }): Promise<BrowserProfile | undefined> {
    if (input.state !== undefined && !validStorageState(input.state)) throw new Error("Invalid Playwright storage state");
    await this.init();
    const profile = await this.storage.db.tx(async (db) => {
      if (input.enabled) await db.none("UPDATE popagent_browser_profiles SET enabled=FALSE,updated_at=NOW() WHERE id<>$1 AND enabled", [id]);
      return (await db.oneOrNone<BrowserProfile>(
        `UPDATE popagent_browser_profiles SET name=$2,enabled=$3,updated_at=NOW() WHERE id=$1 RETURNING ${PROFILE_COLUMNS}`,
        [id, input.name, input.enabled],
      )) ?? undefined;
    });
    if (profile && input.state !== undefined && !await secrets.update(RESOURCE_ID, `profile:${id}`, JSON.stringify(input.state))) {
      throw new Error("Browser profile secret is missing");
    }
    return profile;
  }

  async recallState(id: string): Promise<Record<string, unknown> | undefined> {
    const value = await secrets.recall(RESOURCE_ID, `profile:${id}`);
    if (!value) return undefined;
    const parsed: unknown = JSON.parse(value);
    if (!validStorageState(parsed)) throw new Error("Stored browser profile has invalid storage state");
    return parsed;
  }

  async active(): Promise<{ profile: BrowserProfile; state: Record<string, unknown> } | undefined> {
    await this.init();
    const profile = await this.storage.db.oneOrNone<BrowserProfile>(
      `SELECT ${PROFILE_COLUMNS} FROM popagent_browser_profiles WHERE enabled ORDER BY updated_at DESC LIMIT 1`,
    );
    if (!profile) return undefined;
    const state = await this.recallState(profile.id);
    if (!state) throw new Error("Enabled browser profile secret is missing");
    return { profile, state };
  }

  async delete(id: string): Promise<boolean> {
    await this.init();
    const removed = Boolean(await this.storage.db.oneOrNone("DELETE FROM popagent_browser_profiles WHERE id=$1 RETURNING id", [id]));
    if (removed) await secrets.delete(RESOURCE_ID, `profile:${id}`);
    return removed;
  }
}

export const browserProfiles = new BrowserProfileStore();