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

clubworx

v0.7.1

Published

A package for fetching data from Clubworx

Readme

Clubworx

A package for fetching your own data from Clubworx. This package is in no way officially affiliated with Clubworx.

Install

npm install clubworx

Usage

import clubworx from 'clubworx';

// Creates a session with your login details, ideally from ENV
const session = await clubworx.login('[email protected]', 'secret');

// Get array of all your reports (just ID and name)
const reports = await session.allReports();
// Returns: [{ id: 123, name: "My Report" }, ...]

// Get the complete data for a specific report (array of row objects)
const report = await session.reportById(reports[0].id);
// Returns: [{ "First Name": "John", "Last Name": "Doe", ... }, ...]

// Optional pagination parameters (default: page=1, count=100)
const reportPage2 = await session.reportById(reports[0].id, { page: 2, count: 50 });

// Get members with optional pagination and search
const members = await session.members();
// Returns: [{ id: 12345, name: "Jane Doe", firstName: "Jane", lastName: "Doe", ... }, ...]

// With pagination and search
const searchResults = await session.members({ page: 1, count: 50, search: 'Smith' });

// Get a single member by ID
const member = await session.memberById(members[0].id);
// Returns: { id: 12345, name: "Jane Doe", firstName: "Jane", lastName: "Doe", ... }

// Add a note to a member
const note = await session.addMemberNote(members[0].id, 'Subject', 'Note body text');
// Returns: { id: 964591, subject: "Subject", body: "Note body text", created_at: "...", ... }

// With optional tags
const taggedNote = await session.addMemberNote(members[0].id, 'Follow-up', 'Call next week', ['urgent', 'callback']);

// Iterate over every member (pages automatically)
for await (const m of session.allMembers()) {
  console.log(m.name);
}

// Download a member's profile photo as a Buffer
const photo = await session.downloadImage(member.imageUrl);

// Financials summary from the dashboard
const financials = await session.financials();

console.log({ reports, report, members, member, note });

Classes and check-ins

// Classes/events on a day (Date or 'YYYY-MM-DD')
const classes = await session.classesOn(new Date());
// Returns: [{ id, name, startsAt, endsAt, instructor, location, capacity, bookedCount, attendedCount, raw }, ...]

// Check a member in to a class, and undo it
await session.checkInToClass(classes[0].id, member.id);
await session.undoCheckIn(classes[0].id, member.id);

Status: the class/attendance endpoints have not yet been confirmed against the Clubworx web app. Until the CLASS_ENDPOINTS block at the top of index.js is filled in (see DISCOVERY.md), these methods throw "<name>: Clubworx endpoint not yet discovered".

Errors

Non-2xx responses and unparseable bodies throw an Error with statusCode and body properties. An expired login throws SessionExpiredError (see below). Cookies are refreshed from every response, so long-lived sessions keep a valid CSRF token — persist session.toJSON() again after mutating calls if you store sessions externally.

For CommonJS, use const clubworx = require('clubworx') and wrap in an async function.

Serverless Usage

For serverless environments, you can serialize and restore sessions to avoid re-authenticating on every invocation:

const { login, Session, SessionExpiredError } = require('clubworx');

// First invocation - login and save session
const session = await login('[email protected]', 'secret');
const sessionData = session.toJSON();
// Store sessionData in your preferred storage (Redis, DynamoDB, S3, etc.)
await saveToStorage('session-key', JSON.stringify(sessionData));

// Subsequent invocations - restore session from storage
try {
  const storedData = JSON.parse(await getFromStorage('session-key'));
  const session = Session.fromJSON(storedData);
  const reports = await session.allReports();
} catch (error) {
  if (error instanceof SessionExpiredError) {
    // Session expired - login again and update storage
    const session = await login('[email protected]', 'secret');
    await saveToStorage('session-key', JSON.stringify(session.toJSON()));
    const reports = await session.allReports();
  } else {
    throw error;
  }
}