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/zp-hcp

v0.1.10

Published

ZenPay Hosted Checkout Plugin — zero-dependency modal/redirect payment integration with optional jQuery and Bootstrap backward compatibility

Readme

ZenPay HCP Plugin

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

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

CI

Install

bun add @ianmenethil/zp-hcp
// Full plugin (modal + all features)
import { zpPayment } from '@ianmenethil/zp-hcp';

// Client-safe utilities — tree-shakeable subpath (browser or server, no secrets, no DOM)
import { createZpTimestamp, createZpMupid, ZpPaymentStatus, isZpPaymentSuccessful } from '@ianmenethil/zp-hcp/client';

// Server-only utilities (require the merchant password — never ship to the browser)
import { createZpFingerprint, verifyZpValidationCode, createSha3_512 } from '@ianmenethil/zp-hcp/server';

Full import/export map (main vs /client vs /server, types, session API, CDN): USAGE.md — Package entries.

Package contents

@ianmenethil/zp-hcp/
├── dist/
│   ├── npm/
│   │   ├── index.mjs          ← ESM entry (browser, es2022)
│   │   ├── index.cjs          ← CJS entry (Node 22+)
│   │   ├── index.d.ts         ← public types
│   │   ├── server.mjs         ← server-only utilities (ESM)
│   │   ├── server.cjs         ← server-only utilities (CJS)
│   │   ├── server.d.ts        ← server utility types
│   │   ├── client.mjs         ← client-safe utilities (ESM)
│   │   ├── client.cjs         ← client-safe utilities (CJS)
│   │   └── client.d.ts        ← client utility types
│   └── cdn/
│       ├── v6/
│       │   ├── zp.hcp.js              ← IIFE (unminified)
│       │   ├── zp.hcp.min.js          ← IIFE (minified)
│       │   ├── zp.hcp.obf.js          ← IIFE (minified + obfuscated)
│       │   ├── zp.hcp.esm.js          ← ESM (for `import()`)
│       │   └── zp.hcp.manifest.json   ← SRI integrity hashes
│       ├── v5/
│       │   ├── zenpay.payment.v5.js
│       │   ├── zenpay.payment.v5.min.js
│       │   ├── zenpay.payment.v5.obf.min.js
│       │   └── manifest.json
│       └── v4/
│           ├── zenpay.payment.v4.js
│           ├── zenpay.payment.v4.min.js
│           ├── zenpay.payment.v4.obf.min.js
│           └── manifest.json
├── README.md
└── LICENSE

CDN

CDN files are available from two sources — jsDelivr (automatic from each npm publish) and the self-hosted CDN at cdn.zenithpayments.support (deployed on every build).

| File | jsDelivr | Self-hosted | |------|----------|-------------| | v6 IIFE (minified) | @ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.min.js | hcp/v6/zp.hcp.min.js | | v6 IIFE (unminified) | @ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.js | hcp/v6/zp.hcp.js | | v6 IIFE (obfuscated) | @ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.obf.js | hcp/v6/zp.hcp.obf.js | | v6 ESM | @ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.esm.js | hcp/v6/zp.hcp.esm.js | | v6 Manifest | @ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.manifest.json | hcp/v6/zp.hcp.manifest.json | | v5 IIFE (minified) | @ianmenethil/zp-hcp/dist/cdn/v5/zenpay.payment.v5.min.js | hcp/v5/zenpay.payment.v5.min.js | | v5 IIFE (unminified) | @ianmenethil/zp-hcp/dist/cdn/v5/zenpay.payment.v5.js | hcp/v5/zenpay.payment.v5.js | | v5 IIFE (obfuscated) | @ianmenethil/zp-hcp/dist/cdn/v5/zenpay.payment.v5.obf.min.js | hcp/v5/zenpay.payment.v5.obf.min.js | | v4 IIFE (minified) | @ianmenethil/zp-hcp/dist/cdn/v4/zenpay.payment.v4.min.js | hcp/v4/zenpay.payment.v4.min.js | | v4 IIFE (unminified) | @ianmenethil/zp-hcp/dist/cdn/v4/zenpay.payment.v4.js | hcp/v4/zenpay.payment.v4.js | | v4 IIFE (obfuscated) | @ianmenethil/zp-hcp/dist/cdn/v4/zenpay.payment.v4.obf.min.js | hcp/v4/zenpay.payment.v4.obf.min.js |

  • jsDelivr base: https://cdn.jsdelivr.net/npm/ — drop the version tag for latest, or pin with @5.
  • Self-hosted base: https://cdn.zenithpayments.support/latest/ always points to the most recent build; versioned folders are created on bun run release.

CDN usage

<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.min.js"></script>

<!-- Self-hosted -->
<script src="https://cdn.zenithpayments.support/hcp/v6/zp.hcp.min.js"></script>

<script>
  var payment = window.zpPayment({
    url: 'https://payuat.travelpay.com.au/online/v5',
    apiKey: 'YOUR_API_KEY',
    fingerprint: '...',
    theme: 'auto',
  });
  payment.open();
</script>

ESM import (v6)

import { zpPayment, type ZpPaymentOptions, type ZpTheme } from '@ianmenethil/zp-hcp';

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

Tree-shakeable utilities (v6)

// Client-safe (browser or server)
import { createZpTimestamp, createZpMupid, ZpPaymentStatus, isZpPaymentSuccessful } from '@ianmenethil/zp-hcp/client';
// Server-only (requires the merchant password)
import { createZpFingerprint } from '@ianmenethil/zp-hcp/server';

const timestamp = createZpTimestamp();     // "2026-05-27T14:30:00"
const mupid = createZpMupid();             // base64(UUID-Timestamp)
const fp = createZpFingerprint({
  apiKey: "...", username: "...", password: "...",
  mode: 0, paymentAmount: "1.00",
  merchantUniquePaymentId: mupid, timestamp,
}).fingerprint;

CJS require (v6)

const { zpPayment } = require('@ianmenethil/zp-hcp');

The main plugin requires a browser DOM. Client utility functions (createZpTimestamp, createZpMupid, ZpPaymentStatus, isZpPaymentSuccessful) work in any environment with crypto.randomUUID() and btoa(). Fingerprint functions (createZpFingerprint, verifyZpValidationCode) are server-side — Node 19+, Bun, Deno.


Subresource Integrity (SRI)

A manifest with SHA-384 and SHA-256 hashes is published per version at dist/cdn/{v4,v5,v6}/manifest.json in the npm package. Use it to pin CDN scripts with integrity attributes:

<script src="https://cdn.jsdelivr.net/npm/@ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.min.js"
        integrity="sha384-..."
        crossorigin="anonymous"></script>

SRI is optional — all existing CDN URLs continue to work without it.


Test Status

All tests passing on v6 (245 tests, 20 files).

| 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:v6 | 20 | 245 | Full v6 test suite |

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.

bun run test runs unit + dom + v6 (test:vitest). v4 and v5 tests are run directly via vitest CLI (no npm script alias).

Coverage

v6 coverage is generated automatically with bun run test:v6 and output to coverage/v6/.

| Version | Statements | Branches | Functions | Lines | |---------|-----------|----------|-----------|-------| | v6 | 87.66% | 78.81% | 92.50% | 89.75% |


Plugin Versions

Version docs: v3→v4 · v4→v5 · v5→v6 — visual references (diagrams + tables).

This repository ships one plugin in four versions. All produce the same end-user payment experience when using the same options on a jQuery + Bootstrap page (v3/v4 parity path).

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.jsdelivr.net/npm/@ianmenethil/zp-hcp/dist/cdn/v5/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. Brand palette: light ink #1C1C1C / accent #D71F26; dark surface #161616 / accent #E83239. "auto" follows OS prefers-color-scheme.
  • CSS custom properties — Integrators can override any --zp-* variable in their own stylesheet. See the CSS Variables Reference table below for the full token list with light and dark defaults.
  • 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/zp-hcp" with full IDE autocomplete.
  • In-page error toast — plugin validation failures show a dismissible banner instead of v3 alert().
  • onPluginOpen callback — fires when the HCP iframe finishes loading (spinner hides). v6 only; not fired at modal shell show.
  • @starting-style entry animation — modal slides down + fades in on supported browsers.
  • prefers-reduced-motion support — WCAG 2.2 AA compliance.
  • createZpTimestamp() — produces a slice-19 ISO 8601 timestamp (YYYY-MM-DDTHH:MM:SS) for HCP fingerprint parameters.
  • createZpMupid() — produces a base64-encoded MUPID (base64(UUID-Timestamp)) for idempotency.
  • ZpPaymentStatus + isZpPaymentSuccessful() — typed result-status codes; isZpPaymentSuccessful guards the 3-is-success / 1-is-error trap.
  • createSha3_512(input) — generic SHA3-512 hash of any arbitrary string. No transformation applied — input is hashed as-is. Exported from /server alongside the ZenPay-specific helpers.
  • createZpFingerprint() — server-side SHA3-512 fingerprint generator with per-field verification. Works in Node 19+, Bun, and Deno. Pass paymentAmount in dollars (hash uses cents); mode 2 hashes "0". Details: USAGE.md.
  • verifyZpValidationCode() — server-side callback verification. Hashes and compares (constant-time) the ValidationCode query parameter to authenticate HCP callbacks.
  • Tree-shakeable /client + /server importsimport { createZpTimestamp, createZpMupid, ZpPaymentStatus, isZpPaymentSuccessful } from '@ianmenethil/zp-hcp/client' and import { createZpFingerprint, verifyZpValidationCode } from '@ianmenethil/zp-hcp/server' without pulling in the full plugin bundle. Client utilities are also exported from the main entry (@ianmenethil/zp-hcp / zp.hcp.esm.js) for CDN ESM consumers already loading the full bundle.

Usage — CDN / UMD (unchanged from v5):

<script src="https://cdn.jsdelivr.net/npm/@ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.obf.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/zp-hcp";

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/npm/index.d.ts in the npm package.


CSS Variables Reference

The following CSS custom properties are defined in v6's baseline stylesheet. Integrators can override any of them in their own stylesheet to customize the modal appearance without opting into theme.

| Variable | Light default | Dark default (data-zp-theme="dark") | Applies to | |----------|--------------|---------------------------------------|------------| | --zp-modal-bg | #fff | #161616 | Modal content background | | --zp-modal-fg | inherit | #f4f4f4 | Modal content text color | | --zp-modal-border | rgba(0, 0, 0, 0.2) | #262626 | Modal content border, close button border | | --zp-modal-header-border | #dee2e6 / #e5e5e5 | #262626 | Modal header bottom border | | --zp-modal-muted | #6b7280 | #8e8e8e | Close button active background, hover border | | --zp-accent | #0066cc (unthemed) · #D71F26 (theme: light) | #E83239 | Button hover / accent | | --zp-backdrop-bg | rgba(0, 0, 0, 0.5) | rgba(0, 0, 0, 0.7) | Modal backdrop overlay | | --zp-btn-fg | inherit | #f3f4f6 | Button text color | | --zp-font-family | System font stack | System font stack | Modal typography | | --zp-radius | 8px | 8px | Modal content and dialog border radius | | --zp-shadow | 0 10px 30px -10px rgba(0, 0, 0, 0.25) | Same | Modal content box shadow | | --zp-ease | cubic-bezier(0.4, 0, 0.2, 1) | Same | All modal/backdrop transitions | | --zp-modal-width | clamp(500px, 90vw, 900px) | Same | Payment dialog width at ≥768px | | --zp-modal-max-width | 900px | Same | Payment dialog max-width at ≥768px |

Three @property registrations (--zp-accent, --zp-modal-bg, --zp-radius) make these tokens smoothly interpolateable for CSS transitions (e.g. transition: --zp-accent 200ms). No-op on browsers without @property support.


Quick Start

// In browser console or inline script — no build step required
await import("https://cdn.jsdelivr.net/npm/@ianmenethil/zp-hcp/dist/cdn/v6/zp.hcp.obf.js");

// createZpTimestamp() and createZpMupid() are safe for client-side use —
// they involve no secrets. createZpFingerprint() should only be called
// server-side since it requires your merchant password.
const id         = createZpMupid();
const timestamp  = createZpTimestamp();

window.zpPayment({
  url:                    "https://payuat.travelpay.com.au/online/v5",
  merchantCode:           "YOUR_MERCHANT_CODE",
  apiKey:                 "YOUR_API_KEY",
  fingerprint:            "FROM_YOUR_SERVER",   // pre-computed by your backend (see USAGE.md#utilities)
  redirectUrl:            "https://your-site.com/payment/result",
  merchantUniquePaymentId: id,
  timestamp:              timestamp,
  displayMode:            0,
  mode:                   0,
  paymentAmount:          "1.00",
  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/zp-hcp" (also registers window globals) |


Options Reference

Canonical reference: USAGE.mdimport/export map, full zpPayment payload, utility behaviour, fingerprint workflow.

Options merge with jQuery $.extend semantics (undefined does not overwrite defaults). Keys that are functions, theme, or lifecycle callbacks stay off the Authorise URL; other unknown keys are forwarded as query parameters (v3 parity).


Display Modes

displayMode=0 — Modal popup

Opens the hosted checkout page in a full-screen iframe modal. Call .open() on the returned instance.

displayMode=1 — Redirect URL

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


Instance API

zpPayment(options) returns an instance with .open() and .close() methods.

const payment = window.zpPayment(options);
payment.open();   // Opens the payment modal
payment.close();  // Closes and removes the modal

| Method | Returns | Description | |--------|---------|-------------| | .open() | void | Opens the payment modal. Validates options, creates the iframe, injects baseline CSS, and shows the modal. Validation errors show an in-page toast (not alert()). For displayMode=1, returns void — use .init() (legacy) for redirect URL payload | | .close() | void | Finds the .modal-payment element and hides/removes it. Fires onPluginClose callback, destroys Apple Pay plugin, and cleans up options |

Legacy .init() (v3 only)

.init() is the original v3 method. It is retained for backward compatibility only. New integrations should use .open() and .close().

| Method | Returns | Description | |--------|---------|-------------| | .init() | ZpUrlResult \| undefined | Legacy v3 entry point. Routes based on displayMode: 0 → opens modal, 1 → returns { isSuccess, url, height, width } without showing UI |

ZpUrlResult

| Field | Type | Description | |-------|------|-------------| | isSuccess | boolean | Whether URL generation succeeded | | url | string? | Full HCP URL with query parameters (success) | | height | string? | Recommended iframe min-height, e.g. "725px" (success) | | width | string? | Recommended iframe width, e.g. "600px" (success) | | message | string? | Human-readable error message (failure) |


Utility Functions

Canonical reference: USAGE.md — Package entries (what each path exports) and Utilities (behaviour, verification rules, fingerprint workflow).

Quick imports (also shown under Install):

import { createZpTimestamp, createZpMupid, ZpPaymentStatus, isZpPaymentSuccessful } from '@ianmenethil/zp-hcp/client';
import { createZpFingerprint, verifyZpValidationCode, createSha3_512 } from '@ianmenethil/zp-hcp/server';

/client is safe in the browser; /server requires the merchant password and must never ship to client bundles.


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 | All Vitest tests (unit + dom + v6) | | bun run test:unit | v3 unit tests (Node environment) | | bun run test:dom | v3 DOM tests (JSDOM) | | bun run test:v6 | v6 test suite + coverage → coverage/v6/ | | bun run test:e2e | Playwright live E2E (requires env vars) | | bun run lint | ESLint flat config | | bun run typecheck | TypeScript type check (tsc --noEmit) | | bun run check | Full quality gate (lint + typecheck + jscpd + knip + test:v6) | | bun run build | check + bundle all versions + declarations + manifest + validate:dist | | bun run build:v6 | Build v6 only (IIFE + ESM + CJS + declarations) | | bun run build:types:v6 | Emit v6 .d.ts declarations via tsc -p tsconfig.build.json | | bun run release | build + npm publish + CDN deploy |

To run v4 or v5 tests directly (no npm script — use vitest CLI):

bunx vitest run tests/v4 --config vitest.config.ts
bunx vitest run tests/v5 --config vitest.config.ts

The build script accepts version flags for targeted builds:

bun run scripts/build.ts --v4          # v4 only
bun run scripts/build.ts --v5          # v5 only
bun run scripts/build.ts --v6 --esm    # v6 ESM only

Build Outputs

dist/
  npm/
    index.mjs                      # v6 ESM entry (named export: zpPayment)
    index.cjs                      # v6 CJS entry
    index.d.ts                     # v6 public types entry (re-exports zenpay.payment.v6)
    server.mjs                     # /server utilities (ESM) — createZpFingerprint, verifyZpValidationCode, createSha3_512
    server.cjs                     # /server utilities (CJS)
    server.d.ts                    # /server utility types (auto-emitted from src/v6/server.ts)
    client.mjs                     # /client utilities (ESM) — createZpTimestamp, createZpMupid, payment-status
    client.cjs                     # /client utilities (CJS)
    client.d.ts                    # /client utility types (auto-emitted from src/v6/client.ts)
    zenpay.payment.v6.d.ts         # auto-emitted from src/v6/zenpay.payment.v6.ts
    core/                          # auto-emitted: types, constants, zp-payment, defaults, …
    payment/                       # auto-emitted: open-payment, close-payment, generate-url
    modal/                         # auto-emitted: modal, iframe-load-handler, import-script
    compat/                        # auto-emitted: jquery-shim
  cdn/
    v6/
      zp.hcp.js                    # v6 plain IIFE
      zp.hcp.min.js                # v6 minified IIFE
      zp.hcp.obf.js                # v6 obfuscated + minified
      manifest.json                # SRI integrity hashes
    v5/
      zenpay.payment.v5.js         # v5 plain IIFE
      zenpay.payment.v5.min.js     # v5 minified IIFE
      zenpay.payment.v5.obf.min.js # v5 obfuscated + minified
      manifest.json
    v4/
      zenpay.payment.v4.js         # v4 plain IIFE
      zenpay.payment.v4.min.js     # v4 minified IIFE
      zenpay.payment.v4.obf.min.js # v4 obfuscated + minified
      manifest.json

v4 and v5 are IIFE-only. Each file self-registers on window.zpPayment (and $.zpPayment if jQuery is detected). v6 ships IIFE (for CDN / <script> tags), ESM (dist/npm/index.mjs with named export), and CJS (dist/npm/index.cjs); all three side-effect-register the globals for backward compat. Types are auto-emitted by tsc -p tsconfig.build.json from src/v6/zenpay.payment.v6.ts (the single source of truth) into dist/npm/, with dist/npm/index.d.ts re-exporting the entry file's curated public API.


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 (20 files, incl. create-mupid.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_HCP_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 HCP:

| Project | Description | |---------|-------------| | hcp.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

v6 source layout

| Directory | File | Purpose | |-----------|------|---------| | v6/ | zenpay.payment.v6.ts | Main plugin entry — @ianmenethil/zp-hcp; also re-exports all /client utilities for CDN ESM consumers | | | server.ts | Server-only entry — @ianmenethil/zp-hcp/servercreateSha3_512 + createZpFingerprint + verifyZpValidationCode | | | client.ts | npm /client entry (thin re-exports) | | | client/ | types, timestamp-mupid, amount-to-cents, payment-status | | | cdn.ts | IIFE entry for CDN <script> tags | | v6/core/ | types.ts | All public types (ZpMode, ZpTheme, ZpPaymentOptions, …) | | | constants.ts | Error messages, defaults, DOM selectors, URL params | | | zp-payment.ts | ZpPayment class — constructor + open/init/close | | | init-plugin.ts | init() routing — modal vs redirect | | | defaults.ts | 16 default option values | | | extend.ts | zpExtend — jQuery $.extend-compatible shallow merge | | | option-normalizers.ts | getPValue / getPBoolValue / getKeyValue | | v6/payment/ | open-payment.ts | open() flow — validation, modal DOM, Apple Pay, theming | | | close-payment.ts | close() teardown — modal removal + cleanup | | | generate-url.ts | URL construction + parameter encoding | | v6/modal/ | modal.ts | Show/hide, backdrop, baseline CSS injection, brand fonts | | | baseline.css | CSS custom properties + light/dark/auto theme blocks | | | css.d.ts | Module declaration for .css imports | | | iframe-load-handler.ts | onPaymentPluginLoaded — spinner hide + Apple Pay init | | | import-script.ts | Dynamic <script> loader with dedup | | v6/compat/ | jquery-shim.ts | Minimal $ shim for Apple Pay UMD plugin compatibility | | scripts/ | build.ts | esbuild pipeline (IIFE, minify, obfuscate, ESM, CJS) | | | deploy-local.ts | Local CDN copy (hostname-gated) | | tests/ | unit/ dom/ v4/ v5/ v6/ e2e/ helpers/ | See Test Suite Structure | | (repo root) | V3-TO-V4.md V4-TO-V5.md V5-TO-V6.md | Version migration pair references | | docs/ | research/ | Research notes |

src/
  v3/   zenpay.payment.bs5.js   ← frozen production source (never edited)
  v4/   zenpay.payment.v4.ts    ← parity port
  v5/   zenpay.payment.v5.ts    ← stable (bug fixes, zero deps)
        types.ts                ← shared v4/v5 types
  v6/   zenpay.payment.v6.ts    ← active development
        cdn.ts                  ← IIFE entry
        server.ts               ← /server subpath
        client.ts               ← /client subpath
        core/                   ← types, constants, zp-payment, defaults, …
        payment/                ← open-payment, close-payment, generate-url
        modal/                  ← modal, baseline.css, iframe-load-handler, …
        compat/                 ← jquery-shim

Root-level config: tsconfig.json · tsconfig.build.json · eslint.config.ts · vitest.config.ts · knip.json · jscpd.json


License

MIT