npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hira-core/sdk

v1.0.24

Published

SDK for building Hira automation flows with TypeScript

Downloads

1,299

Readme

@hira-core/sdk

SDK for building Hira automation flows with TypeScript. Provides type-safe base classes, browser utilities, and logger for running flows inside the Hira Agent sandbox.

📖 Full Documentation — Guides, API reference, and examples.

Installation

npm install @hira-core/sdk
# or
pnpm add @hira-core/sdk

Peer dependency: Requires puppeteer-core to be available at runtime (provided by the Hira Agent).


Quick Start

1. Define your Flow Config

import {
  AntidetectBaseFlow,
  AntidetectProvider,
  defineFlowConfig,
  IScriptContext,
  BrowserUtils,
  FlowLogger,
} from "@hira-core/sdk";

const config = defineFlowConfig({
  globalInput: [
    {
      key: "targetUrl",
      label: "Target URL",
      type: "text" as const,
      required: true,
    },
    {
      key: "delay",
      label: "Delay (ms)",
      type: "number" as const,
      defaultValue: 2000,
    },
  ],
  profileInput: [
    { key: "username", label: "Username", type: "text" as const },
    { key: "password", label: "Password", type: "text" as const },
  ],
  output: [
    { index: 0, key: "isLoggedIn", label: "Login Status" },
    { index: 1, key: "pageTitle", label: "Page Title" },
  ],
});

type MyConfig = typeof config;

defineFlowConfig() validates for duplicate keys, labels, and output indices at compile time — providing instant TS errors if any field is duplicated.

2. Implement your Flow class

export class MyFlow extends AntidetectBaseFlow<MyConfig> {
  constructor() {
    super(AntidetectProvider.GPM, new FlowLogger(MyFlow.name), config);
  }

  async script(context: IScriptContext<MyConfig>): Promise<void> {
    const { page, logger, globalInput, profileInput, output } = context;
    const utils = new BrowserUtils(context);

    await utils.goto(globalInput.targetUrl);
    logger.info(`Logging in as: ${profileInput.username}`);

    await utils.type("#username", profileInput.username);
    await utils.type("#password", profileInput.password);
    await utils.click("#login-btn");

    const title = await page.title();

    // Write typed output (validated against config.output keys)
    await utils.writeOutput("isLoggedIn", true);
    await utils.writeOutput("pageTitle", title);

    logger.success(`✅ Done — page: ${title}`);
  }
}

export default MyFlow;

3. Run locally (for development)

import MyFlow from "./index";

const flow = new MyFlow();

await flow.run(
  flow.createRunParams({
    antidetect: {
      profileSettings: [
        flow.createProfileSetting("ProfileA", {
          username: "user1",
          password: "pass1",
        }),
      ],
    },
    execution: { concurrency: 2, maxRetries: 1 },
    globalInput: { targetUrl: "https://example.com", delay: 2000 },
    window: { width: 1280, height: 720, scale: 1 },
  }),
);

API Reference

AntidetectBaseFlow<TConfig>

Abstract base class for browser automation flows.

| Method / Property | Description | | ----------------------------------- | ------------------------------------------------ | | abstract script(context) | Your automation logic — implement this | | run(params) | Start the flow (called by Hira Agent) | | createRunParams(params) | Type-safe helper to build run params | | createProfileSetting(name, data?) | Type-safe helper to build profile settings | | flowConfig | The declared config schema (embedded in .hira) |

AntidetectProvider

enum AntidetectProvider {
  GPM = "gpm",         // GPM Login antidetect browser
  HIDEMIUM = "hidemium", // Hidemium antidetect browser
  GENLOGIN = "genlogin", // coming soon
}

IScriptContext<TConfig>

Injected into script() by the runtime:

| Field | Type | Description | | -------------- | ---------------------------- | ---------------------------------------------------- | | browser | Browser | Puppeteer browser instance | | page | Page | Active page | | profile | IAntidetectProfile | Current profile info (unified across providers) | | index | number | Profile index in the batch | | globalInput | InferGlobalInput<TConfig> | Typed global inputs | | profileInput | InferProfileInput<TConfig> | Typed per-profile inputs | | output | InferOutput<TConfig> | Current output values (pre-populated from last run) | | logger | ILogger | Bound logger (auto-tagged with profile name) |

IAntidetectProfile

Unified profile interface — works across all providers (GPM, Hidemium, etc.):

interface IAntidetectProfile {
  id: string;              // Unique ID
  name: string;            // Human-readable name
  provider: "gpm" | "hidemium" | "genlogin";
  raw_proxy?: string;      // Proxy string
  browser_type: "chromium" | "firefox";
  browser_version: string;
  group_id?: string;
  profile_path: string;
  note: string;
  created_at: string;      // ISO 8601
}

Note: IGpmProfile is deprecated — use IAntidetectProfile instead.

BrowserUtils

Helper class for common browser actions. All methods auto-log and respect the abort signal.

const utils = new BrowserUtils(context);

Navigation & Interaction

| Method | Description | | ------------------------------------------ | -------------------------------------- | | utils.goto(url) | Navigate to URL | | utils.click(selector) | Wait + scroll + click | | utils.click({ x, y }) | Click at specific coordinates | | utils.type(selector, text) | Wait + clear + type | | utils.select(selector, value) | Select dropdown option (native <select>) | | utils.getText(selector) | Get text content | | utils.getPosition(selector) | Get element center coordinates | | utils.exists(selector, timeout?) | Check element exists | | utils.waitForElement(selector, timeout?) | Wait for element | | utils.waitForNavigation() | Wait for page navigation | | utils.screenshot(path?) | Take screenshot | | utils.sleep(ms) | Delay (respects abort signal) | | utils.scroll({ deltaY }) | Smooth 60fps scroll (ease-in-out) | | utils.scroll({ deltaY, container }) | Smooth scroll inside overflow container|

Tab Management

| Method | Description | | --------------------------------- | ------------------------ | | utils.activeNewTab(options?) | Switch to new tab, returns true on success / false on timeout | | utils.activePopup(options?) | Switch to popup, returns true on success / false on timeout | | utils.switchToPopup(matcher) | Legacy alias for popup switching | | utils.switchToTabIndex(index) | Switch to tab by index | | utils.closeCurrentTab() | Close current tab | | utils.closeOtherTabs() | Close all other tabs |

Output & Data

| Method | Description | | ------------------------------------ | ------------------------------------------------ | | utils.writeOutput(key, value) | Write output value (type-safe against config) | | utils.writeProfileInput(key, val) | Update profile input value for next run | | utils.logGlobalInput() | Log all global inputs | | utils.logProfileInput() | Log all profile inputs |

Production Stability Notes

  • activeNewTab() and activePopup() now use soft-fail semantics: return false when the tab/popup is not found instead of throwing. Always check the boolean before interacting with the new page.
  • Browser activation internally catches non-critical CDP focus/stealth failures so a closed or unstable tab does not crash the whole flow.
  • BaseFlow.processProfile() performs final logger cleanup and promise-reference cleanup to prevent ghost logs and memory leaks in long-running agents.
  • GPM/Hidemium profile startup errors preserve the provider's original error message, making production failures easier to diagnose.

FlowLogger

Logger that works both in standalone mode (console) and inside Hira Agent worker (postMessage).

const logger = new FlowLogger("MyFlow");

logger.info("message");
logger.success("done");
logger.warn("warning");
logger.error("error");
logger.debug("debug");

IFlowConfig

Schema declaration for your flow's inputs and outputs:

interface IFlowConfig {
  globalInput: readonly IInputField[];   // shared across all profiles
  profileInput: readonly IInputField[];  // per-profile data
  output?: readonly IOutputField[];      // output fields per profile
}

interface IInputField {
  key: string;
  label: string;
  type: "text" | "number" | "boolean" | "select" | "textarea";
  required?: boolean;
  defaultValue?: string | number | boolean;
  placeholder?: string;
  options?: { label: string; value: string | number }[];
}

interface IOutputField {
  index: number;   // display order
  key: string;     // unique key for writeOutput()
  label: string;   // human-readable label
}

defineFlowConfig()

Helper function that validates your config at compile time — catches duplicate keys, labels, indices, and option values:

// ✅ OK
const config = defineFlowConfig({
  globalInput: [
    { key: "url", label: "URL", type: "text" },
  ],
  profileInput: [
    { key: "user", label: "User", type: "text" },
  ],
  output: [
    { index: 0, key: "status", label: "Status" },
    { index: 1, key: "title", label: "Title" },
  ],
});

// ❌ TS Error — duplicate key "url" in globalInput
const bad = defineFlowConfig({
  globalInput: [
    { key: "url", label: "URL 1", type: "text" },
    { key: "url", label: "URL 2", type: "text" }, // Error!
  ],
  profileInput: [],
});

ExcelStorage

Read profile data from Excel files and write output back:

import { ExcelStorage } from "@hira-core/sdk";

const storage = new ExcelStorage("data.xlsx");

// Read rows from a sheet
const rows = await storage.readRows("Sheet1");

// Write output rows
await storage.writeRows("Output", outputData);

Type Inference

The SDK automatically infers TypeScript types from your config at compile time:

const config = defineFlowConfig({
  globalInput: [
    { key: "url", type: "text" as const, label: "URL" },
    { key: "count", type: "number" as const, label: "Count" },
  ],
  profileInput: [
    { key: "username", type: "text" as const, label: "Username" },
  ],
  output: [
    { index: 0, key: "isLoggedIn", label: "Logged In" },
  ],
});

// Inside script():
// globalInput.url         → string  ✅
// globalInput.count       → number  ✅
// profileInput.username   → string  ✅
// output.isLoggedIn       → ProfileOutputValue | null  ✅

Building & Publishing a Flow

Use @hira-core/cli to package your flow:

npx @hira-core/cli build

Virtual Cursor

The SDK includes a virtual cursor — a visible SVG cursor overlay that shows mouse movement, clicks, and scrolling in real-time. This is enabled by default and can be toggled via IExecutionConfig.virtualCursor:

// In flow runner params
execution: {
  virtualCursor: true,   // default — show cursor overlay
  // virtualCursor: false,  // disable cursor overlay
}

When enabled, BrowserUtils.click(), scroll(), and other interaction methods will show realistic Bézier curve mouse movement with human-like timing.


License

ISC