@temboplus/afloat
v0.6.1
Published
A foundational library for Temboplus-Afloat projects.
Readme
@temboplus/afloat
Type-safe client library for the TemboPlus-Afloat API. Repository classes wrap each resource (wallets, payouts, beneficiaries, profile, team members, identity, auth) so consumers never talk to HTTP directly.
Quick Start
bun add @temboplus/afloat
# or: npm install @temboplus/afloatimport { AuthRepository, WalletRepository } from "@temboplus/afloat";
// 1. Log in. The returned User contains the token.
const authRepo = new AuthRepository();
const user = await authRepo.logIn("[email protected]", "password123");
// 2. Pass the token to any other repository.
const walletRepo = new WalletRepository({ token: user.token });
const [wallet] = await walletRepo.getWallets();Usage
afloat is session-agnostic — it does not own login state or export an auth singleton. Your application logs in, stores the token, and passes it into every authenticated repository.
const repo = new SomeRepository({
token: "user-auth-token",
root: "https://api.afloat.money/v1", // optional override
});Available repositories:
AuthRepository—logIn,updatePassword,getAccessListWalletRepository— wallets, balances, statementsPayoutRepository— create, approve, reject, list, countBeneficiaryRepository— create, edit, remove, lookupProfileRepository— current profileTeamMemberRepository— team members and rolesIdentityRepository— authenticated/login/meTradeRepository— P2P currency trades: create, list, look up by reference, convert, cancel
Trades
Sellers (profiles where profile.canTrade is true) create an offer and share its
reference. Any profile can look it up and convert it.
import { TradeRate, TradeRepository, tradeWalletsFor } from "@temboplus/afloat";
const tradeRepo = new TradeRepository({ token: user.token });
// Seller: sell 100 KES for 2,200 TZS, valid for two hours
TradeRate.fromAmounts(100, 2200); // 22, previews the rate the API will derive
const trade = await tradeRepo.create({
debitWallet: kesWallet,
creditWallet: tzsWallet,
sourceAmount: 100,
targetAmount: 2200,
expiresAt: new Date(Date.now() + 2 * 60 * 60 * 1000),
});
share(trade.reference); // e.g. "KSH-TZS-ZJCM052RBUCS"
// Buyer: look up the code, then convert
const offer = await tradeRepo.getByReference(code);
await tradeRepo.convert({
trade: offer,
debitWallet: tradeWalletsFor(wallets, offer.targetCurrency)[0],
creditWallet: tradeWalletsFor(wallets, offer.sourceCurrency)[0],
});Failures are APIErrors; branch on error.reason (TradeErrorReason.TRADE_EXPIRED,
INSUFFICIENT_BALANCE, TRADE_NOT_FOUND, ...). Only virtual wallets can trade.
Currency codes are ISO 4217 throughout: the API's KSH is exposed as KES.
Amounts sent to the server are plain numbers with up to 8 decimal places, never
Amounts. On a Trade, sourceAmount / targetAmount are Amounts for display
only, correct to two decimal places; sourceAmountValue / targetAmountValue
are the exact figures, and sourceAmountLabel / targetAmountLabel format them
with their currency (e.g. "TZS 66.37037034"). Show the labels wherever the buyer
confirms a conversion.
Permissions
The User returned by logIn carries the permission set:
import { Permissions, PayoutRepository } from "@temboplus/afloat";
if (user.can(Permissions.Payout.Create)) {
const payoutRepo = new PayoutRepository({ token: user.token });
await payoutRepo.pay(input);
}Server-side usage
Repositories work on the server too — extract the bearer token from the incoming request and pass it through:
import { WalletRepository } from "@temboplus/afloat";
app.get("/api/wallets", async (req, res) => {
const token = req.headers.authorization?.replace(/^Bearer\s+/i, "");
if (!token) return res.status(401).json({ error: "Unauthorized" });
const walletRepo = new WalletRepository({ token });
return res.json({ wallets: await walletRepo.getWallets() });
});Consumed By
- TemboPlus Afloat (Next.js frontend) — customer-facing app.
- TemboPlus Reports (NestJS backend) — Afloat-specific report generation.
Development
Bun for everything, Biome for lint+format, mise for the toolchain pin.
mise install # one-time: installs pinned Bun
bun install
bun run dev # rollup build in watch mode| Script | Does |
| --- | --- |
| bun run dev | Rollup build in watch mode |
| bun run build | Rollup build to dist/ (CJS + ESM + .d.ts) |
| bun run test | bun:test (passes with zero tests; smoke test only) |
| bun run lint | Biome check |
| bun run format | Biome auto-fix |
| bun run typecheck | tsc --noEmit |
Tag-driven releases via .github/workflows/release.yml — update CHANGELOG.md, bump package.json, push a vX.Y.Z tag.
License
MIT © TemboPlus
