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 +33 -0
- package/LICENSE +1 -1
- package/README.md +190 -69
- package/dist/cache.js +0 -3
- package/dist/cli.js +145 -42
- package/dist/client.d.ts +1 -6
- package/dist/client.js +3 -13
- package/dist/credentials.d.ts +91 -0
- package/dist/credentials.js +145 -0
- package/dist/data-bundle.d.ts +8 -7
- package/dist/data-bundle.js +12 -11
- package/dist/db/sqlite-store.d.ts +1 -1
- package/dist/db/sqlite-store.js +0 -36
- package/dist/fantasy.js +0 -4
- package/dist/http.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3 -4
- package/dist/sources/create.d.ts +16 -0
- package/dist/sources/create.js +23 -0
- package/dist/sources/fbref.d.ts +3 -0
- package/dist/sources/fbref.js +3 -0
- package/dist/sources/index.d.ts +6 -0
- package/dist/sources/index.js +2 -0
- package/dist/sources/statsbomb-endpoints.d.ts +57 -0
- package/dist/sources/statsbomb-endpoints.js +169 -0
- package/dist/sources/statsbomb.d.ts +59 -9
- package/dist/sources/statsbomb.js +177 -19
- package/dist/sources/types.d.ts +1 -2
- package/dist/types.d.ts +0 -16
- package/package.json +5 -4
- package/dist/injuries.d.ts +0 -12
- package/dist/injuries.js +0 -15
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
package/README.md
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
# Campus (`campus-stats`)
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**A data layer for women's football — not a data vendor.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
35
|
+
---
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
## Try the free path (no account)
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
Open Data is wired in. No signup, no API key:
|
|
31
40
|
|
|
32
|
-
|
|
41
|
+
```bash
|
|
42
|
+
# Sync one competition from StatsBomb Open Data
|
|
43
|
+
npx campus sync --competition "Liga F"
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
# Or every women's competition in the open catalogue
|
|
46
|
+
npx campus sync --fantasy
|
|
36
47
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// or: const client = await CampusClient.fromBundle();
|
|
48
|
+
# Optional: lineups + basic player stats (capped)
|
|
49
|
+
npx campus sync --fantasy --with-players
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
57
|
+
# Confirm you are on free Open Data
|
|
58
|
+
npx campus credentials
|
|
59
|
+
# → statsbomb.mode: "open-data"
|
|
48
60
|
```
|
|
49
61
|
|
|
50
|
-
|
|
62
|
+
Data is stored in `.campus/cache.json` (or use `--sqlite` / `--db <path>`).
|
|
51
63
|
|
|
52
|
-
|
|
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
|
-
|
|
71
|
+
Coverage and freshness follow what those platforms publish for free.
|
|
64
72
|
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
+
### 1. Connect credentials
|
|
74
83
|
|
|
75
|
-
|
|
84
|
+
Same env vars as [statsbombpy](https://github.com/statsbomb/statsbombpy):
|
|
76
85
|
|
|
77
86
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
npx campus
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
|
|
113
|
+
### 2. Sync (same commands as free)
|
|
91
114
|
|
|
92
115
|
```bash
|
|
93
116
|
npx campus sync --competition "Liga F"
|
|
94
|
-
npx campus sync --
|
|
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
|
-
##
|
|
197
|
+
## CLI cheat sheet
|
|
101
198
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
226
|
+
## Keep data fresh
|
|
112
227
|
|
|
113
|
-
- **
|
|
114
|
-
|
|
115
|
-
- **
|
|
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
|
-
##
|
|
234
|
+
## Design
|
|
120
235
|
|
|
121
|
-
-
|
|
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
|
-
##
|
|
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)
|
|
130
|
-
-
|
|
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)).
|
|
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
|
}
|