SDK + Plugin System

Program the workflow model.

Glubean is not a runner you invoke and forget. The SDK gives you traced primitives for API workflows, and the plugin system lets you extend the same model with browser steps, GraphQL, and your own domain logic.

real TypeScriptfirst-class pluginsshared configure() runtimeone workflow model

Real TypeScript

Workflows stay readable, reviewable, and easy to refactor with the rest of your codebase.

First-class plugins

Add GraphQL, browser steps, auth helpers, or internal clients without inventing a second system.

One workflow model

Local runs, CI, browser steps, and Cloud all sit on the same runtime and trace model.

Start with a real workflow foundation

The core SDK already gives you the parts most teams need: requests, assertions, secrets, templating, and structured traces. Plugins build on top of that runtime instead of replacing it.

products.test.ts
import { test } from "@glubean/sdk";

test("list products", async (ctx) => {
  const base = ctx.vars.require("BASE_URL");

  const data = await ctx.http
    .get(`${base}/products?limit=5`)
    .json();

  ctx.expect(data.products.length).toBe(5);
  ctx.log(`Found ${data.total} products`);
});
Core: Auto-traced HTTP requests with timing and status
Core: Template variables and secrets resolved per environment
Core: Structured assertions with useful diffs on failure
Core: Shared helpers that stay plain TypeScript
Core: Secrets auto-redacted before upload to Cloud

Plugins are the product, not an afterthought

Use official packages when they fit, then add your own organization-specific capabilities without leaving the workflow system. The point is not a pile of adapters. The point is one runtime that keeps growing with your use case.

@glubean/graphql

Ground GraphQL queries and mutations in the same traced workflow you already use for HTTP.

@glubean/browser

Extend the same workflow into Puppeteer-powered browser steps without losing structure.

Your own plugin

Wrap internal services, auth flows, or domain helpers as reusable capabilities for the whole team.

GraphQL stays inside the same trace model

users.test.ts
import { test, configure } from "@glubean/sdk";
import { graphql } from "@glubean/graphql";

const { gql } = configure({
  plugins: {
    gql: graphql({
      endpoint: "{{GRAPHQL_URL}}",
      headers: { Authorization: "Bearer {{API_KEY}}" },
    }),
  },
});

export const getUser = test("get-user", async (ctx) => {
  const { data } = await gql.query<{ user: { name: string } }>(`
    query GetUser($id: ID!) {
      user(id: $id) { name email }
    }
  `, { variables: { id: "1" } });

  ctx.expect(data?.user.name).toBe("Alice");
});

Browser steps extend the same workflow into Puppeteer

login.test.ts
import { test, configure } from "@glubean/sdk";
import { browser } from "@glubean/browser";

const { chrome } = configure({
  plugins: { chrome: browser({ launch: true }) },
});

const ui = test.extend({
  page: async (ctx, use) => {
    const pg = await chrome.newPage(ctx);
    try { await use(pg); }
    finally { await pg.close(); }
  },
});

export const login = ui("login-flow", async (ctx) => {
  await ctx.page.goto("/login");
  await ctx.page.type("#email", "user@test.com");
  await ctx.page.type("#password", "secret");
  await ctx.page.clickAndNavigate('button[type="submit"]');
  await ctx.page.expectURL("/dashboard");
  await ctx.page.expectText("h1", "Welcome back");
});

Build the plugin your team actually needs

Wrap an internal service client, auth helper, or domain-specific workflow primitive once, then reuse it everywhere. This is the difference between a convenient test file and a workflow system that compounds.

payments-plugin.ts
import { definePlugin, configure, test } from "@glubean/sdk";

const payments = (opts: { baseUrlKey: string }) =>
  definePlugin((runtime) => {
    const client = runtime.http.extend({
      prefixUrl: runtime.requireVar(opts.baseUrlKey),
      headers: {
        Authorization: `Bearer ${runtime.requireSecret("STRIPE_KEY")}`,
      },
    });
    return {
      charge: (amount: number) =>
        client.post("charges", { json: { amount } }).json(),
      refund: (id: string) =>
        client.post(`charges/${id}/refund`).json(),
    };
  });

const { pay } = configure({
  plugins: { pay: payments({ baseUrlKey: "PAYMENTS_URL" }) },
});

export const chargeAndRefund = test("charge-refund", async (ctx) => {
  const charge = await pay.charge(2500);
  ctx.expect(charge.status).toBe("succeeded");

  const refund = await pay.refund(charge.id);
  ctx.expect(refund.status).toBe("refunded");
});
Plugins receive runtime context, including vars, secrets, and the traced HTTP client
Initialization stays lazy, so setup cost lands only when the plugin is used
Types flow through configure() without casts or wrapper DSLs
Official and custom plugins compose into one runtime for the whole workflow

Compose one runtime, not a pile of helpers

Official packages and custom plugins join in one configure() call. That keeps the workflow surface consistent across local runs, CI, and Cloud.

configure.ts
const { gql, chrome, pay } = configure({
  plugins: {
    gql:    graphql({ endpoint: "{{GQL_URL}}" }),
    chrome: browser({ launch: true }),
    pay:    payments({ baseUrlKey: "PAY_URL" }),
  },
});
Shared auth, clients, and plugin setup live in one place
Workflow files stay small because heavy setup moves into configure()
The same runtime can power extension authoring, CI runs, and Cloud history

Runtime note: Node.js, plugin-friendly

Glubean runs on Node.js with native TypeScript support — no build step required. The entire npm ecosystem is available, so any package you already use works out of the box. The practical rule is simple: if you can import it, it is a good plugin candidate. When you need heavier browser coverage, keep Playwright where it fits and use Glubean where the shared workflow model matters more.