@final-commerce/common
v2.0.5
Published
Shared utilities, types, constants, and engineering governance configs for the Final Commerce platform.
Downloads
1,721
Readme
@final-commerce/common
Shared utilities, types, and constants for Final Commerce applications. This package provides framework-agnostic functionality that works across both frontend (React, Vue, etc.) and backend (Node.js, NestJS) environments.
Installation
npm install @final-commerce/commonImports
Everything is re-exported from the package root:
import { CurrencyCode, toMinorUnits, formatCurrency, Amount } from '@final-commerce/common';Sub-path imports also work:
import { toMinorUnits } from '@final-commerce/common/dist/utils/currency.util';
import { CurrencyCode } from '@final-commerce/common/dist/enums';Enums
CurrencyCode
ISO 4217 currency codes. 41 currencies across three decimal groups:
| Decimal Places | Currencies | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | 2 (standard) | USD, EUR, GBP, CAD, AUD, NZD, CHF, CNY, INR, MXN, BRL, ZAR, SGD, HKD, SEK, NOK, DKK, PLN, THB, MYR, PHP, IDR, AED, SAR, ILS, TRY, RUB | | 0 (zero-decimal) | JPY, KRW, VND, CLP, ISK, HUF, TWD | | 3 (three-decimal) | KWD, BHD, OMR, JOD, TND, LYD, IQD |
Interfaces
Amount
Represents a monetary value stored in the database.
{ amount: 3122, currency: 'USD', minorUnits: 2 } // = $31.22| Field | Type | Description |
| ------------ | -------------- | --------------------------------- |
| amount | number | Value in minor units (e.g. cents) |
| currency | CurrencyCode | ISO 4217 code |
| minorUnits | number | Decimal places (2, 0, or 3) |
CurrencyConfig
| Currency | Minor Units | Symbol | Example | | -------- | ----------- | ------ | -------- | | USD | 2 | $ | $10.50 | | EUR | 2 | € | €10.50 | | GBP | 2 | £ | £10.50 | | JPY | 0 | ¥ | ¥1000 | | KWD | 3 | KD | KD10.500 |
| Field | Type | Description |
| ---------------- | ---------------------- | ------------------------------------ |
| minorUnits | number | Decimal places |
| symbol | string | Display symbol ($, €, ¥, etc.) |
| symbolPosition | 'prefix' \| 'suffix' | Where the symbol goes |
Utility Functions
Conversion
| Function | In | Out | What it does |
| ---------------------------------------------- | ------------------ | ------ | ------------------------------------------------------------ |
| toMinorUnits(amount, currency) | (10.50, 'USD') | 1050 | Major to minor units |
| fromMinorUnits(minorAmount, currency) | (1050, 'USD') | 10.5 | Minor to major units |
| stringifyMinorUnits(minorAmount, minorUnits) | (1050, 2) | 10.5 | Minor to major using decimal count directly |
| parseAmountToMinorUnits(str, currency) | ('10.50', 'USD') | 1050 | Parse string input to minor units. Returns null on failure |
Formatting
| Function | In | Out | What it does |
| --------------------------------------------------- | --------------- | ---------- | ----------------------------------------------------------------------------------------------- |
| formatCurrency(minorAmount, currency, options?) | (1050, 'USD') | '$10.50' | Display string with symbol and grouping |
| formatMinorUnitsToString(minorAmount, minorUnits) | (1050, 2) | '10.5' | Plain decimal string (no symbol, no trailing zeros). Useful for API payloads (e.g. WooCommerce) |
formatCurrency options:
includeSymbol(default:true) — include currency symboluseGrouping(default:true) — thousands separators
Arithmetic
All inputs and outputs are in minor units (integers).
| Function | Example | Result |
| ------------------------------------ | ------------- | ------ |
| addAmounts(a, b) | (1050, 250) | 1300 |
| subtractAmounts(a, b) | (1050, 250) | 800 |
| multiplyAmount(amount, multiplier) | (1050, 2) | 2100 |
| divideAmount(amount, divisor) | (1050, 2) | 525 |
| calculatePercentage(amount, pct) | (10000, 15) | 1500 |
divideAmount throws on division by zero. calculatePercentage takes percentage as a whole number (15 = 15%, not 0.15).
Config / Validation
| Function | What it does |
| ---------------------------------- | --------------------------------------------------------------------------------------------- |
| getCurrencyConfig(currency) | Returns CurrencyConfig for a code. Falls back to 2-decimal default for unknown currencies |
| getMinorUnitMultiplier(currency) | Returns 10^minorUnits (100 for USD, 1 for JPY, 1000 for KWD) |
| getMinorUnits(currency) | Returns decimal place count for a currency |
| isSupportedCurrency(currency) | true if the currency has explicit config |
| parseCurrencyCode(value) | Validates a raw string is a valid CurrencyCode. Throws with supported codes list if invalid |
Amount Object Helpers
Used in BuilderHub for converting between user input and the Amount storage format.
| Function | Example | Result |
| ------------------------------- | ---------------------------------------------------- | -------------------------------------------------- |
| createAmount(value, currency) | ('31.22', 'USD') | { amount: 3122, currency: 'USD', minorUnits: 2 } |
| amountToString(amount) | ({ amount: 3122, currency: 'USD', minorUnits: 2 }) | '31.22' |
createAmount accepts string | number | null | undefined. Returns undefined for null, undefined, empty string, or NaN input.
amountToString returns '' for null/undefined input.
Constants
CURRENCY_CONFIG — a Record<CurrencyCode | string, CurrencyConfig> mapping all 41 currencies to their config (symbol, decimal places, symbol position).
Local Development
npm install
npm run build # build with tsup (CJS + ESM + types → dist/)
npm run dev # watch mode — rebuilds on file changes
npm test # vitest in watch mode
npm run test:run # single test run
npm run test:ui # vitest UI
npm run test:coverageLink locally to another project
Use npm link to test changes in a consuming project without publishing:
# 1. In this package (common/) — build first so dist/ is up to date
npm run build
npm link
# 2. In the consuming project (e.g. hub-api/) — clear node_modules to avoid stale/duplicate copies
rm -rf node_modules/@final-commerce/common
npm link @final-commerce/common
# 3. Verify the symlink points to your local copy
ls -la node_modules/@final-commerce/common
# Should show a symlink → /path/to/common
# 4. When done, unlink and restore the published version
npm unlink @final-commerce/common # in consumer
npm install # reinstall published version
npm unlink # in common/If you change source files in common, run
npm run buildagain (or usenpm run devfor watch mode). The symlink means the consumer always reads from common'sdist/, so it picks up new builds immediately.
Quick verification with node -p
After building, verify exports directly from the terminal:
# Check the package loads
node -p "require('./dist/index.js')"
# Test a conversion
node -p "const c = require('./dist/index.js'); c.toMinorUnits(10.50, 'USD')"
# → 1050
# Test formatting
node -p "const c = require('./dist/index.js'); c.formatCurrency(1050, 'USD')"
# → $10.50
# Test zero-decimal currency
node -p "const c = require('./dist/index.js'); c.toMinorUnits(1000, 'JPY')"
# → 1000
# Test three-decimal currency
node -p "const c = require('./dist/index.js'); c.toMinorUnits(10.5, 'KWD')"
# → 10500
# Test Amount helpers
node -p "const c = require('./dist/index.js'); c.createAmount('31.22', 'USD')"
# → { amount: 3122, currency: 'USD', minorUnits: 2 }
node -p "const c = require('./dist/index.js'); c.amountToString({ amount: 3122, currency: 'USD', minorUnits: 2 })"
# → 31.22
# List all exported keys
node -p "Object.keys(require('./dist/index.js'))"Verify from a linked project
After npm link, verify the link works in the consuming project:
# In the consuming project directory
node -p "require('@final-commerce/common')"
node -p "const c = require('@final-commerce/common'); c.formatCurrency(2500, 'EUR')"
# → €25.00License
Private — Final Commerce internal use only.
