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

@ianmenethil/zenpay-hpp

v5.1.0

Published

ZenPay Hosted Payment Page plugin — zero-dependency modal/redirect payment integration with optional jQuery and Bootstrap backward compatibility

Readme

ZenPay HPP Plugin

A hosted payment page (HPP) plugin for integrating ZenPay/Zenith Payments, B2BPay, TravelPay, RentalRewards, SchoolEasyPay, ChildCareEasyPay, and ThoroughbredPayments into merchant pages.

The plugin opens the hosted payment page in a modal iframe (displayMode=0) or returns a generated redirect URL (displayMode=1).

CI

CDN

// v6 — new opt-in features (theming, modern typography, typed ESM import)
// await import("https://cdn.zenithpayments.support/zenpay.payment.v6.js");
// await import("https://cdn.zenithpayments.support/zenpay.payment.v6.min.js");
// await import("https://cdn.zenithpayments.support/zenpay.payment.v6.obf.min.js");

// v5 — current stable release
// await import("https://cdn.zenithpayments.support/zenpay.payment.v5.js");
// await import("https://cdn.zenithpayments.support/zenpay.payment.v5.min.js");
await import("https://cdn.zenithpayments.support/zenpay.payment.v5.obf.min.js");

// v4 — parity port, no bug fixes
// await import("https://cdn.zenithpayments.support/zenpay.payment.v4.js");
// await import("https://cdn.zenithpayments.support/zenpay.payment.v4.min.js");
// await import("https://cdn.zenithpayments.support/zenpay.payment.v4.obf.min.js");

Modern ESM import (v6 only)

import { zpPayment, type ZpPaymentOptions, type ZpTheme } from "@ianmenethil/zenpay-hpp/v6";

const payment = zpPayment({
  url: "https://payuat.travelpay.com.au/online/v5",
  apiKey: "YOUR_API_KEY",
  fingerprint: "...",
  theme: "auto", // 'light' | 'dark' | 'auto'
});
payment.open();

Test Status

529 tests across 54 files — all passing.

| Suite | Files | Tests | Description | |-------|-------|-------|-------------| | test:unit (v3) | 14 | 118 | Node-environment unit tests for v3 source | | test:dom (v3) | 1 | 16 | JSDOM browser integration tests for v3 | | test:v4 | 12 | 118 | Full v4 test suite | | test:v5 | 13 | 136 | Full v5 test suite | | test:v6 | 14 | 141 | Full v6 test suite (v5 clone + 5 new theme tests) | | Total | 54 | 529 | |

Known-bug tests are marked test.fails() — they assert the correct behavior and are expected to fail against the buggy source. They do not inflate the passing count.

Coverage

| Version | Statements | Branches | Functions | Lines | |---------|-----------|----------|-----------|-------| | v3 | 100% | 100% | 100% | 100% | | v4 | 98.19% | 91.30% | 100% | 99.53% | | v5 | 97.70% | 89.47% | 97.43% | 100% | | v6 | 97.38% | 89.28% | 97.43% | 100% |

Run coverage:

bun run test:coverage:v3   # → coverage/v3/
bun run test:coverage:v4   # → coverage/v4/
bun run test:coverage:v5   # → coverage/v5/
bun run test:coverage:v6   # → coverage/v6/

Plugin Versions

This repository ships one plugin in three versions. All three produce the same end-user payment experience.

v3 — Production (jQuery + Bootstrap required)

Source: src/v3/zenpay.payment.bs5.js

The current live version, pulled by thousands of integrators from CDN today. Plain JavaScript. Hard dependencies on jQuery and Bootstrap 5. Contains known bugs — frozen, never edited.

<!-- Requires jQuery and Bootstrap 5 on the page -->
<script src="https://cdnuat.travelpay.com.au/js/zenpay.payment.bs5.js"></script>
<script>
  var payment = $.zpPayment({ ... });
  payment.init();
</script>

v4 — TypeScript Port (jQuery + Bootstrap optional)

Source: src/v4/zenpay.payment.v4.ts

Same behavior as v3. jQuery and Bootstrap are no longer required — the plugin detects them at runtime and uses them if present. Existing integrators with jQuery and Bootstrap see zero difference. New integrators without them get a pure JS/CSS fallback. No bug fixes — parity with v3 only.

<!-- jQuery and Bootstrap are optional -->
<script src="dist/zenpay.payment.v4.min.js"></script>
<script>
  var payment = zpPayment({ ... });   // window.zpPayment — no $ needed
  payment.init();
</script>

v5 — Current Release (zero dependencies, bug fixes)

Source: src/v5/zenpay.payment.v5.ts

v4 with targeted bug fixes and improvements. Same TypeScript codebase, same zero-dependency design, same backward compatibility. The fixes applied are limited to cases where the change cannot break any existing or new integration.

<script src="https://cdn.zenithpayments.support/zenpay.payment.v5.obf.min.js"></script>
<script>
  var payment = window.zpPayment({ ... });
  payment.open();
</script>

v6 — Opt-In Features (theming, typed ESM, modern baseline)

Source: src/v6/zenpay.payment.v6.ts

v5 behavior plus opt-in improvements that are zero-impact when unused. Same factory API (zpPayment({ ... })), same side-effect global registration (window.zpPayment, $.zpPayment), same tests and same passing behavior. Existing integrators who upgrade and don't pass any new options see byte-identical output to v5.

What's new in v6:

  • theme option"light" | "dark" | "auto". When set, stamps data-zp-theme on the modal/backdrop and switches palette via CSS variables. Default brand dark palette: #1a1a1a surface, #ff5252 accent. "auto" follows OS prefers-color-scheme.
  • CSS custom properties--zp-modal-bg, --zp-modal-fg, --zp-modal-border, --zp-modal-header-border, --zp-modal-muted, --zp-accent, --zp-backdrop-bg, --zp-btn-fg, --zp-font-family, --zp-radius, --zp-shadow, --zp-ease, --zp-modal-width, --zp-modal-max-width. Integrators can override any of these in their own stylesheet.
  • Modern baseline typography — system font stack, antialiased, tighter title (font-weight: 600, letter-spacing: -0.01em), body line-height: 1.55.
  • Responsive widthclamp(500px, 90vw, 900px) at ≥768px (up from fixed 600px/690px).
  • Softer visual chromeborder-radius: 8px (was 3px), subtle box-shadow, Material easing cubic-bezier(0.4, 0, 0.2, 1) on transitions.
  • Interactive close-button states — hover/active/focus-visible with 150ms transitions. Zero-specificity via :where() so Bootstrap pages continue to use Bootstrap's rules.
  • Named ESM export + .d.ts typesimport { zpPayment, type ZpPaymentOptions, type ZpTheme } from "@ianmenethil/zenpay-hpp/v6" with full IDE autocomplete.

Usage — CDN / UMD (unchanged from v5):

<script src="https://cdn.zenithpayments.support/zenpay.payment.v6.obf.min.js"></script>
<script>
  var payment = window.zpPayment({ theme: "dark", /* ... */ });
  payment.open();
</script>

Usage — ESM with full types:

import { zpPayment, type ZpPaymentOptions, type ZpTheme } from "@ianmenethil/zenpay-hpp/v6";

const theme: ZpTheme = "auto";
const payment = zpPayment({ theme, url: "...", apiKey: "...", fingerprint: "..." });
payment.open();

All three consumption paths (ESM import, CJS require, CDN script tag) produce the same function. Types are shipped at dist/types/v6/zenpay.payment.v6.d.ts.


Quick Start

// In browser console or inline script — no build step required
await import("https://cdn.jsdelivr.net/npm/js-sha3/src/sha3.min.js");
await import("https://cdn.zenithpayments.support/zenpay.payment.v5.obf.min.js");

const apiKey     = "YOUR_API_KEY";
const merchantCode = "YOUR_MERCHANT_CODE";
const password   = "YOUR_PASSWORD";
const mode       = "0";
const amount     = "1.00";
const id         = "uuid-" + Date.now();
const timestamp  = new Date().toISOString().slice(0, 19);
const fingerprint = sha3_512([apiKey, merchantCode, password, mode, amount * 100, id, timestamp].join("|"));

window.zpPayment({
  url:                    "https://payuat.travelpay.com.au/online/v5",
  merchantCode:           merchantCode,
  apiKey:                 apiKey,
  fingerprint:            fingerprint,
  redirectUrl:            "https://your-site.com/payment/result",
  merchantUniquePaymentId: id,
  timestamp:              timestamp,
  displayMode:            0,
  paymentAmount:          amount,
  customerName:           "Jane Smith",
  customerEmail:          "[email protected]",
  customerReference:      "ORDER-001",
}).open();

Registration

| Context | Call | |---------|------| | v3 | $.zpPayment(options) — jQuery only | | v4/v5/v6, no jQuery | window.zpPayment(options) or zpPayment(options) | | v4/v5/v6, jQuery present | Both $.zpPayment(options) and window.zpPayment(options) work | | v6, ESM import | import { zpPayment } from "@ianmenethil/zenpay-hpp/v6" (also registers window globals) |


Options Reference

Required

| Option | Type | Description | |--------|------|-------------| | url | string | HPP endpoint base URL | | apiKey | string | Merchant API key | | fingerprint | string | SHA3-512 HMAC of payment parameters | | action | string | Payment action (e.g. "Authorise") | | mode | number | Payment mode: 0=DefaultPayment, 1=Tokenise, 3=CustomPayment |

URL & Redirect

| Option | Type | Description | |--------|------|-------------| | callbackUrl | string | Server-to-server callback URL (at least one of callbackUrl/redirectUrl required) | | redirectUrl | string | Browser redirect on completion | | displayMode | string\|number | 0=modal popup, 1=return redirect URL payload | | merchantCode | string | Required for v4-format URLs (path contains v4) |

Customer

| Option | Type | Description | |--------|------|-------------| | customerName | string | Pre-fills customer name | | customerEmail | string | Pre-fills customer email | | customerReference | string | Merchant customer reference | | paymentAmount | string | Pre-fills payment amount | | merchantUniquePaymentId | string | Unique payment identifier (idempotency) | | timestamp | string | ISO 8601 timestamp without timezone (YYYY-MM-DDTHH:MM:SS) | | abn | string | Australian Business Number | | cardProxy | string | Stored card token |

UI

| Option | Type | Default | Description | |--------|------|---------|-------------| | title | string | "Process Payment" | Modal dialog title | | hideHeader | 0\|1 | 0 | Hide HPP page header | | hideAmount | 0\|1 | 0 | Hide amount display | | hideReference | 0\|1 | 0 | Hide reference display | | allowAmountChange | 0\|1 | — | Allow customer to change amount |

Theming (v6 only)

| Option | Type | Default | Description | |--------|------|---------|-------------| | theme | "light" \| "dark" \| "auto" | undefined | Stamps data-zp-theme on the modal/backdrop; undefined = unchanged v5 output |

For custom palettes beyond the built-in themes, override any --zp-* CSS variable in your own stylesheet. No option needed — works alongside or instead of theme. See the v6 section for the full token list.

Behaviour

| Option | Type | Description | |--------|------|-------------| | onPluginClose | function | Callback invoked when modal closes | | redirectOnError | boolean | Redirect instead of showing error in modal | | applePayPlugin | object | Pre-initialized Apple Pay plugin instance |


Display Modes

displayMode=0 — Modal popup

Opens the hosted payment page in a full-screen iframe modal. Call .open() (or .init() in v3) on the returned instance.

displayMode=1 — Redirect URL

Does not open any UI. Returns { isSuccess: true, url, height, width } from .init(). Redirect the browser to url yourself. Useful for mobile apps or custom UI flows.


Instance API

const payment = window.zpPayment(options);

payment.open();   // Opens modal (displayMode=0) or returns URL payload (displayMode=1)
payment.init();   // Alias for open() — v3 style
payment.close();  // Closes and removes the modal

Fingerprint

The fingerprint is a SHA3-512 hash of pipe-delimited payment parameters:

import { sha3_512 } from "js-sha3"; // or load from CDN

const fingerprint = sha3_512([
  apiKey,
  merchantCode,
  merchantPassword,
  mode,
  Math.round(parseFloat(amount) * 100),  // amount in cents
  merchantUniquePaymentId,
  timestamp,                              // YYYY-MM-DDTHH:MM:SS
].join("|"));

The exact parameter order is defined by the ZenPay HPP API. Contact [email protected] for merchant credentials.


Known Bugs (v3 and v4)

These bugs exist in v3 (frozen, never fixed) and are intentionally reproduced in v4 (parity rules). They are fixed in v5 and v6.

| # | Severity | Description | v3 | v4 | v5 | v6 | |---|----------|-------------|----|----|----|-----| | 001 | Medium | getPBoolValue strict equality — string "1" returns false instead of true | Bug | Bug (parity) | Fixed | Fixed | | 002 | Low | Height calculation — mode="1" (string) gives 725px instead of 450px | Bug | Bug (parity) | Fixed | Fixed | | 003 | Low | onPaymentPluginLoaded leaks as implicit global (window.onPaymentPluginLoaded) | Bug | Bug (parity) | Fixed | Fixed | | 004 | Info | CSS class typo modal-dailog-payment (kept for backward compat) | Typo | Kept | Kept | Kept | | 005 | Medium | closePayment() creates a new Bootstrap Modal instance instead of reusing the existing one | Bug | Bug (parity) | Fixed | Fixed |

All bugs are fixed in v5 and v6. Bug 004 is a deliberate backward-compat decision — both the original typo class and the corrected class are applied.


Development

Prerequisites

bun install

Commands

| Command | Description | |---------|-------------| | bun run test:unit | v3 unit tests (Node environment) | | bun run test:dom | v3 DOM tests (JSDOM) | | bun run test:v4 | v4 test suite | | bun run test:v5 | v5 test suite | | bun run test:v6 | v6 test suite | | bun run test:vitest | All Vitest tests (unit + dom + v4 + v5 + v6) | | bun run test:all | Full local suite | | bun run test:coverage:v3 | v3 coverage → coverage/v3/ | | bun run test:coverage:v4 | v4 coverage → coverage/v4/ | | bun run test:coverage:v5 | v5 coverage → coverage/v5/ | | bun run test:coverage:v6 | v6 coverage → coverage/v6/ | | bun run test:e2e | Playwright live E2E (requires env vars) | | bun run lint | ESLint | | bun run typecheck | TypeScript type check | | bun run build | Build all versions to dist/ (includes v6 ESM + .d.ts) | | bun run build:v4 | Build v4 only (plain + min + obf) | | bun run build:v5 | Build v5 only (plain + min + obf) | | bun run build:v6 | Build v6 only (plain + min + obf + esm) | | bun run build:v6:esm | Build v6 ESM module only (.mjs) | | bun run build:types:v6 | Emit v6 TypeScript declarations to dist/types/v6/ | | bun run build:local | Build + copy to local CDN server (hostname Anticide only) | | bun run check | Full quality gate (lint + typecheck + knip + coverage including v6) |

Build Outputs

dist/
  zenpay.payment.v4.js            # v4 plain (IIFE)
  zenpay.payment.v4.min.js        # v4 minified (IIFE)
  zenpay.payment.v4.obf.min.js    # v4 obfuscated + minified
  zenpay.payment.v5.js            # v5 plain (IIFE)
  zenpay.payment.v5.min.js        # v5 minified (IIFE)
  zenpay.payment.v5.obf.min.js    # v5 obfuscated + minified
  zenpay.payment.v6.js            # v6 plain (IIFE)
  zenpay.payment.v6.min.js        # v6 minified (IIFE)
  zenpay.payment.v6.obf.min.js    # v6 obfuscated + minified
  zenpay.payment.v6.mjs           # v6 ESM module (named export: zpPayment)
  types/
    v6/
      zenpay.payment.v6.d.ts      # v6 public declarations
      types.d.ts                  # v6 type re-exports (includes ZpTheme)
      constants.d.ts
    shared/
      types.d.ts                  # shared option/result types

v4 and v5 are IIFE-only. Each file self-registers on window.zpPayment (and $.zpPayment if jQuery is detected). v6 ships both IIFE (for CDN / <script> tags) and ESM (.mjs with named export for import { zpPayment }); both side-effect-register the globals for backward compat.


Test Suite Structure

tests/
  unit/                         # v3 Node-environment tests (14 files)
  dom/                          # v3 JSDOM tests (1 file)
  v4/                           # v4 tests (12 files)
  v5/                           # v5 tests (13 files)
  v6/                           # v6 tests (14 files, incl. theme.v6.test.ts)
  helpers/
    plugin-loader.js            # VM/eval loaders for v3 (V8 coverage compatible)
    unit-browser-harness.js     # JSDOM harness for v3 DOM tests
    v4-dom-harness.ts           # Shared harness for v4 tests
    options.js                  # Canonical valid options baseline
    fingerprint.js              # Fingerprint generation utility
  e2e/                          # Playwright live tests (env-gated)
    fixtures/                   # HTML harness pages (4 variants)
    support/                    # Static server + visual masking CSS

tests/v5/v5-dom-harness.ts and tests/v6/v6-dom-harness.ts are co-located with their respective test suites (not in helpers/).

v3 test helpers

plugin-loader.js provides two loading strategies:

  • loadPluginInVm — compiles via Module._compile so Vitest V8 coverage can instrument the source
  • loadPluginInBrowserWindow — evaluates via window.eval for JSDOM browser-like tests

v4/v5/v6 test pattern

Tests import the TypeScript source directly. There is no VM loader. The shared harness (setupV4Harness / setupV5Harness / setupV6Harness) resets modules between tests and configures window.jQuery and window.bootstrap mocks as needed.


E2E Tests

Live E2E tests require environment variables:

export ZENPAY_HPP_BASE_URL=https://payuat.travelpay.com.au
export ZENPAY_MERCHANT_CODE=1337
export ZENPAY_API_KEY=your-api-key
export ZENPAY_USER_NAME=your-username
export ZENPAY_PASSWORD=your-password

bun run test:e2e

Three Playwright projects run against the live HPP:

| Project | Description | |---------|-------------| | hpp.live | Smoke flow — open modal, verify iframe loads | | harness-matrix.live | Runs all four fixture harnesses (jQuery+BS, jQuery only, BS only, neither) | | v3-v4.compare.live | Side-by-side v3 vs v4 behavioral comparison with screenshots |

Reports and screenshots go to reports/playwright/runs/{runId}/.


Repository Structure

src/
  v3/   zenpay.payment.bs5.js   ← frozen production source
  v4/   zenpay.payment.v4.ts    ← parity port
        types.ts
  v5/   zenpay.payment.v5.ts    ← current stable release
        types.ts
        constants.ts
        baseline.css
  v6/   zenpay.payment.v6.ts    ← v5 + opt-in theming + typed ESM export
        types.ts                    (re-exports shared types + adds ZpTheme)
        constants.ts
        baseline.css                (CSS vars + dark/auto theme blocks)
        css.d.ts
  shared/
        types.ts
scripts/
  build.ts                      ← esbuild pipeline (IIFE, minify, obfuscate, ESM)
  deploy-local.ts               ← local CDN copy (hostname-gated)
tsconfig.json                   ← base TS config (typecheck only)
tsconfig.v6.d.json              ← v6 declaration emit → dist/types/
docs/
  adr/                          ← Architecture Decision Records
.github/
  bugs/                         ← known bug reports (001-005)
  workflows/
    ci.yml                      ← CI: lint, typecheck, jscpd, knip, tests, build, Snyk

License

UNLICENSED — proprietary. Contact [email protected].