campus-stats 0.4.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.6.0
6
+
7
+ - **Remove injuries** from CLI, library, cache, and SQLite (not in StatsBomb API).
8
+ - **BYOK:** free Open Data by default; optional StatsBomb customer login
9
+ (`SB_USERNAME` / `SB_PASSWORD`) → paid API at `data.statsbombservices.com`
10
+ - **Paid extras:** `campus endpoints` + flags (`--with-paid-player-season-stats`, …)
11
+ - **README:** Campus organizes data — free path already connected; bring-your-own
12
+ StatsBomb licence with clear examples
13
+
14
+ ## 0.5.0
15
+
16
+ - **CI / data host:** GitLab → **GitHub Actions**
17
+ - `ci.yml` (test), `publish.yml` (npmjs on `v*` tags), `refresh-data.yml`
18
+ (daily fantasy sync → Release `data-latest`)
19
+ - Removed `.gitlab-ci.yml` and GitLab Package Registry mirror docs
20
+ - **Breaking (public API):** removed export `GITLAB_PROJECT_ID`;
21
+ `dataBundleUrl()` / `dataBundleMetaUrl()` now point at
22
+ `https://github.com/Minacava/campus-stats/releases/download/data-latest/…`
23
+ - Docs (`cron.md`, `npm.md`, README) updated for GitHub
24
+
25
+ ## 0.4.5
26
+
27
+ - Drop Vercel / `campus-docs` links from npm metadata and README
28
+ - `homepage` → https://github.com/Minacava/campus-stats#readme
29
+ (docs live only in this repo’s README)
30
+
31
+ ## 0.4.4
32
+
33
+ - npm `repository` / `bugs` → https://github.com/Minacava/campus-stats
34
+ (`homepage` stays on the public docs site)
35
+
3
36
  ## 0.4.3
4
37
 
5
38
  - npm `homepage` and `repository` both point at
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Campus / campus contributors
3
+ Copyright (c) 2026 Marina Camacho
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,11 +1,18 @@
1
1
  # Campus (`campus-stats`)
2
2
 
3
- **Open, normalized, queryable data for women's football — installable in your app.**
3
+ **A data layer for women's football — not a data vendor.**
4
4
 
5
- `campus-stats` is the npm package for **Campus**: a library + CLI that pulls
6
- women's football stats from public sources, normalizes them into one schema,
7
- and gives your web/API/app access to competitions, seasons, clubs, national
8
- teams, matches, lineups, player stats, and basic fantasy points.
5
+ Campus does **not** sell football data. It **organizes** data from existing
6
+ sources into one schema you can query from a CLI or drop into a web app.
7
+
8
+ You choose how to feed it:
9
+
10
+ | Path | What you do | What Campus does |
11
+ |------|-------------|------------------|
12
+ | **Free** | Nothing — already connected | Syncs [StatsBomb Open Data](https://github.com/statsbomb/open-data) (and an FBref schedule pilot) |
13
+ | **Your StatsBomb licence** | Set `SB_USERNAME` / `SB_PASSWORD` | Talks to the StatsBomb **paid API** with *your* credentials and normalizes the response |
14
+
15
+ Same CLI, same `CampusClient`, same local cache either way.
9
16
 
10
17
  Requires **Node.js ≥ 22**.
11
18
 
@@ -13,126 +20,240 @@ Requires **Node.js ≥ 22**.
13
20
 
14
21
  ## Install
15
22
 
16
- Published on **npmjs.com**:
17
-
18
23
  ```bash
19
24
  npm install campus-stats
25
+ ```
20
26
 
27
+ Binaries: `campus` and `campus-stats` (same entrypoint).
28
+
29
+ ```bash
21
30
  npx campus sync --competition "Liga F"
22
31
  npx campus teams --competition "Liga F"
23
32
  npx campus matches --competition "Liga F" --team "Barcelona"
24
33
  ```
25
34
 
26
- The CLI binaries are `campus` and `campus-stats` (same entrypoint).
35
+ ---
27
36
 
28
- Docs: https://campus-tawny-mu.vercel.app/
37
+ ## Try the free path (no account)
29
38
 
30
- ---
39
+ Open Data is wired in. No signup, no API key:
31
40
 
32
- ## Use as a library (recommended for apps)
41
+ ```bash
42
+ # Sync one competition from StatsBomb Open Data
43
+ npx campus sync --competition "Liga F"
33
44
 
34
- ```ts
35
- import { CampusClient } from "campus-stats";
45
+ # Or every women's competition in the open catalogue
46
+ npx campus sync --fantasy
36
47
 
37
- const client = await CampusClient.open();
38
- await client.syncFantasy({ includePlayerStats: true });
39
- // or: const client = await CampusClient.fromBundle();
48
+ # Optional: lineups + basic player stats (capped)
49
+ npx campus sync --fantasy --with-players
40
50
 
41
- const clubs = client.teams({ competition: "Liga F", kind: "club" });
42
- const nations = client.teams({ competition: "Women's World Cup", kind: "national" });
43
- const matches = client.matches({ competition: "Liga F", team: "Barcelona" });
44
- const squad = client.squad({ competition: "Liga F", team: "Barcelona" });
45
- const points = client.fantasyPoints({ competition: "Liga F", player: "Walsh" });
51
+ # Query the local cache
52
+ npx campus competitions
53
+ npx campus matches --competition "Liga F" --team "Barcelona"
54
+ npx campus squad --competition "Liga F" --team "Barcelona"
55
+ npx campus fantasy-points --competition "Liga F"
46
56
 
47
- return Response.json({ clubs, nations, matches, squad, points });
57
+ # Confirm you are on free Open Data
58
+ npx campus credentials
59
+ # → statsbomb.mode: "open-data"
48
60
  ```
49
61
 
50
- ### What you get from the package
62
+ Data is stored in `.campus/cache.json` (or use `--sqlite` / `--db <path>`).
51
63
 
52
- | API | Purpose |
53
- |-----|---------|
54
- | `CampusClient` | Main entry for apps: sync / pull / query |
55
- | `syncFantasyBundle` / `updateCachedCompetitions` | Low-level sync helpers |
56
- | `scoreFantasyPoints` | Default fantasy scoring rules |
57
- | `listInjuries` | Stable stub (empty until a source exists) |
58
- | Types | `Competition`, `Team`, `Match`, `Player`, `LineupEntry`, … |
59
- | CLI bins `campus` / `campus-stats` | Same data from the terminal |
64
+ **Free sources today**
60
65
 
61
- ---
66
+ | Source | Coverage |
67
+ |--------|----------|
68
+ | StatsBomb Open Data | Women's competitions published on GitHub (e.g. Liga F, WSL, NWSL, major tournaments) |
69
+ | FBref | Schedule pilot — WSL + Liga F (`--source fbref`) |
62
70
 
63
- ## Keep data fresh (cron)
71
+ Coverage and freshness follow what those platforms publish for free.
64
72
 
65
- 1. GitLab **Pipeline schedule** on `main` (e.g. `0 6 * * *`) runs
66
- `refresh_fantasy_data` and publishes `campus-data/latest/cache.json`.
67
- 2. Apps call `CampusClient.fromBundle()` or `npx campus pull`.
73
+ ---
68
74
 
69
- Details: [`docs/cron.md`](./docs/cron.md).
75
+ ## Use your StatsBomb licence (optional)
70
76
 
71
- ---
77
+ If you already pay Hudl StatsBomb, Campus is a thin pipe: **your login → their
78
+ paid API → one Campus schema → your app**.
79
+
80
+ Campus never hosts or resells a StatsBomb subscription.
72
81
 
73
- ## CLI quick start
82
+ ### 1. Connect credentials
74
83
 
75
- After `npm install campus-stats`:
84
+ Same env vars as [statsbombpy](https://github.com/statsbomb/statsbombpy):
76
85
 
77
86
  ```bash
78
- npx campus sync --fantasy # all women's comps (clubs + selecciones)
79
- npx campus sync --fantasy --with-players # + lineups + player stats (capped)
80
- npx campus pull # download cron bundle
81
- npx campus competitions
82
- npx campus matches --competition "Liga F" --team "Barcelona"
83
- npx campus squad --competition "Liga F" --team "Barcelona"
84
- npx campus fantasy-points --competition "Liga F"
85
- npx campus injuries # empty + documented deferral
87
+ export SB_USERNAME="you@company.com"
88
+ export SB_PASSWORD="your-statsbomb-password"
89
+
90
+ npx campus credentials
91
+ # statsbomb.mode: "paid"
86
92
  ```
87
93
 
88
- Store: `.campus/cache.json` (or `--sqlite` / `--db <path>`).
94
+ Or write a local config file (the `.campus/` directory is gitignored):
95
+
96
+ ```json
97
+ {
98
+ "statsbomb": {
99
+ "username": "you@company.com",
100
+ "password": "your-statsbomb-password"
101
+ }
102
+ }
103
+ ```
104
+
105
+ Or one-off flags:
106
+
107
+ ```bash
108
+ npx campus sync --competition "Liga F" \
109
+ --sb-user "you@company.com" \
110
+ --sb-password "your-statsbomb-password"
111
+ ```
89
112
 
90
- Single-competition sync and identities still work:
113
+ ### 2. Sync (same commands as free)
91
114
 
92
115
  ```bash
93
116
  npx campus sync --competition "Liga F"
94
- npx campus sync --source fbref --competition "WSL"
95
- npx campus identities propose --competition "Liga F"
117
+ npx campus sync --fantasy
96
118
  ```
97
119
 
120
+ With a paid login, Campus calls `https://data.statsbombservices.com` instead of
121
+ Open Data. Which leagues and seasons you get depends on **your StatsBomb
122
+ contract**, not on Campus.
123
+
124
+ ### 3. Optional paid-only endpoints
125
+
126
+ These hit the StatsBomb paid API **directly** when your licence includes them:
127
+
128
+ | Flag | StatsBomb paid API |
129
+ |------|--------------------|
130
+ | `--with-paid-player-match-stats` | Player match aggregates |
131
+ | `--with-paid-team-match-stats` | Team match aggregates |
132
+ | `--with-paid-player-season-stats` | Player season aggregates |
133
+ | `--with-paid-team-season-stats` | Team season aggregates |
134
+ | `--with-paid-360` | 360 freeze frames |
135
+
136
+ ```bash
137
+ npx campus sync --competition "Liga F" \
138
+ --with-paid-player-season-stats \
139
+ --with-paid-player-match-stats
140
+ ```
141
+
142
+ See the full endpoint map:
143
+
144
+ ```bash
145
+ npx campus endpoints
146
+ ```
147
+
148
+ > **FBref:** there is no official API key. `--source fbref` remains free HTML only.
149
+
150
+ ---
151
+
152
+ ## Use in your app
153
+
154
+ ```ts
155
+ import { CampusClient, resolveCredentials, syncFantasyBundle } from "campus-stats";
156
+
157
+ // Free: omit credentials → Open Data
158
+ // Paid: set SB_USERNAME / SB_PASSWORD in the environment
159
+ const creds = await resolveCredentials();
160
+
161
+ await syncFantasyBundle({
162
+ includePlayerStats: true,
163
+ credentials: creds.statsbombPaidReady
164
+ ? {
165
+ username: creds.statsbomb.username,
166
+ password: creds.statsbomb.password,
167
+ }
168
+ : undefined,
169
+ });
170
+
171
+ const client = await CampusClient.open();
172
+
173
+ const clubs = client.teams({ competition: "Liga F", kind: "club" });
174
+ const matches = client.matches({ competition: "Liga F", team: "Barcelona" });
175
+ const squad = client.squad({ competition: "Liga F", team: "Barcelona" });
176
+ const points = client.fantasyPoints({ competition: "Liga F", player: "Walsh" });
177
+
178
+ return Response.json({ clubs, matches, squad, points });
179
+ ```
180
+
181
+ Or load a published bundle without syncing yourself:
182
+
183
+ ```ts
184
+ const client = await CampusClient.fromBundle();
185
+ ```
186
+
187
+ | Export | Purpose |
188
+ |--------|---------|
189
+ | `CampusClient` | Open cache / bundle, query teams, matches, squads, fantasy points |
190
+ | `syncFantasyBundle` / `updateCachedCompetitions` | Bulk sync helpers |
191
+ | `resolveCredentials` | Detect free vs paid StatsBomb login |
192
+ | `scoreFantasyPoints` | Default fantasy scoring rules |
193
+ | Types | `Competition`, `Season`, `Team`, `Match`, `Player`, `LineupEntry`, … |
194
+
98
195
  ---
99
196
 
100
- ## Supported data (open sources)
197
+ ## CLI cheat sheet
101
198
 
102
- | Source | Coverage | Notes |
103
- |--------|----------|-------|
104
- | **StatsBomb Open Data** | Liga F, WSL, NWSL, Serie A Women, Frauen Bundesliga, Women's World Cup, UEFA Women's Euro | Clubs + national teams; optional player stats / lineups |
105
- | **FBref** | WSL + Liga F schedules (pilot) | Live HTML may hit Cloudflare |
199
+ ```bash
200
+ npx campus sync --fantasy|--all [--with-players] [--player-stats-limit <n>]
201
+ npx campus sync --competition <name> [--source statsbomb|fbref] [--with-players]
202
+ npx campus update
203
+ npx campus pull
204
+ npx campus available
205
+ npx campus credentials
206
+ npx campus endpoints
207
+ npx campus competitions
208
+ npx campus seasons --competition <name>
209
+ npx campus teams --competition <name>
210
+ npx campus matches --competition <name> [--season <name>] [--team <name>]
211
+ npx campus players [--team <name>] [--name <name>]
212
+ npx campus player-stats [--competition <name>] [--match <id>] [--player <name>]
213
+ npx campus lineups [--match <id>] [--team <name>]
214
+ npx campus squad --competition <name> --team <name>
215
+ npx campus fantasy-points [--competition <name>] [--player <name>]
216
+ npx campus identities propose --competition <name>
217
+ ```
106
218
 
107
- Injuries are **not** in these open feeds yet — the API is ready, the list is empty.
219
+ Paid extras (require `SB_USERNAME` / `SB_PASSWORD`):
220
+ `--with-paid-player-match-stats`, `--with-paid-team-match-stats`,
221
+ `--with-paid-player-season-stats`, `--with-paid-team-season-stats`,
222
+ `--with-paid-360`.
108
223
 
109
224
  ---
110
225
 
111
- ## Why this shape
226
+ ## Keep data fresh
112
227
 
113
- - **One canonical schema** (`Competition`, `Season`, `Team`, `Match`, …). Adapters translate; the app never sees provider field names.
114
- - **Provenance on every record** (`sources: [{ source, id }]`) so cross-source identity is possible.
115
- - **Local-first cache** (JSON by default, SQLite optional) no hosted database required for the library.
228
+ - **Pull a published snapshot:** `npx campus pull` or `CampusClient.fromBundle()`
229
+ (this repo can publish a daily `data-latest` release via GitHub Actions).
230
+ - **Sync yourself:** `npx campus sync --fantasy` or `npx campus update`.
116
231
 
117
232
  ---
118
233
 
119
- ## Docs
234
+ ## Design
120
235
 
121
- - https://campus-tawny-mu.vercel.app/
236
+ - **One schema** — your app never sees provider field names.
237
+ - **Provenance** — every record carries `sources: [{ source, id }]`.
238
+ - **Local-first** — JSON cache by default; SQLite optional (`--sqlite`).
122
239
 
123
240
  ---
124
241
 
125
- ## Data source & terms
242
+ ## Terms
126
243
 
127
244
  **Code is MIT. Data is not ours to relicense.**
128
245
 
129
- - [StatsBomb Open Data](https://github.com/statsbomb/open-data): free for research and genuine football analytics. Credit StatsBomb in published analysis ([media pack](https://statsbomb.com/media-pack/)).
130
- - FBref / Sports Reference: respect site terms, `robots.txt`, and rate limits.
246
+ - [StatsBomb Open Data](https://github.com/statsbomb/open-data) free for research and genuine football analytics; credit StatsBomb ([media pack](https://statsbomb.com/media-pack/)).
247
+ - StatsBomb paid API your Hudl StatsBomb contract; never commit `SB_USERNAME` / `SB_PASSWORD`.
248
+ - FBref / Sports Reference — respect site terms, `robots.txt`, and rate limits.
131
249
 
132
- Pass those requirements downstream.
250
+ Pass those requirements downstream to your users.
133
251
 
134
252
  ---
135
253
 
136
254
  ## License
137
255
 
138
- Code: MIT (see [`LICENSE`](./LICENSE)). Data: subject to each source's terms.
256
+ Code: MIT (see [`LICENSE`](./LICENSE)).
257
+ Data: subject to each upstream source’s terms.
258
+
259
+ Source: https://github.com/Minacava/campus-stats
package/dist/cache.js CHANGED
@@ -12,7 +12,6 @@ export function emptyCache() {
12
12
  players: [],
13
13
  playerMatchStats: [],
14
14
  lineups: [],
15
- injuries: [],
16
15
  };
17
16
  }
18
17
  export function cachePath(cwd = process.cwd()) {
@@ -31,7 +30,6 @@ export async function loadCache(filePath = cachePath()) {
31
30
  players: parsed.players ?? [],
32
31
  playerMatchStats: parsed.playerMatchStats ?? [],
33
32
  lineups: parsed.lineups ?? [],
34
- injuries: parsed.injuries ?? [],
35
33
  };
36
34
  }
37
35
  catch (err) {
@@ -64,6 +62,5 @@ export function mergeSyncResult(cache, result) {
64
62
  players: mergeById(cache.players, result.players ?? []),
65
63
  playerMatchStats: mergeById(cache.playerMatchStats, result.playerMatchStats ?? []),
66
64
  lineups: mergeById(cache.lineups, result.lineups ?? []),
67
- injuries: mergeById(cache.injuries, result.injuries ?? []),
68
65
  };
69
66
  }