nhle-api 0.5.4 → 0.7.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 +56 -0
- package/README.md +319 -234
- package/lib/index.cjs +922 -418
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +3169 -859
- package/lib/index.d.ts +3169 -859
- package/lib/index.js +899 -417
- package/lib/index.js.map +1 -1
- package/lib/nhl-B7Hg7iMB.d.cts +462 -0
- package/lib/nhl-B7Hg7iMB.d.ts +462 -0
- package/lib/toolkit.cjs +1216 -0
- package/lib/toolkit.cjs.map +1 -0
- package/lib/toolkit.d.cts +502 -0
- package/lib/toolkit.d.ts +502 -0
- package/lib/toolkit.js +1194 -0
- package/lib/toolkit.js.map +1 -0
- package/package.json +42 -11
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,62 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.7.0] - 2026-10-19
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `EdgeByTheNumbers.highDangerSavesGoalie`, the goalie with the most high-danger saves, newly returned by `adv.byTheNumbers`
|
|
15
|
+
- Live-game fields on `Scoreboard` games: `clock`, `situation` and each team's `sog`
|
|
16
|
+
- `DraftPositionCode` (`C`, `LW`, `RW`, `D`, `G`, `F`, `C/LW`, `C/RW`, `LW/RW`), used by the `draft.picks`, `draft.rankings` and `draft.tracker` response types
|
|
17
|
+
- The drift check flags position codes a response's types don't declare, and `--update` won't accept them
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `savePctgLast10` and `savePctg5v5Last10` on `adv.goalies.compare` and `adv.goalies.savePercentage5v5` are typed as `EdgeGoalieGame[]` and `EdgeGoalieGameDecision[]` instead of `unknown[]`, now that the API fills them
|
|
22
|
+
- **Breaking:** `PositionCode` is now `'C' | 'L' | 'R' | 'D' | 'G'`. Outside the draft endpoints the API sends `L`/`R` for wingers, never `LW`/`RW`
|
|
23
|
+
|
|
24
|
+
## [0.6.0] - 2026-10-03
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `stats` namespace for the Stats API (`api.nhle.com/stats/rest`): skater, goalie and team reports, leaders, milestones, teams, seasons, games, shift charts, drafts, config, countries, glossary and franchises
|
|
29
|
+
- `getStats(report, params)` for skaters, goalies and teams, with `SkaterReport`, `GoalieReport` and `TeamReport` unions of the report names
|
|
30
|
+
- Response types for every `adv` function (`EdgeSkaterDetail`, `EdgeTeamZoneTime`, ...) and `LocalizedText`
|
|
31
|
+
- `video.metadata(videoId)` for Brightcove video titles, descriptions and sources
|
|
32
|
+
- Root exports: `APIResult`, `NHLClient`, `createNHLClient`, `BASE_URLS`, the error classes (`NHLError`, `NotFoundError`, `ValidationError`...), `ErrorCategory`, `ErrorLogLevel`, and the Cayenne query builder
|
|
33
|
+
- `nhle-api/toolkit` entry point with constants, date helpers, `resolvePath`, `normalizeAbbrev`, the Cayenne query builder, and team branding (colors and logo URLs)
|
|
34
|
+
- `NHLClient` accepts an options object (`baseUrl`, `timeout`, `language`, `headers`, `errorConfig`)
|
|
35
|
+
- Level-aware `logger` and `writeLog`
|
|
36
|
+
- Daily API drift check (`bun run drift`, GitHub workflow "API drift") covering every public function
|
|
37
|
+
- CI on pull requests (lint, typecheck, tests, build, publint and are-the-types-wrong) and a tag-triggered release workflow that publishes with npm trusted publishing
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- `config` is read on every request, so changing it at runtime takes effect; environment variable configuration was removed
|
|
42
|
+
- Invalid `adv` parameters resolve to a failed result with a `ValidationError` instead of rejecting
|
|
43
|
+
- Date parameters use the NHL's timezone (America/New_York)
|
|
44
|
+
- `require` resolves `.d.cts` type declarations; the package declares `sideEffects: false` and `engines.node >= 18`
|
|
45
|
+
- Stats API: `getPlayerInfo`, `getLeaders`, `getGames`, `teams.getAll` and `teams.getById` take query params before `lang`; `teams.getById` returns a list, matching the API
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- The build failed under TypeScript 7; builds use TypeScript 5.9
|
|
50
|
+
- Published types left out `config`, `logConfig`, `logger` and `writeLog`
|
|
51
|
+
- Edge skater and team paths, goalie top-10 save percentage paths and top-10 filter codes (23 endpoints)
|
|
52
|
+
- `postalLookup` sends Canadian postal codes in the only form the API matches
|
|
53
|
+
- `stats.skaters.getStats()` requested an unresolved `{report}` path, report functions sent no `cayenneExp` (HTTP 500), and `getStatsWithFilters` dropped most filters
|
|
54
|
+
- Functions that default to the current season used 2025-26 (the last hardcoded season); the default now follows today's date
|
|
55
|
+
|
|
56
|
+
### Deprecated
|
|
57
|
+
|
|
58
|
+
- `gc.game.whereToWatch()`: the endpoint now returns 404
|
|
59
|
+
|
|
60
|
+
### Removed
|
|
61
|
+
|
|
62
|
+
- The unused `NHLScoreboard` type
|
|
63
|
+
|
|
8
64
|
## [0.5.4] - 2026-02-10
|
|
9
65
|
|
|
10
66
|
### Added
|
package/README.md
CHANGED
|
@@ -1,234 +1,319 @@
|
|
|
1
|
-
# NHLe API Library
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/nhle-api)
|
|
4
|
-
[](https://www.npmjs.com/package/nhle-api)
|
|
5
|
-
[](LICENSE)
|
|
6
|
-
|
|
7
|
-
A modern TypeScript wrapper around the public NHL GameCenter and EdgeStats APIs with simple, composable functions and strong TypeScript typing.
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
The library exposes a small, functional surface over the NHL "Game Center" and
|
|
12
|
-
|
|
13
|
-
- Written in TypeScript and published as ESM/CJS
|
|
14
|
-
- Thin functional wrappers over official NHL API routes
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- `
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
- `
|
|
129
|
-
- `
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
- `
|
|
134
|
-
- `
|
|
135
|
-
- `
|
|
136
|
-
- `
|
|
137
|
-
- `
|
|
138
|
-
- `
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
- `
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
- `
|
|
148
|
-
- `
|
|
149
|
-
- `
|
|
150
|
-
- `
|
|
151
|
-
- `
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
- `
|
|
156
|
-
- `
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
- `
|
|
162
|
-
- `
|
|
163
|
-
- `
|
|
164
|
-
- `
|
|
165
|
-
- `
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (result.success)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
##
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
1
|
+
# NHLe API Library
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/nhle-api)
|
|
4
|
+
[](https://www.npmjs.com/package/nhle-api)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A modern TypeScript wrapper around the public NHL GameCenter and EdgeStats APIs with simple, composable functions and strong TypeScript typing.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
The library exposes a small, functional surface over the NHL "Game Center", Edge and Stats APIs and ships with response types for every endpoint.
|
|
12
|
+
|
|
13
|
+
- Written in TypeScript and published as ESM/CJS
|
|
14
|
+
- Thin functional wrappers over official NHL API routes
|
|
15
|
+
- Typed responses for Game Center (`gc`), Edge advanced stats (`adv`), the Stats API (`stats`) and video metadata (`video`)
|
|
16
|
+
- Every function resolves to an `APIResult` instead of throwing
|
|
17
|
+
- Runtime configuration for timeouts, language and logging
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install nhle-api
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The package ships both ESM and CJS builds; use standard `import`/`require` according to your toolchain.
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
The primary entrypoint is the Game Center API namespace `gc`:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { gc } from 'nhle-api';
|
|
33
|
+
|
|
34
|
+
// Get game landing page data
|
|
35
|
+
const gameInfo = await gc.game.landing(2023020001);
|
|
36
|
+
|
|
37
|
+
// Get live play-by-play
|
|
38
|
+
const playByPlay = await gc.game.playByPlay(2023020001);
|
|
39
|
+
|
|
40
|
+
// Get boxscore
|
|
41
|
+
const boxscore = await gc.game.boxscore(2023020001);
|
|
42
|
+
|
|
43
|
+
// Get today's scores
|
|
44
|
+
const scores = await gc.score(new Date());
|
|
45
|
+
|
|
46
|
+
// Get current scoreboard
|
|
47
|
+
const scoreboard = await gc.scoreboard();
|
|
48
|
+
|
|
49
|
+
// Get team roster
|
|
50
|
+
const roster = await gc.team.roster('TOR');
|
|
51
|
+
|
|
52
|
+
// Get player landing page (Connor McDavid)
|
|
53
|
+
const player = await gc.player.landing(8478402);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
`config` holds the shared defaults. Change it at runtime; every request reads it, so changes apply even after the API modules are loaded:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { config, logConfig } from 'nhle-api';
|
|
62
|
+
|
|
63
|
+
config.timeout = 10000; // ms, default 5000
|
|
64
|
+
config.language = 'fr'; // 'en' (default) or 'fr'
|
|
65
|
+
config.logLevel = 'error'; // 'silent' | 'error' | 'warn' (default) | 'info' | 'debug'
|
|
66
|
+
|
|
67
|
+
logConfig();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See `docs/CONFIGURATION.md` for per-client settings.
|
|
71
|
+
|
|
72
|
+
## Top-Level Exports
|
|
73
|
+
|
|
74
|
+
The package root `nhle-api` re-exports the API namespaces, configuration, the HTTP client, error classes, constants and types:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
// API namespaces
|
|
78
|
+
import { adv, gc, stats, video } from 'nhle-api';
|
|
79
|
+
|
|
80
|
+
// Configuration and logging
|
|
81
|
+
import { config, logConfig, logger } from 'nhle-api';
|
|
82
|
+
|
|
83
|
+
// Result type and errors
|
|
84
|
+
import { NHLError, NotFoundError, ValidationError } from 'nhle-api';
|
|
85
|
+
import type { APIResult } from 'nhle-api';
|
|
86
|
+
|
|
87
|
+
// Your own client (custom base URL, headers, timeout, error handling)
|
|
88
|
+
import { NHLClient, createNHLClient } from 'nhle-api';
|
|
89
|
+
|
|
90
|
+
// Cayenne filter builder for `stats`
|
|
91
|
+
import { CayenneQueryBuilder } from 'nhle-api';
|
|
92
|
+
|
|
93
|
+
// Response and parameter types
|
|
94
|
+
import type { EdgeSkaterDetail, GamecenterLanding, Season } from 'nhle-api';
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Toolkit Entry Point
|
|
98
|
+
|
|
99
|
+
Use the `nhle-api/toolkit` subpath when you only need NHL constants and shared helpers. It does not load the API clients or configuration:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import {
|
|
103
|
+
NHL,
|
|
104
|
+
getCurrentSeason,
|
|
105
|
+
normalizeAbbrev,
|
|
106
|
+
resolvePath,
|
|
107
|
+
} from 'nhle-api/toolkit';
|
|
108
|
+
|
|
109
|
+
const season = getCurrentSeason();
|
|
110
|
+
const team = normalizeAbbrev('TB'); // 'TBL'
|
|
111
|
+
const teamPath = resolvePath('/teams/{team}', { team });
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This entry point exports `NHL`, date helpers, `normalizeAbbrev`, `resolvePath`,
|
|
115
|
+
the Cayenne query builder, team branding data, historical team palettes, and
|
|
116
|
+
official logo URL helpers.
|
|
117
|
+
|
|
118
|
+
## Game Center API (`gc`)
|
|
119
|
+
|
|
120
|
+
`gc` is the primary namespace for accessing live and historical NHL data.
|
|
121
|
+
|
|
122
|
+
### `gc.game` – Game Data
|
|
123
|
+
|
|
124
|
+
- `playByPlay(gameId)` – Full live play-by-play event stream
|
|
125
|
+
- `boxscore(gameId)` – Boxscore and team/player stats for a game
|
|
126
|
+
- `landing(gameId)` – Game landing page data (summary, lines, etc.)
|
|
127
|
+
- `reports(gameId)` – Game reports / right-rail data
|
|
128
|
+
- `schedule(date?)` – Schedule for a given date (defaults to today)
|
|
129
|
+
- `scheduleCalendar(date?)` – Calendar-style schedule for a date
|
|
130
|
+
- `playoffBracket(year?)` – Playoff bracket for a given year
|
|
131
|
+
- `playoffSeries(season?)` – Playoff series information for a season
|
|
132
|
+
- `playoffSeriesSchedule(season, seriesLetter)` – Schedule for a playoff series
|
|
133
|
+
- `whereToWatch()` – Regional broadcast / streaming info (deprecated: the NHL retired this endpoint and it returns 404)
|
|
134
|
+
- `networkTVSchedule(date?)` – National TV schedule
|
|
135
|
+
- `wsc.gameStory(gameId)` – Game story from the web service collection
|
|
136
|
+
- `wsc.playByPlay(gameId)` – Play-by-play from the web service collection
|
|
137
|
+
- `pptReplay.goal(gameId, eventId)` – Goal replay data for a specific event
|
|
138
|
+
- `pptReplay.event(date?)` – Replay events for a given date (does not appear to be functional at this time)
|
|
139
|
+
|
|
140
|
+
### `gc.score` – Scores & Scoreboards
|
|
141
|
+
|
|
142
|
+
- `score(date?)` – Scores for a given date (defaults to today)
|
|
143
|
+
- `scoreboard()` – Current live scoreboard
|
|
144
|
+
|
|
145
|
+
### `gc.team` – Team Data
|
|
146
|
+
|
|
147
|
+
- `roster(teamCode, season?)` – Team roster for a given season
|
|
148
|
+
- `rosterSeasons(teamCode)` – Available roster seasons for a team
|
|
149
|
+
- `prospects(teamCode)` – Team prospects
|
|
150
|
+
- `clubStats(teamCode, season?)` – Club stats for a team/season
|
|
151
|
+
- `clubStatsSeason(teamCode)` – Season-level club stats
|
|
152
|
+
- `standings(date?)` – Standings for a given date
|
|
153
|
+
- `standingsSeason()` – Season standings
|
|
154
|
+
- `schedule.now(teamCode)` – Current schedule segment for a team
|
|
155
|
+
- `schedule.month(teamCode, month)` – Team schedule for a given month
|
|
156
|
+
- `schedule.season(teamCode, season)` – Full season schedule for a team
|
|
157
|
+
|
|
158
|
+
### `gc.player` – Player Data
|
|
159
|
+
|
|
160
|
+
- `landing(playerId)` – Player landing page data
|
|
161
|
+
- `gameLog(playerId, season?, gameType?)` – Game log for a player
|
|
162
|
+
- `spotlight()` – Featured players (spotlight carousel)
|
|
163
|
+
- `search(query)` – Player search
|
|
164
|
+
- `statsLeaders.season(season?, gameType?, category?, limit?)` – Season stat leaders
|
|
165
|
+
- `statsLeaders.current(gameType?, category?, limit?)` – Current stat leaders
|
|
166
|
+
|
|
167
|
+
### `gc.draft` – Draft Data
|
|
168
|
+
|
|
169
|
+
- `picks(year?)` – Draft picks for a given year
|
|
170
|
+
- `tracker()` – Draft tracker
|
|
171
|
+
- `rankings(year?)` – Draft rankings (all, NA/International, skaters/goalies)
|
|
172
|
+
|
|
173
|
+
### `gc.misc` – Miscellaneous
|
|
174
|
+
|
|
175
|
+
- `seasons()` – All NHL seasons
|
|
176
|
+
- `meta.game(gameId)` – Game metadata
|
|
177
|
+
- `meta.gameVideo(gameId)` – Game video metadata
|
|
178
|
+
- `postalLookup(postalCode)` – Postal/ZIP lookup (location info)
|
|
179
|
+
- `location()` – Location info for current context
|
|
180
|
+
- `partnerGame(country, date?)` – Partner game information
|
|
181
|
+
|
|
182
|
+
## Edge Advanced Stats (`adv`)
|
|
183
|
+
|
|
184
|
+
NHL Edge puck and player tracking data (`api-web.nhle.com/v1/edge`), with response types for every function (`EdgeSkaterDetail`, `EdgeTeamZoneTime`, ...).
|
|
185
|
+
|
|
186
|
+
- `adv.skaters`: `detail`, `comparison`, `leaders`, `shotLocation`, `shotSpeed`, `skatingDistance`, `skatingSpeed`, `zoneTime`, and `top10.{distance, shotLocation, shotSpeed, speed, zoneTime}`
|
|
187
|
+
- `adv.goalies`: `player`, `compare`, `leaders`, `savePercentage`, `savePercentage5v5`, `saveLocation`, and `top10.{savePercentage, savePercentage5v5, saveLocation}`
|
|
188
|
+
- `adv.teams`: `stats`, `compare`, `leaders`, `shotLocation`, `shotSpeed`, `skatingDistance`, `skatingSpeed`, `zoneTime`, and `top10.{shotLocation, shotSpeed, skatingDistance, skatingSpeed, zoneTime}`
|
|
189
|
+
- `adv.byTheNumbers()`: the Edge home page's daily highlights
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
const result = await adv.skaters.detail(8478402, 20242025, 2);
|
|
193
|
+
if (result.success) console.log(result.data.skatingSpeed.speedMax.imperial);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Stats API (`stats`)
|
|
197
|
+
|
|
198
|
+
The stats.nhl.com reports (`api.nhle.com/stats/rest`). List endpoints answer `{ data, total }` and accept `cayenneExp`, `sort`, `dir`, `limit` and `start`.
|
|
199
|
+
|
|
200
|
+
- `stats.skaters` / `stats.goalies` / `stats.teams`: `getStats(report, params)` for any report (`summary`, `realtime`, `powerplay`...; `SkaterReport`, `GoalieReport` and `TeamReport` list them), plus `getStatsWithParams`, `getStatsWithBuilder` and `getStatsWithFilters`
|
|
201
|
+
- `stats.skaters.getPlayerInfo(params)`, `getLeaders(category, params)`, `getMilestones()`; the same leaders and milestones for goalies
|
|
202
|
+
- `stats.teams.getAll(params)`, `getById(teamId, params)`
|
|
203
|
+
- `stats.season`: `getSeasons()`, `getGames(params)`, `getShiftChart(gameId)`, `getDraft()`
|
|
204
|
+
- `stats.misc`: `getConfig()` (every report's columns), `getCountries()`, `getGlossary()`, `getFranchises()`
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import { stats } from 'nhle-api';
|
|
208
|
+
|
|
209
|
+
const result = await stats.skaters.getStats('summary', {
|
|
210
|
+
cayenneExp: 'seasonId=20242025 and gameTypeId=2',
|
|
211
|
+
sort: 'points',
|
|
212
|
+
dir: 'desc',
|
|
213
|
+
limit: 10,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Or with the query builder
|
|
217
|
+
const goalies = await stats.goalies.getStatsWithBuilder('summary', (q) => ({
|
|
218
|
+
cayenneExp: q.equals('seasonId', 20242025).greaterThan('gamesPlayed', 20).build(),
|
|
219
|
+
sort: 'savePct',
|
|
220
|
+
dir: 'desc',
|
|
221
|
+
}));
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
See [docs/QUERY_BUILDER_GUIDE.md](docs/QUERY_BUILDER_GUIDE.md) for the builder.
|
|
225
|
+
|
|
226
|
+
## Video (`video`)
|
|
227
|
+
|
|
228
|
+
- `video.metadata(videoId)`: title, descriptions, duration, poster and playable sources (with the best MP4 as `url`) for a Brightcove video id, such as a goal's `highlightClip` in `gc.game.landing`
|
|
229
|
+
|
|
230
|
+
## Types
|
|
231
|
+
|
|
232
|
+
Response types are exported for every endpoint: Game Center (`GamecenterLanding`, `TeamRoster`...), Edge (`Edge*`) and the Stats API (`stats.SkaterStats`, `stats.Team`...), along with parameter types (`Season`, `GameId`, `TeamAbbrev`...) and shared shapes such as `LocalizedText`.
|
|
233
|
+
|
|
234
|
+
### Results and errors
|
|
235
|
+
|
|
236
|
+
Functions never throw for API failures. Each resolves to an `APIResult<T>`:
|
|
237
|
+
|
|
238
|
+
- `{ success: true, data }` on success.
|
|
239
|
+
- `{ success: false, error }` otherwise, where `error` is an `NHLError` subclass: `NotFoundError` (404), `ClientError` (other 4xx), `ServerError` (5xx), `RateLimitError` (429), `NetworkError`, or `ValidationError` for parameters rejected before any request.
|
|
240
|
+
- `error.category` and `error.context` (endpoint, status code, response body) carry the details.
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { gc, NotFoundError } from 'nhle-api';
|
|
244
|
+
import type { APIResult, GamecenterLanding } from 'nhle-api';
|
|
245
|
+
|
|
246
|
+
const result: APIResult<GamecenterLanding> = await gc.game.landing(2023020001);
|
|
247
|
+
|
|
248
|
+
if (result.success) {
|
|
249
|
+
console.log(result.data.venue.default);
|
|
250
|
+
} else if (result.error instanceof NotFoundError) {
|
|
251
|
+
console.log('No such game');
|
|
252
|
+
} else {
|
|
253
|
+
console.error(result.error.category, result.error.message);
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Roadmap / Status
|
|
258
|
+
|
|
259
|
+
- ✅ Game Center endpoints with response types
|
|
260
|
+
- ✅ Edge Advanced (`adv`) endpoints with response types
|
|
261
|
+
- ✅ Stats API (`stats`) endpoints with typed reports
|
|
262
|
+
- ✅ Runtime configuration (`config`) and per-client settings (`NHLClient`)
|
|
263
|
+
- ✅ Error classes and `APIResult` exported
|
|
264
|
+
- ✅ Daily drift check against the live APIs
|
|
265
|
+
|
|
266
|
+
For a detailed list of changes, see `CHANGELOG.md`.
|
|
267
|
+
|
|
268
|
+
## Docs
|
|
269
|
+
|
|
270
|
+
- [Configuration](docs/CONFIGURATION.md) - Code-defined configuration and default values
|
|
271
|
+
- [Query Builder Guide](docs/QUERY_BUILDER_GUIDE.md) - Cayenne query builder for stats APIs
|
|
272
|
+
|
|
273
|
+
## Contributing
|
|
274
|
+
|
|
275
|
+
This project is still evolving and feedback is very welcome.
|
|
276
|
+
|
|
277
|
+
- **Bug reports / issues:** If an endpoint returns unexpected data, response parsing fails, or types don’t match the real API, please open a GitHub issue with the endpoint, parameters, and (sanitized) sample payloads if possible.
|
|
278
|
+
- **Type improvements:** PRs or issues that improve response coverage, fix missing/incorrect fields, or refine enums and unions are particularly helpful.
|
|
279
|
+
- **JSDoc / docs:** Additions or corrections to JSDoc on public types and functions, or clarifications to the guides in `docs/`, are also very much appreciated.
|
|
280
|
+
|
|
281
|
+
Before filing an issue, check the `CHANGELOG.md` for recent changes and breaking notes, and include the library version you’re using.
|
|
282
|
+
|
|
283
|
+
## API drift check
|
|
284
|
+
|
|
285
|
+
The NHL APIs are undocumented and change without notice. `bun run drift` calls every public function against the live APIs (with a finished season, game and draft) and compares each response's structure with `scripts/drift/baseline.json`. It fails when an endpoint stops answering, an error response changes, or a field is added, removed or changes type. Values are ignored, and so are fields that turn `null`. Translations in localized strings (`{ default, fr, cs, ... }`) count as one field.
|
|
286
|
+
|
|
287
|
+
The **API drift** workflow runs it daily and on demand (Actions → API drift → Run workflow). A failure opens one `api-drift` issue with the report, which the next passing run closes. It never runs on PRs, so upstream changes don't block unrelated work.
|
|
288
|
+
|
|
289
|
+
When an API really has changed:
|
|
290
|
+
|
|
291
|
+
1. Update the response types in `src/types/responses/`.
|
|
292
|
+
2. Accept the new shapes with `bun run drift --update` and commit the baseline.
|
|
293
|
+
|
|
294
|
+
Checks for date- or location-dependent data (scoreboard, draft tracker) are marked `volatile`: a field missing today is only noted, and `--update` adds to their baseline instead of replacing it. When you add a library function, add a check in `scripts/drift/checks.ts`; `test/unit/drift.test.ts` fails if a public function has none.
|
|
295
|
+
|
|
296
|
+
## Releasing
|
|
297
|
+
|
|
298
|
+
1. Move the `Unreleased` notes in `CHANGELOG.md` under the new version.
|
|
299
|
+
2. Bump the version and tag it: `npm version patch` (or `minor`/`major`).
|
|
300
|
+
3. Push the commit and tag: `git push --follow-tags`.
|
|
301
|
+
|
|
302
|
+
4. Approve the staged version with 2FA, on npmjs.com (the package's **Staged Packages** tab) or with `npm stage approve <stage-id>`.
|
|
303
|
+
|
|
304
|
+
The **Release** workflow checks that the tag matches `package.json`, runs the full CI suite and `check:package`, stages the version on npm with provenance, and creates a GitHub release. It uses [npm trusted publishing](https://docs.npmjs.com/trusted-publishers), so there is no npm token in the repo, and [staged publishing](https://docs.npmjs.com/staged-publishing), so nothing goes live until a maintainer approves it.
|
|
305
|
+
|
|
306
|
+
One-time setup on npmjs.com:
|
|
307
|
+
|
|
308
|
+
1. Open the `nhle-api` package's **Settings → Trusted publishing** and add GitHub Actions with user `spiflicate`, repository `nhle-api` and workflow `release.yml`. Leave "Allow npm publish" and "Allow npm dist-tag" unchecked, so CI can only stage.
|
|
309
|
+
2. Under **Publishing access**, choose "Require two-factor authentication and disallow tokens".
|
|
310
|
+
|
|
311
|
+
## Support
|
|
312
|
+
|
|
313
|
+
If you find this library helpful, consider supporting its development:
|
|
314
|
+
|
|
315
|
+
[](https://ko-fi.com/R6R01DV0JD)
|
|
316
|
+
|
|
317
|
+
## License
|
|
318
|
+
|
|
319
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|