Skip to content

ABHINAVGARG05/Live-Leaderboard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

16 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ† Live Leaderboard SDK

A realโ€‘time leaderboard library powered by Redis, Postgres, Socket.IO, and TypeScript.

  • Postgres โ†’ Persistent storage
  • Redis โ†’ Ultra-fast reads & live score updates
  • Socket.IO โ†’ Instant leaderboard broadcasts
  • Express Router โ†’ Drop-in REST API

Perfect for multiplayer games, coding contests, and online quizzes.


๐Ÿ“ฆ Installation

npm install live-leaderboard redis pg express socket.io dotenv
# or:
pnpm add live-leaderboard redis pg express socket.io dotenv

โš™๏ธ Database Setup (Postgres)

1) Create schema

Save this as playground/schema.sql in your project:

CREATE TABLE IF NOT EXISTS leaderboard_scores (
  id BIGSERIAL PRIMARY KEY,
  game_id TEXT NOT NULL,
  user_id TEXT NOT NULL,
  score INTEGER NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT leaderboard_scores_game_user_uk UNIQUE (game_id, user_id)
);

CREATE INDEX IF NOT EXISTS idx_leaderboard_scores_game_score_desc
  ON leaderboard_scores (game_id, score DESC);

Run it once:

psql -d <YOUR_DB_NAME> -f playground/schema.sql

If you customize table/column names, update the LeaderboardConfig accordingly (see below).


๐Ÿš€ Backend Setup

.env

REDIS_URL=redis://localhost:6379
POSTGRES_URL=postgres://user:pass@localhost:5432/dbname
PORT=3000

Run Redis & Postgres (Docker)

docker run -p 6379:6379 redis

docker run -p 5432:5432 \
  -e POSTGRES_PASSWORD=pass \
  -e POSTGRES_USER=user \
  -e POSTGRES_DB=dbname \
  postgres

server.ts

import express from "express";
import http from "http";
import { Server as SocketIOServer } from "socket.io";
import { createClient } from "redis";
import { Pool } from "pg";
import dotenv from "dotenv";

import {
  Leaderboard,
  RedisService,
  PostgresService,
  createLeaderboardRouter,
  type LeaderboardConfig,
} from "live-leaderboard";

dotenv.config();

async function main() {
  const app = express();
  const server = http.createServer(app);
  const io = new SocketIOServer(server, { cors: { origin: "*" } });
  app.use(express.json());

  const redis = createClient({ url: process.env.REDIS_URL });
  await redis.connect();

  const pg = new Pool({ connectionString: process.env.POSTGRES_URL });

  const config: LeaderboardConfig = {
    redisPrefix: "leaderboard",
    tableName: "leaderboard_scores",
    columns: {
      gameId: "game_id",
      userId: "user_id",
      score: "score",
    },
  };

  const leaderboard = new Leaderboard(
    new RedisService(redis, config.redisPrefix),
    new PostgresService(pg, config)
  );

  app.use("/leaderboard", createLeaderboardRouter(leaderboard, io));

  io.on("connection", (socket) => {
    console.log("Client connected:", socket.id);
    socket.on("join-game", (gameId: string) => socket.join(gameId));
  });

  server.listen(process.env.PORT || 3000, () =>
    console.log(
      `Server running at http://localhost:${process.env.PORT || 3000}`
    )
  );
}

main().catch(console.error);

๐ŸŽฎ Frontend Example (Vanilla)

<!DOCTYPE html>
<html>
  <head>
    <title>Live Leaderboard</title>
    <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
  </head>
  <body>
    <h1>Leaderboard</h1>
    <ul id="leaderboard"></ul>

    <script>
      const socket = io("http://localhost:3000");
      socket.emit("join-game", "demo123");

      socket.on("leaderboard:update", (players) => {
        const list = document.getElementById("leaderboard");
        list.innerHTML = "";
        players.forEach((p, i) => {
          const li = document.createElement("li");
          li.textContent = `#${i + 1} ${p.userId} - ${p.score}`;
          list.appendChild(li);
        });
      });
    </script>
  </body>
</html>

๐Ÿ“ก REST API

POST /leaderboard/score

Submit or update a score.

Body

{
  "gameId": "demo123",
  "userId": "alice",
  "score": 150
}

Validation

  • gameId and userId must be non-empty strings
  • score must be a non-negative integer

Response

{ "success": true }

GET /leaderboard/:gameId/top?limit=10

Get top N players. limit must be an integer โ‰ฅ 1. A hard cap of 100 is enforced.

Response

[
  { "userId": "dave", "score": 490 },
  { "userId": "alice", "score": 237 },
  { "userId": "bob", "score": 39 }
]

GET /leaderboard/:gameId/rank/:userId

Get a userโ€™s rank.

Response

{ "rank": 2 }

โšก SDK Usage (Direct)

import {
  Leaderboard,
  RedisService,
  PostgresService,
  type LeaderboardConfig,
} from "live-leaderboard";
import { createClient } from "redis";
import { Pool } from "pg";

const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();

const pg = new Pool({ connectionString: process.env.POSTGRES_URL });

const config: LeaderboardConfig = {
  redisPrefix: "lb",
  tableName: "leaderboard_scores",
  columns: { gameId: "game_id", userId: "user_id", score: "score" },
};

const leaderboard = new Leaderboard(
  new RedisService(redis, config.redisPrefix),
  new PostgresService(pg, config)
);

await leaderboard.submitScore("game1", "bob", 1000);
console.log(await leaderboard.getTopPlayers("game1", 5));
console.log(await leaderboard.getUserRank("game1", "bob"));

๐Ÿ”ง Custom Schema Support

Use any table/column names by changing the config:

const config: LeaderboardConfig = {
  redisPrefix: "myapp:lb",
  tableName: "game_scores_custom",
  columns: {
    gameId: "gid",
    userId: "uid",
    score: "points",
  },
};

Matching SQL:

CREATE TABLE IF NOT EXISTS game_scores_custom (
  id BIGSERIAL PRIMARY KEY,
  gid TEXT NOT NULL,
  uid TEXT NOT NULL,
  points INTEGER NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT game_scores_custom_gid_uid_uk UNIQUE (gid, uid)
);

๐Ÿ“ Suggested Project Structure

live-leaderboard/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ config/           # DB & service configs
โ”‚   โ”œโ”€โ”€ server/           # Express + Socket.IO setup
โ”‚   โ”œโ”€โ”€ sdk/              # Leaderboard classes/services
โ”‚   โ””โ”€โ”€ playground/
โ”‚       โ”œโ”€โ”€ server.ts     # Example server
โ”‚       โ””โ”€โ”€ schema.sql    # Postgres schema
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ README.md

๐Ÿ“ License

MIT ยฉ abhi-garg

About

No description or website provided.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published