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

@baraka-team/pos-domain

v0.2.0

Published

Shared POS pricing and payment calculations for the monolith, the branch store agent and the POS client

Readme

@baraka-team/pos-domain

The POS pricing and payment calculations, in one place, so the monolith, the branch store agent and the POS client all compute the same total from the same version.

This package exists because @iztech-baraka/baraka_common pulls in express, winston and axios middleware. Importing it into a browser bundle or into the Bun sidecar that runs on a counter PC drags server code along with it. The calculations therefore live here instead.

What is in it

| Area | Entry points | |---|---| | Money arithmetic | add, subtract, multiply, divide, applyDiscount, applyCharge, fixedToPercentage | | Rounding | roundMoneyCustom, applyShopRounding, wasPriceRounded | | Line breakdown | calculateLineBreakdown | | Order breakdown | calculateOrderBreakdown | | Discount and promotion engine | resolveDiscounts, resolveDiscountLifecycle, buildDiscountLifecycleFilter | | Tender allocation | allocateTenders, allocateTenderTotals, sumCardTenders, sumNonCashTenders | | Payment status | determinePaidStatus, calculatePaymentTotalFromTenders, appliedPaymentAmount, paymentCoverageRatio, calculateRemainingFromPayments | | Partial-payment slicing | calculatePaymentBreakdown, calculatePaymentRoundedPrice, calculateUnroundedPaymentDue |

The rules it encodes

These are the behaviours the package is pinned to. They are deliberate, they are what the monolith does today, and a change to any of them is a breaking release.

subtract never goes below zero. Every money subtraction clamps at zero, so a discount larger than the price yields a free line rather than a negative one.

Every operation rounds to the currency scale, half up. JOD carries three decimals, everything else two. An unknown currency falls back to two.

Shop rounding is a separate rule from currency scale. roundMoneyCustom rounds to a whole unit with the break at .45, not .50 — 10.44 becomes 10, 10.45 becomes 11. It applies only when the shop has roundPrices on, which is why it is a separate call and not folded into the arithmetic.

A percentage service charge is plain arithmetic. (price * amount) / 100, without a Decimal pass and without rounding to the currency scale. This matches the monolith and is preserved deliberately.

Card and debt tenders allocate first and always at face value. A card tender is captured money and a debt tender is a recorded receivable; neither can ever be change. Only cash absorbs an overpayment. Counting part of a card or debt tender would drop the rest out of the drawer report, the ledger and the debtor's balance alike.

The last line absorbs the allocation remainder. When order-level amounts are spread across paid lines, each line takes its weighted share except the last, which takes whatever is left in the pool. That is what makes the line amounts sum exactly to the payment total instead of drifting by a rounding unit.

What it does not do

It does not mutate what you pass it. calculateOrderBreakdown returns the breakdown, the computed price and the resolved service and delivery costs; the caller writes them onto its own entities. A serviceCost of null means the order's saved service cost stands — a dine-in order the branch charge did not price — and the caller leaves its own value untouched. The monolith's calculateAndSetTotalOrderPrice mutates the order in place, which is why the adapter, not this package, is where that assignment belongs.

It does not read ambient context. The monolith reads roundPrices from the request context and the dine-in service charge from branch settings. Both arrive here as explicit arguments. This is the seam that makes the same code runnable on a branch agent that has no request context at all.

It does not resolve the catalog. A line arrives with its unit price and its addon prices already resolved. Looking up an item variant, falling back to a branch price, or naming an addon is the caller's job — the agent does it from its local mirror, the monolith from the database.

It does not evaluate promotions as part of the order breakdown. Promotions are computed separately (resolveDiscounts) and handed to calculateOrderBreakdown as an input, so the order assembly stays synchronous and pure.

Types

Currency is a type parameter, not a fixed enum. Money<C> carries whatever string type the caller uses, so the monolith's Currency enum flows through add, subtract and the rest unchanged and comes back out the same type. The package's own Currency, MoneyType, DiscountType and the rest are const objects with a matching union type, so an enum member from a consumer assigns to them without a cast.

Structural *Like types (PaymentLike, PaymentOrderLike, TenderLike) are satisfied by the monolith's entities as they are, so the adapter passes an entity straight in.

Dependencies

One: decimal.js, pinned exactly. It has no dependencies of its own, ships ESM and CJS, and runs in the browser.

This is a deliberate deviation from decision D21's "zero runtime dependencies". The reason D21 gave for a new package was that baraka_common drags server code into the browser and the agent, and decimal.js does not. Reimplementing decimal arithmetic to satisfy the letter of the rule would put a hand-written rounding routine underneath every price in the system, for no gain — the monolith already depends on this exact version, and bit-exact parity with it is worth more than a dependency count.

types is empty in tsconfig.json, so neither Node nor DOM globals can be used in src/. That constraint is compiler-enforced, not a convention.

Versioning

POS_DOMAIN_VERSION is exported so a pushed SALE_OPENED event can record which rules priced an offline sale. A pricing change ships as a release here first, then the monolith bumps, then the agent bumps. The server compares the agent's totals against its own recomputation and stores a mismatch flag rather than rejecting the sale.

POS_DOMAIN_VERSION in src/version.ts must be bumped with the package.json version; tests/version.spec.ts fails if they drift.

Parity with the monolith

The package is a port of the monolith's pricing code, not a reimplementation. Parity was verified before release:

  • 415,200 generated comparisons of the money and tender functions against the monolith's own function bodies, across four currencies, tie cases and fuzzed amounts — zero mismatches.
  • The monolith's 53 discount-engine tests pass against this package unmodified (tests/discountEngine.parity.spec.ts).
  • The monolith's partial-payment allocation tests pass against this package unmodified (tests/paymentBreakdown.parity.spec.ts).

Development

npm install
npm run typecheck
npm test
npm run build

Publishing

Releases are published by hand from a maintainer's machine. There is no CI release job, so prepublishOnly is the gate: it runs typecheck, lint, the full test suite and the build, and npm publish aborts if any of them fails.

Publishing is done by the baraka-team npm account, which owns the @baraka-team scope. Check you are on the right one before publishing — the older @iztech-baraka scope still owns baraka_common and is a different account:

npm whoami   # expect: baraka-team

To let a teammate publish, add them to the scope (npm org set baraka-team <user> developer) or to this package alone (npm owner add <user> @baraka-team/pos-domain).

First publish

npm login
npm publish --access public

--access public is required on a scoped package's first publish. Without it npm treats the package as restricted, which needs a paid plan and fails with a 402.

If the account has 2FA enabled on writes, npm prompts for a one-time password. Pass it inline instead with --otp=<code> if you prefer.

Later releases

npm version patch -m "chore(release): %s"
npm publish
git push --follow-tags

Use minor for a new capability and major for a change to any of the rules in The rules it encodes — those are behavioural contracts that the monolith, the branch agent and the client all depend on matching.

Bump POS_DOMAIN_VERSION in src/version.ts to match. npm version does not touch it, and tests/version.spec.ts fails when the two drift. That is on purpose: the constant is what a replayed SALE_OPENED records as the rules that priced an offline sale, so a stale one silently misattributes a price.

What ships

Eight files, about 72 kB packed: dist/ (ESM, CJS, both declaration files and source maps), README.md and package.json. No source, no tests. Check before publishing with:

npm pack --dry-run