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

@bevingh/money

v0.1.0

Published

Integer-pesewa conversions, validators, and formatting helpers for pesewa_end_to_end apps (not GHS-float migration).

Readme

@bevingh/money

Phase 3 / PR-12 — extracted. Pure integer-pesewa helpers for pesewa_end_to_end apps only. No Express adapter (pure_core).

Purpose

Integer-pesewa conversions, validators, and formatting helpers for pesewa_end_to_end apps (not GHS-float migration).

| Field | Value | |---|---| | surfaceShape | pure_core | | targetRuntime | typescript_esm | | extractionOrderHint | 2 | | dependsOnPackages | (none) | | status | extracted (implementation + tests) |

Deliberately narrow scope

This package encodes the standing rule: monetary values as integers in the smallest unit (pesewas) end-to-end, not only at a payment-API boundary (roomsplit docs/02-SCHEMA.md §8).

Permanent out-of-scope boundaries (do not “resolve and remove”)

These are not a temporary extraction checklist. They stay documented forever for this package:

| Boundary | Why | |---|---| | ghs_float_at_boundary (8 apps: bevin-events, conduit, payment-gatway, ussd-service, UVT, Academicx, imep-portal-api, Texify payment amounts) | Those apps store GHS floats and convert only at the provider edge. They need a convention migration before adopting @bevingh/money — this package is not a drop-in for them. | | Texify SMS credit balance | Product-specific credit units, not GHS/pesewas. Stays keep_project_specific. | | Accounting LedgerEntry Number amounts (conduit / payment-gatway) | Tax/P&L bookkeeping in major units — different convention from wallet pesewas (@bevingh/ledger / document-only accounting). | | Provider API call logic | Paystack/Moolre/etc. live in @bevingh/payments or apps — not here. |

Likely consumers today: roomsplit, Didipay, mirrly, maame, Bevin-Photos (pesewa_end_to_end cluster only).

Public API

| Export | Role | |---|---| | pesewasToGhs(pesewas) | Integer pesewas → "12.50" string (mirrly) | | ghsToPesewas(ghs) | GHS string or number → integer pesewas (Math.round(*100)) | | isPesewas(value, opts?) | Type guard: finite safe integer; non-negative by default | | assertPesewas(value, opts?) | Same, throws TypeError on failure | | formatPesewasAsGhs(pesewas, opts?) | Display helper, default "GH₵12.50" | | PesewasValidationOptions, FormatPesewasOptions | Types |

import {
  pesewasToGhs,
  ghsToPesewas,
  assertPesewas,
  formatPesewasAsGhs,
} from '@bevingh/money';

assertPesewas(1250);                    // 1250
pesewasToGhs(1250);                     // "12.50"
ghsToPesewas("12.50");                  // 1250
formatPesewasAsGhs(1250);               // "GH₵12.50"
formatPesewasAsGhs(1250, { symbol: 'GHS ' }); // "GHS 12.50" (Didipay USSD style)
assertPesewas(0);                       // ok (wallet default)
assertPesewas(1, { allowZero: false }); // roomsplit budget-style positive

Validation options

| Option | Default | Notes | |---|---|---| | allowNegative | false | Set true for signed deltas only | | allowZero | true | Set false for roomsplit .positive() budget fields |

Champion files (read-only references)

| Path | What was taken | |---|---| | mirrly moolre-utils.ts | Conversion pesewasToGhs / ghsToPesewas | | mirrly db.schema.ts | integer columns with // pesewas comments | | Didipay schema.prisma | Int // pesewas wallet/txn fields | | roomsplit User.js + profile.validators.js | budget_*_pesewas + .int() / .positive() | | roomsplit docs/02-SCHEMA.md | standing rule text + display example GH₵ |

Display formatting pattern also observed in Didipay ussd.service.ts / moolre.service.ts ((n/100).toFixed(2) + GHS label) — not listed as a formal champion file but used as the operational format source.

Tests

No champion unit tests existed (championTestPaths: "no tests found"). Package tests are new:

npm run test -w @bevingh/money
npm run build -w @bevingh/money

Coverage: round-trip conversion, non-integer rejection, NaN/Infinity/negative rejection, format zero / mid / large amounts.

Layout

src/index.ts       # pure core only (KD13: no adapters/)
test/money.test.ts

mustNotContain (verified)

| Constraint | Status | |---|---| | ghs_float_at_boundary domain models | OK — not present; boundary documented permanently | | SMS credit units (Texify) | OK | | accounting LedgerEntry Number amounts | OK | | provider API call logic | OK |