Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ labels: bug

## Environment

- `@dpianelli/chesscom` version:
- `chesscom-sdk` version:
- Runtime + version (Node / Deno / Bun / browser):

## Extra context
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
dist
coverage
CHANGELOG.md

# Local Claude Code harness files.
.claude
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

Thanks for your interest in `@dpianelli/chesscom`! This is an unofficial,
Thanks for your interest in `chesscom-sdk`! This is an unofficial,
community SDK for the Chess.com Published-Data API.

## Prerequisites
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# @dpianelli/chesscom
# chesscom-sdk

[![npm version](https://img.shields.io/npm/v/@dpianelli/chesscom.svg)](https://www.npmjs.com/package/@dpianelli/chesscom)
[![license](https://img.shields.io/npm/l/@dpianelli/chesscom.svg)](./LICENSE)
[![types](https://img.shields.io/npm/types/@dpianelli/chesscom.svg)](https://www.npmjs.com/package/@dpianelli/chesscom)
[![npm version](https://img.shields.io/npm/v/chesscom-sdk.svg)](https://www.npmjs.com/package/chesscom-sdk)
[![license](https://img.shields.io/npm/l/chesscom-sdk.svg)](./LICENSE)
[![types](https://img.shields.io/npm/types/chesscom-sdk.svg)](https://www.npmjs.com/package/chesscom-sdk)

> **Unofficial** TypeScript SDK for the [Chess.com Published-Data API](https://www.chess.com/news/view/published-data-api).
> Not affiliated with, endorsed by, or sponsored by Chess.com.
Expand All @@ -23,13 +23,13 @@ rate limiting, ETag caching, runtime response validation, and lazy pagination.
## Install

```bash
npm install @dpianelli/chesscom
npm install chesscom-sdk
```

## Quickstart

```ts
import { ChessComClient } from "@dpianelli/chesscom";
import { ChessComClient } from "chesscom-sdk";

const client = new ChessComClient({
// Required by Chess.com — include an app name and a contact.
Expand Down Expand Up @@ -179,7 +179,7 @@ Every error thrown by the SDK extends `ChessComError` and carries a discriminant
`kind`. Branch with `instanceof` or `switch (err.kind)`.

```ts
import { ChessComError, NotFoundError } from "@dpianelli/chesscom";
import { ChessComError, NotFoundError } from "chesscom-sdk";

try {
await client.getPlayer("does-not-exist");
Expand Down Expand Up @@ -224,7 +224,7 @@ The client revalidates with ETags (`If-None-Match`) and serves the cached body o
implementing `CacheStore`:

```ts
import type { CacheStore, CacheEntry } from "@dpianelli/chesscom";
import type { CacheStore, CacheEntry } from "chesscom-sdk";

class RedisCacheStore implements CacheStore {
constructor(private redis: import("ioredis").Redis) {}
Expand Down
2 changes: 1 addition & 1 deletion RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ These must be configured once by a maintainer:
"Allow GitHub Actions to create and approve pull requests". (release-please
needs this to open its release PR.)
2. **npm trusted publishing (OIDC)** — on npmjs.com, open the package settings
for `@dpianelli/chesscom` → Trusted Publisher → add a GitHub Actions publisher
for `chesscom-sdk` → Trusted Publisher → add a GitHub Actions publisher
for repo `denispianelli/chesscom`, workflow `.github/workflows/publish.yml`.
No `NPM_TOKEN` secret is then needed.

Expand Down
6 changes: 3 additions & 3 deletions SPEC.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# `@dpianelli/chesscom` — Technical spec
# `chesscom-sdk` — Technical spec

> Unofficial TypeScript SDK for the [Chess.com Published-Data API](https://www.chess.com/news/view/published-data-api).
> Not affiliated with, endorsed by, or sponsored by Chess.com.
Expand All @@ -13,7 +13,7 @@ choice, not drift.

| Aspect | Decision |
| -------------- | ----------------------------------------------------------- |
| **npm name** | `@dpianelli/chesscom` (scope = npm username `dpianelli`) |
| **npm name** | `chesscom-sdk` (scope = npm username `dpianelli`) |
| **Language** | TypeScript, isomorphic (Node 18+, Deno, Bun, browser) |
| **Runtime** | native global `fetch` — no HTTP library |
| **Dependency** | **Exactly one: `zod`** (runtime response validation) |
Expand Down Expand Up @@ -119,7 +119,7 @@ test/
## 4. Public surface (flat methods)

```ts
import { ChessComClient } from "@dpianelli/chesscom";
import { ChessComClient } from "chesscom-sdk";

const client = new ChessComClient({
userAgent: "myapp/1.0 (me@example.com)", // MANDATORY
Expand Down
2 changes: 1 addition & 1 deletion STYLE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# `@dpianelli/chesscom` — Conventions (clean code)
# `chesscom-sdk` — Conventions (clean code)

This document sets the code conventions that keep the project clean and
consistent over time. Guiding principle: **clean, not ceremonious.** We prefer
Expand Down
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import prettier from "eslint-config-prettier";
import { defineConfig, globalIgnores } from "eslint/config";

export default defineConfig(
globalIgnores(["dist", "node_modules", "coverage"]),
globalIgnores(["dist", "node_modules", "coverage", ".claude", "examples"]),
eslint.configs.recommended,
tseslint.configs.strictTypeChecked,
tseslint.configs.stylisticTypeChecked,
Expand Down
30 changes: 30 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Examples

Runnable, self-contained scripts showing common `chesscom-sdk` usage. They
import the package by name (`chesscom-sdk`) — exactly how you'd use it in your
own project.

## Running them against this checkout

The examples resolve `chesscom-sdk` to the local build via Node's
[self-referencing](https://nodejs.org/api/packages.html#self-referencing-a-package-using-its-name),
so build once, then run any file with a TypeScript-aware runner:

```bash
npm run build
npx tsx examples/player-profile.ts
```

> Node 22 can also run these directly with `node --experimental-strip-types
examples/player-profile.ts`; on Node 23.6+ the flag is unnecessary.

Every request to Chess.com **requires** a descriptive `User-Agent` (an app name
and a contact). Edit the `userAgent` in each example before running against the
live API.

| File | Shows |
| ------------------------------------------------------------ | -------------------------------------------- |
| [`player-profile.ts`](./player-profile.ts) | Fetch a profile + rating stats |
| [`stream-games.ts`](./stream-games.ts) | Lazily iterate monthly archives with filters |
| [`leaderboards-and-puzzle.ts`](./leaderboards-and-puzzle.ts) | Leaderboards, titled players, daily puzzle |
| [`error-handling.ts`](./error-handling.ts) | Typed errors (404, rate limit, validation) |
33 changes: 33 additions & 0 deletions examples/error-handling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Every failure mode is a typed error you can narrow on. The SDK throws a
* `NotFoundError` for 404s, a `RateLimitError` for 429s, a `ValidationError`
* when a response doesn't match its schema, and so on — all subclasses of
* `ChessComError`.
*
* npm run build && npx tsx examples/error-handling.ts
*/
import {
ChessComClient,
ChessComError,
NotFoundError,
RateLimitError,
} from "chesscom-sdk";

const client = new ChessComClient({
userAgent: "chesscom-sdk-examples/1.0 (you@example.com)",
});

try {
// A username that (almost certainly) does not exist → 404.
await client.getPlayer("this-player-should-not-exist-xyz-123");
} catch (error) {
if (error instanceof NotFoundError) {
console.log("✓ Caught NotFoundError — player does not exist.");
} else if (error instanceof RateLimitError) {
console.log("Rate limited — back off and retry later.");
} else if (error instanceof ChessComError) {
console.log(`Other Chess.com error (${error.kind}): ${error.message}`);
} else {
throw error;
}
}
24 changes: 24 additions & 0 deletions examples/leaderboards-and-puzzle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Read-only "discovery" endpoints: live leaderboards, titled players, and the
* daily puzzle.
*
* npm run build && npx tsx examples/leaderboards-and-puzzle.ts
*/
import { ChessComClient } from "chesscom-sdk";

const client = new ChessComClient({
userAgent: "chesscom-sdk-examples/1.0 (you@example.com)",
});

const leaderboards = await client.getLeaderboards();
console.log("Top 5 — live blitz:");
for (const entry of (leaderboards.live_blitz ?? []).slice(0, 5)) {
console.log(` #${entry.rank} ${entry.username} (${entry.score})`);
}

const grandmasters = await client.getTitledPlayers("GM");
console.log(`\nGrandmasters with a Chess.com account: ${grandmasters.length}`);

const puzzle = await client.getDailyPuzzle();
console.log(`\nDaily puzzle: "${puzzle.title}"`);
console.log(` ${puzzle.url}`);
29 changes: 29 additions & 0 deletions examples/player-profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Fetch a player's public profile and rating stats.
*
* npm run build && npx tsx examples/player-profile.ts [username]
*/
import { ChessComClient } from "chesscom-sdk";

const username = process.argv[2] ?? "hikaru";

const client = new ChessComClient({
// Required by Chess.com — include an app name and a contact.
userAgent: "chesscom-sdk-examples/1.0 (you@example.com)",
});

const [profile, stats] = await Promise.all([
client.getPlayer(username),
client.getPlayerStats(username),
]);

console.log(`${profile.name ?? profile.username} (@${profile.username})`);
console.log(` followers: ${profile.followers ?? 0}`);
console.log(` country: ${profile.country}`);

const blitz = stats.chess_blitz?.last?.rating;
const rapid = stats.chess_rapid?.last?.rating;
const bullet = stats.chess_bullet?.last?.rating;
console.log(
` ratings: blitz ${blitz ?? "—"} · rapid ${rapid ?? "—"} · bullet ${bullet ?? "—"}`,
);
32 changes: 32 additions & 0 deletions examples/stream-games.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Lazily iterate a player's games across monthly archives. The SDK hides the
* pagination, fetches one month at a time (rate-limited + ETag-cached), and
* yields game by game. Here we keep only rated blitz games since a given month.
*
* npm run build && npx tsx examples/stream-games.ts [username] [since YYYY-MM]
*/
import { ChessComClient } from "chesscom-sdk";

const username = process.argv[2] ?? "magnuscarlsen";
const since = process.argv[3] ?? "2024-01";

const client = new ChessComClient({
userAgent: "chesscom-sdk-examples/1.0 (you@example.com)",
});

let count = 0;
for await (const game of client.streamPlayerGames(username, {
since,
rated: true,
timeClass: "blitz",
})) {
console.log(
`${game.end_time} ${game.white.username} vs ${game.black.username} ${game.url}`,
);
// Stop after 20 so the example stays quick — drop this to walk everything.
if (++count >= 20) break;
}

console.log(
`\nShowed ${count} rated blitz game(s) for ${username} since ${since}.`,
);
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
{
"name": "@dpianelli/chesscom",
"name": "chesscom-sdk",
"version": "1.0.1",
"description": "Unofficial TypeScript SDK for the Chess.com Published-Data API. Not affiliated with Chess.com.",
"keywords": [
"chess.com",
"chesscom",
"chess-com",
"chess",
"chess-api",
"chess-com-api",
"chesscom-api",
"published-data-api",
"api",
"api-client",
"sdk",
"typescript"
"typescript",
"pgn",
"zod",
"esm"
],
"author": "dpianelli",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"packages": {
".": {
"release-type": "node",
"package-name": "@dpianelli/chesscom",
"package-name": "chesscom-sdk",
"changelog-path": "CHANGELOG.md",
"bump-minor-pre-major": true,
"include-component-in-tag": false
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* `@dpianelli/chesscom` — Unofficial TypeScript SDK for the Chess.com
* `chesscom-sdk` — Unofficial TypeScript SDK for the Chess.com
* Published-Data API.
*
* Public surface is assembled here. The high-level client lands next;
Expand Down