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

fitzroy

v7.0.0

Published

TypeScript port of the fitzRoy R package — programmatic access to AFL data including match results, player stats, fixtures, ladders, and more

Readme

Fitzroy

CI npm

TypeScript library and CLI for AFL data - matches, stats, ladders, teams, players, and awards.

A port of the fitzRoy R package.

Data Sources

  • AFL API: official AFL data covering AFLM (2012+), AFLW (2017+), VFL and VFLW (2021+). Default for matches, stats, squads, lineups, ladders.
  • FootyWire: scraped AFLM match results, fixtures, player stats, team stats, and awards.
  • AFL Tables: AFLM historical results from 1897 and statistics from about 1965.
  • Match coaches: AFL Tables supplies credited-coach records for AFLM from 1990. FootyWire extraction remains internal. Captured match headings must establish coverage before any FootyWire season-wide support.
  • Squiggle: AFLM match results and ladders.
  • Fryzigg: advanced AFLM and AFLW player-stat snapshots.
  • AFL Coaches: AFLCA coaches votes.

Install

npm install fitzroy effect

effect is a peer dependency, so your program and fitzroy share one copy of Effect 4.

Upgrading to version 7? Read the version 7 migration guide. For earlier changes, see the version 6 migration guide.

Library Usage

Version 7 uses Effect. Each fetch* function returns an Effect that succeeds with data or fails with a tagged error. Run it with FitzroyLive, which provides the source services and the HTTP policy:

import { Effect } from "effect";
import { FitzroyLive, fetchMatches, resolveDefaultSeason } from "fitzroy";

const season = resolveDefaultSeason("AFLM");

const program = fetchMatches({ source: "afl-api", season }).pipe(
  Effect.map((matches) => `${matches.length} matches in ${season}`),
  Effect.catchTag("AflApiError", (error) => Effect.succeed(`AFL API failed: ${error.message}`)),
);

console.log(await Effect.runPromise(program.pipe(Effect.provide(FitzroyLive))));

Errors are Schema.TaggedError classes such as AflApiError, ScrapeError, OutOfRangeError, and UnsupportedSourceError. Handle them with Effect.catchTag or Match.tag. Coverage errors carry a suggestion that names a source with coverage.

Provide FitzroyLive once per program. A single runtime shares one AFL API token across every call. To change the request policy, provide SourceHttpConfig:

import { Effect } from "effect";
import { FitzroyLive, SourceHttpConfig, fetchLadder } from "fitzroy";

const ladder = fetchLadder({ source: "afl-api", season: 2025 }).pipe(
  Effect.provide(FitzroyLive),
  Effect.provideService(SourceHttpConfig, { timeout: "10 seconds", retry5xx: true }),
);

In tests, replace FetchHttpClient.Fetch from effect/http with a fixture-backed fetch, or provide a stub for one source service such as AflApi with Layer.succeed.

Public API

| Function | Query type | Succeeds with | Requires | | -------------------- | -------------------- | --------------------- | ------------------------------------------- | | fetchMatches | MatchQuery | Match[] | SourceRegistry | | fetchMatchCoaches | MatchCoachesQuery | MatchCoachesResult | SourceRegistry | | fetchPlayerStats | PlayerStatsQuery | SeasonPlayerStats | SourceRegistry | | fetchTeamStats | TeamStatsQuery | TeamStatsEntry[] | SourceRegistry | | fetchLadder | LadderQuery | Ladder | SourceRegistry | | fetchTeams | TeamQuery | Team[] | AflApi | | fetchSquad | SquadQuery | Squad | SourceRegistry | | fetchLineup | LineupQuery | Lineup[] | SourceRegistry | | fetchPlayerDetails | PlayerDetailsQuery | PlayerDetailsResult | SourceRegistry, AflApi | | fetchAwards | AwardQuery | AwardResult | SourceRegistry, FootyWire, AflCoaches | | fetchSeasons | CompetitionCode | CompetitionSeason[] | AflApi |

Every function fails with a SourceError. FitzroyLive provides every requirement.

Examples for each, inside Effect.gen (using resolveDefaultSeason so the snippets stay stable year-on-year):

import { Effect } from "effect";
import {
  FitzroyLive,
  fetchAwards,
  fetchLadder,
  fetchLineup,
  fetchMatchCoaches,
  fetchMatches,
  fetchPlayerDetails,
  fetchPlayerStats,
  fetchSquad,
  fetchTeamStats,
  fetchTeams,
  resolveDefaultSeason,
} from "fitzroy";

const season = resolveDefaultSeason("AFLM");

const program = Effect.gen(function* () {
  // Coach assignments use AFL Tables by default; partial page failures remain
  // visible in `completeness` instead of dropping successful assignments.
  yield* fetchMatchCoaches({ season, team: "Carlton" });

  // All matches for a season, only completed, or upcoming fixtures
  yield* fetchMatches({ source: "afl-api", season });
  yield* fetchMatches({ source: "afl-api", season, status: "Complete" });
  yield* fetchMatches({ source: "afl-api", season, status: "Upcoming" });

  // Player and team stats for round 1
  yield* fetchPlayerStats({ source: "afl-api", season, round: 1 });
  yield* fetchTeamStats({ source: "afl-tables", season, competition: "AFLM" });

  // Ladder
  yield* fetchLadder({ source: "afl-api", season });

  // Team identity
  yield* fetchTeams({ competition: "AFLM" });
  yield* fetchSquad({ source: "afl-api", season, team: "Carlton" });
  yield* fetchLineup({ source: "afl-api", season, round: 1 });
  yield* fetchPlayerDetails({ source: "afl-api", season, team: "Carlton" });

  // Awards
  yield* fetchAwards({ award: "coleman", season, limit: 10 });
  yield* fetchAwards({ award: "brownlow", season });
});

await Effect.runPromise(program.pipe(Effect.provide(FitzroyLive)));

The package root also exports an Effect schema for every domain model, such as MatchSchema and LadderSchema. Use them to decode or encode stored output.

Partial-result envelopes keep successful rows and identify missing data. Check failedMatchIds, failedTeams, or failedRounds before you treat a result as complete. Check Squad.scope and PlayerDetailsResult.scope before you treat a scraped roster as season-specific.

Wire Schemas (fitzroy/schemas)

The fitzroy/schemas subpath exports the raw AFL API and Squiggle response schemas (Effect Schema) for consumers who need to validate wire-level payloads directly. The package publishes this subpath, but its contents track upstream API shapes. Schemas may change at minor versions when the upstream changes. Depend on it only if you are deliberately coupling to the raw wire format.

import { Result, Schema } from "effect";
import { MatchItemListSchema } from "fitzroy/schemas";

// Validate a raw AFL API round response
const result = Schema.decodeUnknownResult(MatchItemListSchema)(rawJson);
if (Result.isFailure(result)) {
  console.error("Upstream shape changed:", result.failure.message);
}

Available exports include MatchItemListSchema, PlayerStatsListSchema, CompetitionListSchema, SquiggleGameSchema, and the full suite of AFL API CFS response schemas. See src/schemas.ts for the complete list.

CLI

# Install globally
npm install -g fitzroy

# Six top-level commands, all sharing a uniform "drill in by adding flags" UX:

# Matches (subsumes the old `matches` and `fixture` commands)
fitzroy match --season 2025 --round 1
fitzroy match --season 2025 --status Upcoming

# Player or team stats (subsumes the old `team-stats` command)
fitzroy stats --season 2025 --round 1                 # per-player rows
fitzroy stats --season 2025 --by team                 # team aggregates

# Ladder standings
fitzroy ladder --season 2025

# Team identity (subsumes the old `teams`, `squad`, `lineup` commands)
fitzroy team                                          # list all teams
fitzroy team --name Carlton -s 2025                   # team's squad for season
fitzroy team -s 2025 -r 3                             # all match-day lineups for round 3

# Player biography (replaces `player-details`)
fitzroy player --team Carlton -s 2025

# Awards (subsumes `coaches-votes`; adds Coleman, Brownlow, etc.)
fitzroy awards --type brownlow -s 2024
fitzroy awards --type coleman  -s 2025 --limit 10
fitzroy awards --type coaches  -s 2024 --round 3

# Output formats
fitzroy match --season 2025 --json    # JSON (default when piped)
fitzroy match --season 2025 --csv     # CSV with headers
fitzroy match --season 2025 --full    # All columns in table view

Pass --competition VFL to select a competition when the command and source cover it. Coverage errors identify unsupported combinations.

Run fitzroy --help for all commands and options.

Read the CLI guide for modes, validation rules, source limits, output envelopes, and partial-failure behaviour.

Contributing

  1. Clone the repository.
  2. Install the Vite+ CLI, then run vp install. Vite+ selects Node.js from .node-version and pnpm from packageManager. The install also sets up the pre-commit hook that runs vp staged.
  3. Use pnpm through vp install, vp add, and vp remove. pnpm-lock.yaml is the only lock file.
  4. Run quality checks with vp check && vp test.

License

MIT

Explicit Competition Seasons in Version 6

Use fetchSeasons(competition) to discover canonical season keys, calendar years, display names and provider season IDs. Ordinary seasons accept either 2026 or "2026". AFLW's two 2022 seasons require "2022-S6" or "2022-S7". A bare AFLW 2022 fails with AmbiguousSeasonError and its validSelectors. Competition remains separate from the season key.

import { fetchMatches, fetchSeasons } from "fitzroy";

const seasons = yield* fetchSeasons("AFLW");
const matches = yield* fetchMatches({
  source: "afl-api",
  competition: "AFLW",
  season: "2022-S7",
});

The seasons CLI command exposes discovery. Match-ID shortcuts validate the selected competition and season. Returned records retain the numeric calendar year and add seasonKey. Use that key when joining or grouping season data.