pupflow
v0.1.0
Published
**Have you ever felt your automation or web scraping project was a total mess?**
Maintainers
Readme
Pupflow
Have you ever felt your automation or web scraping project was a total mess?
You wanted to improve the code structure but didn't know which architecture to follow? Tired of reinventing the wheel for every new scraper, mixing logic, config, and logging in a single file?
Meet Pupflow.
Pupflow is a lightweight, type-safe, and structured framework designed to bring sanity to your browser automation workflows. It provides a clean architecture for defining Flows composed of reusable Actions, handling logging, error diagnostics, and context management out of the box.
While designed with Puppeteer in mind, Pupflow is structured to be compatible with Playwright as well, thanks to its generic interface design.
Key Features
- Structured Architecture: Break down complex workflows into small, manageable, and reusable Actions.
- Type-Safety: Fully typed Context, Input, Page, and Browser ensures you catch errors at compile time, not runtime.
- Framework Agnostic: Works seamlessly with Puppeteer (default examples) and is compatible with Playwright.
- Built-in Diagnostics: Automatically captures Screenshots and HTML snapshots when a flow fails, making debugging painless.
- Context Management: Easily pass state between actions and receive a final result object.
- Integrated Logging: Built-in structured logging with Winston.
Installation
npm install pupflow puppeteer
# or
yarn add pupflow puppeteerExample: Login Flow
Here is a complete example of a Login Flow using Puppeteer.
The flow accepts LoginCredentials as Input and returns a LoginContext indicating if the login was successful.
import puppeteer from "puppeteer"
import { flow, action, PuppeteerPage, PuppeteerBrowser } from "pupflow"
// 1. Define the Result Context
type LoginContext = {
isLogged: boolean
}
// 2. Define the Input Data
type LoginInput = {
username: string
password: string
}
// 3. Create the Flow
const loginFlow = flow<LoginContext, LoginInput, PuppeteerPage, PuppeteerBrowser>(
"Simple Login Flow",
{
// Initial state of the context
defaultContext: {
isLogged: false,
},
// Enable auto-screenshots and HTML dumps on error
diagnostics: true,
actions: [
action("Navigate to Login", async ({ page, logger }) => {
logger.info("Navigating...")
await page.goto("https://example.com/login")
}),
action("Fill Credentials", async ({ page, input, logger }) => {
// Input is fully typed here!
logger.info(`Filling form for user: ${input.username}`)
await page.type("#username", input.username)
await page.type("#password", input.password)
}),
action("Submit Form", async ({ page }) => {
await Promise.all([
page.waitForNavigation(),
page.click("#login-btn"),
])
}),
action("Verify Session", async ({ page, context }) => {
try {
await page.waitForSelector(".dashboard-element", { timeout: 3000 })
context.isLogged = true
} catch {
context.isLogged = false
}
}),
],
}
)
// 4. Run it
async function main() {
const browser = await puppeteer.launch({ headless: false })
const page = await browser.newPage()
try {
console.log("Starting Login Flow...")
const result = await loginFlow.execute({
page: page,
browser: browser,
input: {
username: "myuser",
password: "mypassword123",
},
})
console.log("Flow Finished. Result:", result)
// Output: { isLogged: true } (or false)
} catch (error) {
console.error("Critical failure during flow execution.")
} finally {
await browser.close()
}
}
main()Debugging & Diagnostics
One of the biggest pains in automation is knowing why something failed in headless mode.
Pupflow handles this automatically. If an exception is thrown inside any action, Pupflow will:
- Log the error with the specific action label.
- (If configured) Capture a Screenshot of the page state at the moment of failure.
- (If configured) Save the HTML source of the page.
These artifacts are saved to an errors/ directory by default, allowing you to visually inspect exactly what the browser saw when it crashed.
const myFlow = flow("My Flow", {
// ...
diagnostics: {
screenshot: true, // Save error.png
html: true, // Save error.html
outDir: "./debug-artifacts" // Optional custom path
}
})Contributing
Feel free to open issues or PRs if you want to add more built-in patterns or support for other drivers!
