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

@temboplus/afloat

v0.2.0-beta.14

Published

A foundational library for Temboplus-Afloat projects.

Readme

@temboplus/afloat

A foundational JavaScript/TypeScript library for TemboPlus-Afloat projects, providing abstracted server communication, shared utilities, and standardized data models for consistent development.

Key Features

  • Abstracted Server Communication

    • Simplifies front-end development by abstracting all interactions with the server behind model-specific repositories
    • Consuming projects only need to interact with these repositories, decoupling them from the underlying API implementation
  • Authentication-Agnostic Repositories

    • The library does not own session state or export an auth singleton
    • Consuming applications log in, store the returned token, and pass that token to repositories
  • Data Models

    • Defines standardized data structures and interfaces for consistent data representation throughout the Afloat ecosystem
  • Cross-Environment Compatibility

    • Works seamlessly in both client-side and server-side environments

Usage

Login

Use AuthRepository.logIn(...) for the unauthenticated login request. The returned User contains the token that should be stored by your app and passed to other repositories.

import { AuthRepository } from "@temboplus/afloat";

try {
  const authRepo = new AuthRepository();
  const user = await authRepo.logIn("[email protected]", "password123");

  storeSession({
    token: user.token,
    user: user.toJSON(),
  });
} catch (error) {
  const message = error instanceof Error ? error.message : "Unknown error";
  console.error("Login failed:", message);
}

AuthRepository also has authenticated methods. Construct it with a token before calling those:

import { AuthRepository } from "@temboplus/afloat";

const authRepo = new AuthRepository({ token });

await authRepo.updatePassword("currentPassword", "newPassword");
const accessList = await authRepo.getAccessList();

Repository Usage

Authenticated repositories share the same construction shape:

const repo = new SomeRepository({
  token: "user-auth-token",
  root: "https://api.afloat.money/v1", // optional
});

Use this shape for:

  • WalletRepository
  • PayoutRepository
  • BeneficiaryRepository
  • ProfileRepository
  • TeamMemberRepository
  • IdentityRepository
  • AuthRepository when calling authenticated methods like updatePassword or getAccessList

The TypeScript constructors accept optional fields because the base repository supports a global token getter, but authenticated Afloat API calls still require a token. Passing { token } explicitly is the recommended and documented integration path.

Wallet Example

import { Permissions, WalletRepository } from "@temboplus/afloat";

const walletRepo = new WalletRepository({ token });
const [wallet] = await walletRepo.getWallets();

if (!wallet) {
  throw new Error("No wallet available");
}

if (user.can(Permissions.Wallet.ViewBalance)) {
  const balance = await walletRepo.getBalance({ wallet });
  console.log(balance.label);
}

const entries = await walletRepo.getStatement({
  wallet,
  range: {
    startDate: new Date("2024-01-01"),
    endDate: new Date("2024-01-31"),
  },
});

Identity Example

IdentityRepository reads the authenticated /login/me data. It is not the login request itself, so it requires a token.

import { IdentityRepository } from "@temboplus/afloat";

const identityRepo = new IdentityRepository({ token });
const identity = await identityRepo.getIdentity();

Server Route Example

import { WalletRepository } from "@temboplus/afloat";

function extractBearerToken(req): string | undefined {
  return req.headers.authorization?.replace(/^Bearer\s+/i, "");
}

app.get("/api/wallets", async (req, res) => {
  const token = extractBearerToken(req);

  if (!token) {
    return res.status(401).json({ error: "Unauthorized" });
  }

  const walletRepo = new WalletRepository({ token });
  const wallets = await walletRepo.getWallets();

  return res.json({ wallets });
});

Architecture Overview

Host Application Responsibilities

  • Call AuthRepository.logIn(...) to create a session
  • Store the returned token in your own state, cookie, storage, or server session
  • Rehydrate User with User.fromJSON(...) when needed
  • Pass { token } to repositories before calling authenticated endpoints
  • Check permissions with the returned User instance, for example user.can(Permissions.Wallet.ViewBalance)

Library Responsibilities

  • Provide typed repositories for Afloat API resources
  • Attach the token and request ID headers to repository calls
  • Convert API responses into domain models where repositories support it
  • Surface API errors through APIError or repository-specific errors

Best Practices

Token Handling

import {
  AuthRepository,
  ProfileRepository,
  WalletRepository,
} from "@temboplus/afloat";

const authRepo = new AuthRepository();
const user = await authRepo.logIn(email, password);

saveToken(user.token);

const walletRepo = new WalletRepository({ token: user.token });
const profileRepo = new ProfileRepository({ token: user.token });

Permission Checks

import { Permissions, PayoutRepository } from "@temboplus/afloat";

if (user.can(Permissions.Payout.Create)) {
  const payoutRepo = new PayoutRepository({ token: user.token });
  await payoutRepo.pay(input);
}

Troubleshooting

Common Issues

AfloatAuth Import Errors

Problem: AfloatAuth is undefined or cannot be imported.

Solution: Replace AfloatAuth usage with AuthRepository.logIn(...) plus application-owned session state.

import { AuthRepository } from "@temboplus/afloat";

const authRepo = new AuthRepository();
const user = await authRepo.logIn(email, password);
const token = user.token;

Repository Token Issues

Problem: Repository calls fail with authentication errors.

Solution: Ensure the token from login or the incoming request is passed into the repository.

if (!extractedToken) {
  throw new Error("Missing authentication token");
}

const repo = new WalletRepository({ token: extractedToken });

Identity Repository Confusion

Problem: IdentityRepository is used for login.

Solution: Use AuthRepository.logIn(...) for login. Use IdentityRepository({ token }).getIdentity() only after you have a token.

API Reference

Login and Auth

  • AuthRepository.logIn(email, password) - Authenticate without an existing token and return a User
  • AuthRepository({ token }).updatePassword(current, next) - Update the current user's password
  • AuthRepository({ token }).getAccessList() - Fetch the current user's access list
  • User.token - Token to pass into repositories
  • User.can(permission) - Check a single permission
  • User.canAny(permissions) - Check if the user has at least one permission
  • User.canAll(permissions) - Check if the user has all permissions

Authenticated Repositories

All authenticated repositories use:

new RepositoryName({
  token: "user-auth-token",
  root: "custom-api-root", // optional
});

Available repositories:

  • WalletRepository - Wallet operations, balances, and statements
  • PayoutRepository - Payout creation, approval, rejection, lookup, and counting
  • BeneficiaryRepository - Beneficiary create, edit, remove, and lookup
  • ProfileRepository - Current profile lookup
  • TeamMemberRepository - Team member and role management
  • IdentityRepository - Current /login/me identity data
  • AuthRepository - Login without token; password and access-list operations with token