{"id":48524803,"url":"https://github.com/teamstep/leaderboard-function","last_synced_at":"2026-04-07T22:02:43.302Z","repository":{"id":342634613,"uuid":"1174451661","full_name":"TeamSTEP/leaderboard-function","owner":"TeamSTEP","description":"simple leaderboard function","archived":false,"fork":false,"pushed_at":"2026-03-06T17:04:41.000Z","size":26,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-06T20:17:03.338Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TeamSTEP.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-06T13:07:34.000Z","updated_at":"2026-03-06T17:04:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/TeamSTEP/leaderboard-function","commit_stats":null,"previous_names":["teamstep/leaderboard-function"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/TeamSTEP/leaderboard-function","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TeamSTEP%2Fleaderboard-function","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TeamSTEP%2Fleaderboard-function/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TeamSTEP%2Fleaderboard-function/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TeamSTEP%2Fleaderboard-function/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TeamSTEP","download_url":"https://codeload.github.com/TeamSTEP/leaderboard-function/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TeamSTEP%2Fleaderboard-function/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31530647,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-07T22:02:18.207Z","updated_at":"2026-04-07T22:02:43.290Z","avatar_url":"https://github.com/TeamSTEP.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Simple Leaderboard Function\n\nThis is a basic online leaderboard function made with Supabase.\nThis code is mainly meant to be used with our project, Meltdown.\n\n## Usage\n\nUse any API clients, or curl like the following:\n\n```bash\ncurl -X POST \u003cPUBLIC_URL\u003e/functions/v1/leaderboard \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer \u003cLOCAL_ANON_KEY\u003e\" \\\n  -d '{\"playerScore\": 4200}' # payload body in JSON\n```\n\n## Leaderboard API\n\nBase URL: `/functions/v1/leaderboard`\n\nAll responses are JSON. All error responses follow the shape `{ \"error\": string }`.\n\n---\n\n## Endpoints\n\n### `GET /` — Get top N players\n\nReturns the top players on the leaderboard, ranked by their best (highest) score.\n\n**Query Parameters**\n\n| Parameter | Type    | Required | Default | Constraints      | Description                        |\n|-----------|---------|----------|---------|------------------|------------------------------------|\n| `count`   | integer | No       | `5`     | Min: 1, Max: 50  | Number of top players to return    |\n\n**Responses**\n\n| Status | Description        |\n|--------|--------------------|\n| `200`  | Success            |\n| `500`  | Internal server error |\n\n**`200` Response**\n```json\n{\n  \"count\": 5,\n  \"top_players\": [\n    {\n      \"player_name\": \"Alice\",\n      \"best_score\": \"98000\"\n    }\n  ]\n}\n```\n\n**`top_players` entry shape**\n\n| Field         | Type   | Description                               |\n|---------------|--------|-------------------------------------------|\n| `player_name` | string | Player's name                             |\n| `best_score`  | string | Player's all-time highest score (numeric string) |\n\n---\n\n### `GET /?playerName=` — Get scores for a player\n\nReturns a list of score entries for a specific player, ordered newest first. Each entry includes the score's global rank across all leaderboard entries.\n\n**Query Parameters**\n\n| Parameter    | Type    | Required | Default | Constraints           | Description                            |\n|--------------|---------|----------|---------|-----------------------|----------------------------------------|\n| `playerName` | string  | Yes      | —       | Max: 64 chars         | The player's name to look up           |\n| `count`      | integer | No       | `5`     | Min: 1, Max: 50       | Number of score entries to return      |\n\n**Responses**\n\n| Status | Description              |\n|--------|--------------------------|\n| `200`  | Success                  |\n| `404`  | Player not found         |\n| `500`  | Internal server error    |\n\n**`200` Response**\n```json\n{\n  \"player_name\": \"Alice\",\n  \"count\": 5,\n  \"total_entries\": 3,\n  \"scores\": [\n    {\n      \"id\": 12,\n      \"score\": \"98000\",\n      \"rank\": 1,\n      \"created_at\": \"2026-03-07T09:00:00Z\"\n    }\n  ]\n}\n```\n\n**`scores` entry shape**\n\n| Field        | Type   | Description                                        |\n|--------------|--------|----------------------------------------------------|\n| `id`         | number | Unique score entry ID                              |\n| `score`      | string | Score value as a numeric string                    |\n| `rank`       | number | Global rank of this score across all players       |\n| `created_at` | string | ISO 8601 timestamp of when the score was recorded  |\n\n---\n\n### `POST /?playerName=` — Submit a score\n\nInserts a new score entry for a player.\n\n**Query Parameters**\n\n| Parameter    | Type   | Required | Constraints   | Description              |\n|--------------|--------|----------|---------------|--------------------------|\n| `playerName` | string | Yes      | Max: 64 chars | The player's name        |\n\n**Request Body** (`application/json`)\n\n| Field         | Type             | Required | Description                                                                                     |\n|---------------|------------------|----------|-------------------------------------------------------------------------------------------------|\n| `playerScore` | number \\| string | Yes      | The score to record. Use a `number` for values ≤ `9007199254740991`. Use a numeric `string` for larger values to avoid precision loss. |\n\n```json\n{ \"playerScore\": 15000 }\n```\n\n```json\n{ \"playerScore\": \"99999999999999999999\" }\n```\n\n**Responses**\n\n| Status | Description                  |\n|--------|------------------------------|\n| `201`  | Score created successfully   |\n| `400`  | Validation error             |\n| `500`  | Internal server error        |\n\n**`201` Response**\n\n```json\n{\n  \"data\": {\n    \"id\": 42,\n    \"player_name\": \"Alice\",\n    \"score\": \"15000\",\n    \"created_at\": \"2026-03-07T11:00:00Z\"\n  }\n}\n```\n\n**`400` Error cases**\n\n| Cause                                              | Error message                                                                             |\n|----------------------------------------------------|-------------------------------------------------------------------------------------------|\n| `playerName` missing or empty                      | `` `playerName` is required and must be a non-empty string. ``                            |\n| `playerName` too long                              | `` `playerName` must not exceed 64 characters. ``                                         |\n| `playerScore` missing or wrong type                | `` `playerScore` is required and must be a number or numeric string. ``                   |\n| `playerScore` is a float                           | `` `playerScore` must be an integer, not a float. ``                                      |\n| `playerScore` is a `number` above MAX_SAFE_INTEGER | `` `playerScore` exceeds Number.MAX_SAFE_INTEGER. Pass it as a numeric string instead. `` |\n| `playerScore` is outside PostgreSQL `bigint` range | `` `playerScore` is outside the PostgreSQL bigint range. ``                               |\n\n---\n\n### `PATCH /?playerName=` — Rename a player\n\nRenames a player across all their score entries.\n\n**Query Parameters**\n\n| Parameter    | Type   | Required | Constraints   | Description                        |\n|--------------|--------|----------|---------------|------------------------------------|\n| `playerName` | string | Yes      | Max: 64 chars | The player's current name          |\n\n**Request Body** (`application/json`)\n\n| Field           | Type   | Required | Constraints   | Description                  |\n|-----------------|--------|----------|---------------|------------------------------|\n| `newPlayerName` | string | Yes      | Max: 64 chars | The new name for the player  |\n\n```json\n{ \"newPlayerName\": \"Bob\" }\n```\n\n**Responses**\n\n| Status | Description                              |\n|--------|------------------------------------------|\n| `200`  | Player successfully renamed              |\n| `400`  | Validation error                         |\n| `404`  | Player not found                         |\n| `409`  | New name is already taken                |\n| `500`  | Internal server error                    |\n\n**`200` Response**\n\n```json\n{\n  \"message\": \"Player \\\"Alice\\\" successfully renamed to \\\"Bob\\\".\",\n  \"updated_entries\": 3\n}\n```\n\n**`400` Error cases**\n\n| Cause                                          | Error message                                                                  |\n|------------------------------------------------|--------------------------------------------------------------------------------|\n| `playerName` missing or empty                  | `` `playerName` is required and must be a non-empty string. ``                 |\n| Either name exceeds 64 characters              | `` `playerName` must not exceed 64 characters. ``                              |\n| Body is missing or not valid JSON              | `Request body is missing or is not valid JSON`                                 |\n| `newPlayerName` missing or empty               | `` `newPlayerName` is required and must be a non-empty string. ``              |\n| `newPlayerName` is the same as `playerName`    | `` `newPlayerName` must be different from the current player name. ``          |\n\n---\n\n### `DELETE /?playerName=` — Remove a player\n\nPermanently deletes a player and all their score entries.\n\n**Query Parameters**\n\n| Parameter    | Type   | Required | Constraints   | Description                      |\n|--------------|--------|----------|---------------|----------------------------------|\n| `playerName` | string | Yes      | Max: 64 chars | The name of the player to remove |\n\n**Responses**\n\n| Status | Description                  |\n|--------|------------------------------|\n| `200`  | Player successfully removed  |\n| `400`  | Validation error             |\n| `404`  | Player not found             |\n| `500`  | Internal server error        |\n\n**`200` Response**\n\n```json\n{\n  \"message\": \"Player \\\"Alice\\\" and all their scores have been removed.\",\n  \"deleted_entries\": 3\n}\n```\n\n**`400` Error cases**\n\n| Cause                         | Error message                                         |\n|-------------------------------|-------------------------------------------------------|\n| `playerName` missing or empty | `` `playerName` query param is required. ``           |\n| `playerName` too long         | `` `playerName` must not exceed 64 characters. ``     |\n\n---\n\n## Common error shapes\n\n**`404` Not Found**\n\n```json\n{ \"error\": \"Player \\\"Alice\\\" not found.\" }\n```\n\n**`409` Conflict** *(PATCH only)*\n\n```json\n{ \"error\": \"Player name \\\"Bob\\\" is already taken.\" }\n```\n\n**`500` Internal Server Error**\n\n```json\n{ \"error\": \"Unexpected error message\" }\n```\n\n## Supabase Project Commands\n\nThese are some commonly used commands for working with Supabase.\n\n```bash\n# login\nsupabase login\n\n# db schema update\nsupabase db diff -f name_of_the_change\n\n# start supabase project locally\nsupabase start\n\n# list access keys\nsupabase secrets list\n\n# clear all local db\nsupabase db reset\n\n# apply the db migration locally\nsupabase migration up\n\n# serve the edge functions locally with logs\nsupabase functions serve\n\n# deploy the database to production\nsupabase db push\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteamstep%2Fleaderboard-function","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fteamstep%2Fleaderboard-function","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteamstep%2Fleaderboard-function/lists"}