nhl-api-ts 0.2.1 → 0.3.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.
Files changed (40) hide show
  1. package/README.md +72 -5
  2. package/dist/api/draft.d.mts +61 -0
  3. package/dist/api/draft.mjs +68 -0
  4. package/dist/api/edge.d.mts +198 -1
  5. package/dist/api/edge.mjs +207 -4
  6. package/dist/api/game-center.d.mts +49 -1
  7. package/dist/api/game-center.mjs +47 -0
  8. package/dist/api/misc.d.mts +115 -1
  9. package/dist/api/misc.mjs +147 -2
  10. package/dist/api/players.d.mts +55 -3
  11. package/dist/api/players.mjs +80 -3
  12. package/dist/api/query/cayenne.d.mts +4 -0
  13. package/dist/api/query/cayenne.mjs +13 -0
  14. package/dist/api/query/sorting/sorting-options.d.mts +8 -0
  15. package/dist/api/query/sorting/sorting-options.mjs +30 -0
  16. package/dist/api/schedule.d.mts +19 -6
  17. package/dist/api/schedule.mjs +17 -5
  18. package/dist/api/stats.d.mts +95 -6
  19. package/dist/api/stats.mjs +130 -30
  20. package/dist/api/teams.d.mts +43 -3
  21. package/dist/api/teams.mjs +51 -3
  22. package/dist/cli/commands.mjs +487 -22
  23. package/dist/http-client.d.mts +2 -1
  24. package/dist/http-client.mjs +8 -1
  25. package/dist/index.d.mts +8 -2
  26. package/dist/index.mjs +3 -0
  27. package/dist/nhl-client.d.mts +69 -14
  28. package/dist/nhl-client.mjs +33 -12
  29. package/dist/types/draft.d.mts +97 -0
  30. package/dist/types/draft.mjs +1 -0
  31. package/dist/types/edge.d.mts +299 -3
  32. package/dist/types/game-center.d.mts +223 -8
  33. package/dist/types/index.d.mts +1 -0
  34. package/dist/types/misc.d.mts +101 -0
  35. package/dist/types/misc.mjs +0 -1
  36. package/dist/types/players.d.mts +22 -0
  37. package/dist/types/schedule.d.mts +16 -0
  38. package/dist/types/stats.d.mts +207 -1
  39. package/dist/types/teams.d.mts +29 -1
  40. package/package.json +1 -1
package/dist/api/edge.mjs CHANGED
@@ -1,14 +1,39 @@
1
1
  import { Endpoint } from '#src/http-client.mjs';
2
- /** "<path>/<id>/now" when no season is given, else "<path>/<id>/<season>/<gameType>". */
3
- function edgeResource(path, id, { season, gameType = 2 }) {
4
- const base = id === undefined ? path : `${path}/${id}`;
2
+ /** Player positions of an EDGE top-10 leaderboard. */
3
+ export const EdgePositions = {
4
+ ALL: 'all',
5
+ FORWARDS: 'forwards',
6
+ DEFENSE: 'defense',
7
+ };
8
+ /** Game strengths of an EDGE top-10 leaderboard. */
9
+ export const EdgeStrengths = {
10
+ ALL: 'all',
11
+ EVEN: 'es',
12
+ POWER_PLAY: 'pp',
13
+ PENALTY_KILL: 'pk',
14
+ };
15
+ /** Rink zones; the `sortBy` of the zone time top-10s. */
16
+ export const EdgeZones = {
17
+ OFFENSIVE: 'offensive',
18
+ NEUTRAL: 'neutral',
19
+ DEFENSIVE: 'defensive',
20
+ };
21
+ /**
22
+ * "<path>/<segments...>/now" when no season is given, else
23
+ * "<path>/<segments...>/<season>/<gameType>".
24
+ */
25
+ function edgeResource(path, segments, { season, gameType = 2 }) {
26
+ const base = [path, ...segments].join('/');
5
27
  if (season === undefined || season === null) {
6
28
  return `${base}/now`;
7
29
  }
8
30
  return `${base}/${season}/${gameType}`;
9
31
  }
32
+ async function getEdgeSegments(ctx, path, segments, params) {
33
+ return (await ctx.get(Endpoint.API_WEB_V1, edgeResource(path, segments, params))).json();
34
+ }
10
35
  async function getEdge(ctx, path, id, params) {
11
- return (await ctx.get(Endpoint.API_WEB_V1, edgeResource(path, id, params))).json();
36
+ return getEdgeSegments(ctx, path, id === undefined ? [] : [id], params);
12
37
  }
13
38
  // ========================
14
39
  // SKATER ENDPOINTS
@@ -203,6 +228,169 @@ export async function teamShotSpeedDetail(ctx, params) {
203
228
  export async function teamSkatingSpeedDetail(ctx, params) {
204
229
  return getEdge(ctx, 'edge/team-skating-speed-detail', params.teamId, params);
205
230
  }
231
+ // ========================
232
+ // LEADERBOARDS (TOP 10)
233
+ // ========================
234
+ /**
235
+ * Get the NHL EDGE top 10 skaters by skating distance.
236
+ *
237
+ * @param params.positions 'all' (default), 'forwards' or 'defense'
238
+ * @param params.strength 'all' (default), 'es', 'pp' or 'pk'
239
+ * @param params.sortBy 'total', 'per-60', 'max-game' or 'max-period'
240
+ * @example https://api-web.nhle.com/v1/edge/skater-distance-top-10/all/all/total/20252026/2
241
+ */
242
+ export async function skaterDistanceTop10(ctx, { positions = EdgePositions.ALL, strength = EdgeStrengths.ALL, sortBy, ...params }) {
243
+ return getEdgeSegments(ctx, 'edge/skater-distance-top-10', [positions, strength, sortBy], params);
244
+ }
245
+ /**
246
+ * Get the NHL EDGE top 10 skaters by skating speed.
247
+ *
248
+ * @param params.positions 'all' (default), 'forwards' or 'defense'
249
+ * @param params.sortBy 'max', 'over-22', '20-22' or '18-20' (bursts in mph)
250
+ * @example https://api-web.nhle.com/v1/edge/skater-speed-top-10/all/max/20252026/2
251
+ */
252
+ export async function skaterSpeedTop10(ctx, { positions = EdgePositions.ALL, sortBy, ...params }) {
253
+ return getEdgeSegments(ctx, 'edge/skater-speed-top-10', [positions, sortBy], params);
254
+ }
255
+ /**
256
+ * Get the NHL EDGE top 10 skaters by zone time.
257
+ *
258
+ * @param params.positions 'all' (default), 'forwards' or 'defense'
259
+ * @param params.strength 'all' (default), 'es', 'pp' or 'pk'
260
+ * @param params.sortBy Zone: 'offensive', 'neutral' or 'defensive'. See `EdgeZones`.
261
+ * @example https://api-web.nhle.com/v1/edge/skater-zone-time-top-10/all/all/offensive/20252026/2
262
+ */
263
+ export async function skaterZoneTimeTop10(ctx, { positions = EdgePositions.ALL, strength = EdgeStrengths.ALL, sortBy, ...params }) {
264
+ return getEdgeSegments(ctx, 'edge/skater-zone-time-top-10', [positions, strength, sortBy], params);
265
+ }
266
+ /**
267
+ * Get the NHL EDGE top 10 skaters by shot speed.
268
+ *
269
+ * @param params.positions 'all' (default), 'forwards' or 'defense'
270
+ * @param params.sortBy 'max', 'over-100', '90-99', '80-89' or '70-79' (attempts in mph)
271
+ * @example https://api-web.nhle.com/v1/edge/skater-shot-speed-top-10/all/max/20252026/2
272
+ */
273
+ export async function skaterShotSpeedTop10(ctx, { positions = EdgePositions.ALL, sortBy, ...params }) {
274
+ return getEdgeSegments(ctx, 'edge/skater-shot-speed-top-10', [positions, sortBy], params);
275
+ }
276
+ /**
277
+ * Get the NHL EDGE top 10 skaters by shot location. `sortBy` comes before
278
+ * `category` in the URL (the NHL-API-Reference has them the other way round,
279
+ * which 404s).
280
+ *
281
+ * @param params.positions 'all' (default), 'forwards' or 'defense'. 'F' / 'D' are a 404 here.
282
+ * @param params.sortBy 'sog', 'goals' or 'shooting-pctg'
283
+ * @param params.category 'all' (default), 'high', 'mid' or 'long'
284
+ * @example https://api-web.nhle.com/v1/edge/skater-shot-location-top-10/all/sog/all/20252026/2
285
+ */
286
+ export async function skaterShotLocationTop10(ctx, { positions = EdgePositions.ALL, sortBy, category = 'all', ...params }) {
287
+ return getEdgeSegments(ctx, 'edge/skater-shot-location-top-10', [positions, sortBy, category], params);
288
+ }
289
+ /**
290
+ * Get the NHL EDGE top 10 goalies by 5v5 performance.
291
+ *
292
+ * @param params.sortBy 'save-pctg', 'save-pctg-close', 'shots' or 'shots-per-60'
293
+ * @example https://api-web.nhle.com/v1/edge/goalie-5v5-top-10/save-pctg/20252026/2
294
+ */
295
+ export async function goalie5v5Top10(ctx, { sortBy, ...params }) {
296
+ return getEdgeSegments(ctx, 'edge/goalie-5v5-top-10', [sortBy], params);
297
+ }
298
+ /**
299
+ * Get the NHL EDGE top 10 goalies by shot location.
300
+ *
301
+ * @param params.sortBy 'save-pctg', 'saves', 'goals-against' or 'shots-against'
302
+ * @param params.category 'all' (default), 'high', 'mid' or 'long'
303
+ * @example https://api-web.nhle.com/v1/edge/goalie-shot-location-top-10/save-pctg/all/20252026/2
304
+ */
305
+ export async function goalieShotLocationTop10(ctx, { sortBy, category = 'all', ...params }) {
306
+ return getEdgeSegments(ctx, 'edge/goalie-shot-location-top-10', [sortBy, category], params);
307
+ }
308
+ /**
309
+ * Get the NHL EDGE top 10 goalies by games above a .900 save percentage.
310
+ *
311
+ * @param params.sortBy 'games' (count) or 'pctg' (share of games played)
312
+ * @example https://api-web.nhle.com/v1/edge/goalie-edge-save-pctg-top-10/games/20252026/2
313
+ */
314
+ export async function goalieSavePercentageTop10(ctx, { sortBy, ...params }) {
315
+ return getEdgeSegments(ctx, 'edge/goalie-edge-save-pctg-top-10', [sortBy], params);
316
+ }
317
+ /**
318
+ * Get the NHL EDGE top 10 teams by skating distance.
319
+ *
320
+ * @param params.positions 'all' (default), 'forwards' or 'defense'
321
+ * @param params.strength 'all' (default), 'es', 'pp' or 'pk'
322
+ * @param params.sortBy 'total', 'per-60', 'max-game' or 'max-period'
323
+ * @example https://api-web.nhle.com/v1/edge/team-skating-distance-top-10/all/all/total/20252026/2
324
+ */
325
+ export async function teamSkatingDistanceTop10(ctx, { positions = EdgePositions.ALL, strength = EdgeStrengths.ALL, sortBy, ...params }) {
326
+ return getEdgeSegments(ctx, 'edge/team-skating-distance-top-10', [positions, strength, sortBy], params);
327
+ }
328
+ /**
329
+ * Get the NHL EDGE top 10 teams by skating speed.
330
+ *
331
+ * @param params.positions 'all' (default), 'forwards' or 'defense'
332
+ * @param params.sortBy 'max', 'over-22', '20-22' or '18-20' (bursts in mph)
333
+ * @example https://api-web.nhle.com/v1/edge/team-skating-speed-top-10/all/max/20252026/2
334
+ */
335
+ export async function teamSkatingSpeedTop10(ctx, { positions = EdgePositions.ALL, sortBy, ...params }) {
336
+ return getEdgeSegments(ctx, 'edge/team-skating-speed-top-10', [positions, sortBy], params);
337
+ }
338
+ /**
339
+ * Get the NHL EDGE top 10 teams by zone time. There is no `positions` slot.
340
+ *
341
+ * @param params.strength 'all' (default), 'es', 'pp' or 'pk'
342
+ * @param params.sortBy Zone: 'offensive', 'neutral' or 'defensive'. See `EdgeZones`.
343
+ * @example https://api-web.nhle.com/v1/edge/team-zone-time-top-10/es/offensive/20242025/2
344
+ */
345
+ export async function teamZoneTimeTop10(ctx, { strength = EdgeStrengths.ALL, sortBy, ...params }) {
346
+ return getEdgeSegments(ctx, 'edge/team-zone-time-top-10', [strength, sortBy], params);
347
+ }
348
+ /**
349
+ * Get the NHL EDGE top 10 teams by shot speed.
350
+ *
351
+ * @param params.positions 'all' (default), 'forwards' or 'defense'
352
+ * @param params.sortBy 'max', 'over-100', '90-99', '80-89' or '70-79' (attempts in mph)
353
+ * @example https://api-web.nhle.com/v1/edge/team-shot-speed-top-10/all/max/20252026/2
354
+ */
355
+ export async function teamShotSpeedTop10(ctx, { positions = EdgePositions.ALL, sortBy, ...params }) {
356
+ return getEdgeSegments(ctx, 'edge/team-shot-speed-top-10', [positions, sortBy], params);
357
+ }
358
+ /**
359
+ * Get the NHL EDGE top 10 teams by shot location. `sortBy` comes before
360
+ * `category` in the URL (the NHL-API-Reference has them the other way round,
361
+ * which 404s).
362
+ *
363
+ * @param params.positions 'all' (default), 'forwards' or 'defense'. 'F' / 'D' are a 404 here.
364
+ * @param params.sortBy 'sog', 'goals' or 'shooting-pctg'
365
+ * @param params.category 'all' (default), 'high', 'mid' or 'long'
366
+ * @example https://api-web.nhle.com/v1/edge/team-shot-location-top-10/all/sog/all/20252026/2
367
+ */
368
+ export async function teamShotLocationTop10(ctx, { positions = EdgePositions.ALL, sortBy, category = 'all', ...params }) {
369
+ return getEdgeSegments(ctx, 'edge/team-shot-location-top-10', [positions, sortBy, category], params);
370
+ }
371
+ /**
372
+ * Get the NHL EDGE comparison statistics for a specific team.
373
+ *
374
+ * @param params.teamId NHL team id, e.g. 10
375
+ * @example await client.edge.teamComparison({ teamId: 10 })
376
+ */
377
+ export async function teamComparison(ctx, params) {
378
+ return getEdge(ctx, 'edge/team-comparison', params.teamId, params);
379
+ }
380
+ // ========================
381
+ // LEAGUE ENDPOINTS
382
+ // ========================
383
+ /**
384
+ * Get the NHL EDGE "by the numbers" league highlights. Without a season this
385
+ * is the latest game night (`games`, `gameDate` and the nightly leaders);
386
+ * with a season it is the season bests (hardest shot, top speed, longest
387
+ * distance in a game).
388
+ *
389
+ * @example https://api-web.nhle.com/v1/edge/by-the-numbers/now
390
+ */
391
+ export async function byTheNumbers(ctx, params = {}) {
392
+ return getEdge(ctx, 'edge/by-the-numbers', undefined, params);
393
+ }
206
394
  export const edgeApi = {
207
395
  skaterDetail,
208
396
  skaterShotSpeedDetail,
@@ -227,4 +415,19 @@ export const edgeApi = {
227
415
  teamLanding,
228
416
  teamShotSpeedDetail,
229
417
  teamSkatingSpeedDetail,
418
+ skaterDistanceTop10,
419
+ skaterSpeedTop10,
420
+ skaterZoneTimeTop10,
421
+ skaterShotSpeedTop10,
422
+ skaterShotLocationTop10,
423
+ goalie5v5Top10,
424
+ goalieShotLocationTop10,
425
+ goalieSavePercentageTop10,
426
+ teamSkatingDistanceTop10,
427
+ teamSkatingSpeedTop10,
428
+ teamZoneTimeTop10,
429
+ teamShotSpeedTop10,
430
+ teamShotLocationTop10,
431
+ teamComparison,
432
+ byTheNumbers,
230
433
  };
@@ -1,5 +1,5 @@
1
1
  import type { Context } from '#src/context.mjs';
2
- import type { Boxscore, DailyScores, GameLanding, GameStory, PlayByPlay, RightRail, ShiftChart } from '#src/types/index.mjs';
2
+ import type { Boxscore, DailyScores, GameLanding, GameMeta, GameStory, PlayByPlay, PlayReplay, RightRail, Scoreboard, ShiftChart, WscPlay } from '#src/types/index.mjs';
3
3
  import type { Id } from '#src/utils.mjs';
4
4
  /**
5
5
  * Get the full boxscore for a specific NHL game, including team scores,
@@ -73,6 +73,50 @@ export declare function seasonSeriesMatchup(ctx: Context, { gameId }: {
73
73
  export declare function gameStory(ctx: Context, { gameId }: {
74
74
  gameId: Id;
75
75
  }): Promise<GameStory>;
76
+ /**
77
+ * Get the league scoreboard: every game in the week around a date, grouped by
78
+ * date. Returns the week around today when no date is supplied.
79
+ *
80
+ * @param params.date Date in YYYY-MM-DD format. Defaults to "now".
81
+ * @example https://api-web.nhle.com/v1/scoreboard/2023-10-15
82
+ */
83
+ export declare function scoreboard(ctx: Context, { date }?: {
84
+ date?: string;
85
+ }): Promise<Scoreboard>;
86
+ /**
87
+ * Get the play-by-play feed nhl.com's game story widget uses. A bare array of
88
+ * plays, with a different play shape from `playByPlay`.
89
+ *
90
+ * @param params.gameId Game id, e.g. 2023020280
91
+ * @example https://api-web.nhle.com/v1/wsc/play-by-play/2023020280
92
+ */
93
+ export declare function wscPlayByPlay(ctx: Context, { gameId }: {
94
+ gameId: Id;
95
+ }): Promise<WscPlay[]>;
96
+ /**
97
+ * Get the replay card for one play-by-play event: the game header, plus a
98
+ * `goal` object (scorer, assists, highlight clip and the `pptReplayUrl`
99
+ * puck-and-player-tracking link) when the event is a goal. Any event id works.
100
+ *
101
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
102
+ * @param params.gameId Game id, e.g. 2023020280
103
+ * @param params.eventNumber The play's `eventId` from `playByPlay`, e.g. 193
104
+ * @example https://api-web.nhle.com/v1/ppt-replay/2023020280/193
105
+ */
106
+ export declare function playReplay(ctx: Context, { gameId, eventNumber }: {
107
+ gameId: Id;
108
+ eventNumber: Id;
109
+ }): Promise<PlayReplay>;
110
+ /**
111
+ * Get the metadata nhl.com uses to render a game page: the two teams, the
112
+ * season state and the game state.
113
+ *
114
+ * @param params.gameId Game id, e.g. 2023020280
115
+ * @example https://api-web.nhle.com/v1/meta/game/2023020280
116
+ */
117
+ export declare function gameMeta(ctx: Context, { gameId }: {
118
+ gameId: Id;
119
+ }): Promise<GameMeta>;
76
120
  export declare const gameCenterApi: {
77
121
  readonly boxscore: typeof boxscore;
78
122
  readonly playByPlay: typeof playByPlay;
@@ -81,4 +125,8 @@ export declare const gameCenterApi: {
81
125
  readonly shiftChartData: typeof shiftChartData;
82
126
  readonly seasonSeriesMatchup: typeof seasonSeriesMatchup;
83
127
  readonly gameStory: typeof gameStory;
128
+ readonly scoreboard: typeof scoreboard;
129
+ readonly wscPlayByPlay: typeof wscPlayByPlay;
130
+ readonly playReplay: typeof playReplay;
131
+ readonly gameMeta: typeof gameMeta;
84
132
  };
@@ -75,6 +75,49 @@ export async function seasonSeriesMatchup(ctx, { gameId }) {
75
75
  export async function gameStory(ctx, { gameId }) {
76
76
  return getWeb(ctx, `wsc/game-story/${gameId}`);
77
77
  }
78
+ /**
79
+ * Get the league scoreboard: every game in the week around a date, grouped by
80
+ * date. Returns the week around today when no date is supplied.
81
+ *
82
+ * @param params.date Date in YYYY-MM-DD format. Defaults to "now".
83
+ * @example https://api-web.nhle.com/v1/scoreboard/2023-10-15
84
+ */
85
+ export async function scoreboard(ctx, { date } = {}) {
86
+ return getWeb(ctx, `scoreboard/${date ?? 'now'}`);
87
+ }
88
+ /**
89
+ * Get the play-by-play feed nhl.com's game story widget uses. A bare array of
90
+ * plays, with a different play shape from `playByPlay`.
91
+ *
92
+ * @param params.gameId Game id, e.g. 2023020280
93
+ * @example https://api-web.nhle.com/v1/wsc/play-by-play/2023020280
94
+ */
95
+ export async function wscPlayByPlay(ctx, { gameId }) {
96
+ return getWeb(ctx, `wsc/play-by-play/${gameId}`);
97
+ }
98
+ /**
99
+ * Get the replay card for one play-by-play event: the game header, plus a
100
+ * `goal` object (scorer, assists, highlight clip and the `pptReplayUrl`
101
+ * puck-and-player-tracking link) when the event is a goal. Any event id works.
102
+ *
103
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
104
+ * @param params.gameId Game id, e.g. 2023020280
105
+ * @param params.eventNumber The play's `eventId` from `playByPlay`, e.g. 193
106
+ * @example https://api-web.nhle.com/v1/ppt-replay/2023020280/193
107
+ */
108
+ export async function playReplay(ctx, { gameId, eventNumber }) {
109
+ return getWeb(ctx, `ppt-replay/${gameId}/${eventNumber}`);
110
+ }
111
+ /**
112
+ * Get the metadata nhl.com uses to render a game page: the two teams, the
113
+ * season state and the game state.
114
+ *
115
+ * @param params.gameId Game id, e.g. 2023020280
116
+ * @example https://api-web.nhle.com/v1/meta/game/2023020280
117
+ */
118
+ export async function gameMeta(ctx, { gameId }) {
119
+ return getWeb(ctx, `meta/game/${gameId}`);
120
+ }
78
121
  export const gameCenterApi = {
79
122
  boxscore,
80
123
  playByPlay,
@@ -83,4 +126,8 @@ export const gameCenterApi = {
83
126
  shiftChartData,
84
127
  seasonSeriesMatchup,
85
128
  gameStory,
129
+ scoreboard,
130
+ wscPlayByPlay,
131
+ playReplay,
132
+ gameMeta,
86
133
  };
@@ -1,5 +1,6 @@
1
1
  import type { Context } from '#src/context.mjs';
2
- import type { Country, DraftYear, GlossaryEntry, SeasonRules, StatsConfig } from '#src/types/index.mjs';
2
+ import type { ComponentSeason, Country, DraftYear, GeoLocation, GlossaryEntry, Meta, PartnerGameOdds, PostalLookupTeam, SeasonId, SeasonRules, StatsConfig, StatsGame, TvSchedule } from '#src/types/index.mjs';
3
+ import type { Id } from '#src/utils.mjs';
3
4
  /**
4
5
  * Gets the full NHL glossary of statistical terms and abbreviations.
5
6
  *
@@ -31,10 +32,123 @@ export declare function seasonSpecificRulesAndInfo(ctx: Context): Promise<Season
31
32
  * @example https://api.nhle.com/stats/rest/en/draft
32
33
  */
33
34
  export declare function draftYearAndRounds(ctx: Context): Promise<DraftYear[]>;
35
+ /**
36
+ * Gets the season and game type the stats API currently serves by default.
37
+ *
38
+ * @example https://api.nhle.com/stats/rest/en/componentSeason
39
+ */
40
+ export declare function componentSeasons(ctx: Context): Promise<ComponentSeason[]>;
41
+ export interface GamesParams {
42
+ /** Season in YYYYYYYY format, e.g. 20232024 (about 1,500 games). */
43
+ season?: Id;
44
+ /** 1=Preseason, 2=Regular season, 3=Playoffs. */
45
+ gameType?: number;
46
+ /** NHL team id, home or away, e.g. 10. */
47
+ teamId?: Id;
48
+ /** First game date, YYYY-MM-DD (inclusive). */
49
+ startDate?: string;
50
+ /** Last game date, YYYY-MM-DD (inclusive). */
51
+ endDate?: string;
52
+ /**
53
+ * Extra filter expression, joined to the others with `and`. Only the row
54
+ * fields (`season`, `gameType`, `gameDate`, `homeTeamId`, ...) can be
55
+ * filtered; report columns like `seasonId` are a 400.
56
+ */
57
+ cayenneExp?: string;
58
+ }
59
+ /**
60
+ * Gets games from the stats API. At least one filter is required:
61
+ * unfiltered, the API sends every game ever played (about 19 MB).
62
+ *
63
+ * @param params.season Season in YYYYYYYY format, e.g. 20232024
64
+ * @param params.gameType 1=Preseason, 2=Regular season, 3=Playoffs
65
+ * @param params.teamId NHL team id, home or away, e.g. 10
66
+ * @param params.startDate First game date, YYYY-MM-DD
67
+ * @param params.endDate Last game date, YYYY-MM-DD
68
+ * @param params.cayenneExp Extra filter expression, e.g. "homeScore>=7"
69
+ * @throws RangeError When no filter is given, or a date is not YYYY-MM-DD
70
+ * @example await client.misc.games({ season: 20232024, teamId: 10, gameType: 3 })
71
+ */
72
+ export declare function games(ctx: Context, params: GamesParams): Promise<StatsGame[]>;
73
+ /**
74
+ * Gets the national TV schedule for the week around a date, grouped by date.
75
+ *
76
+ * @param params.date Date in YYYY-MM-DD format. Defaults to "now".
77
+ * @example https://api-web.nhle.com/v1/network/tv-schedule/2023-10-15
78
+ */
79
+ export declare function tvSchedule(ctx: Context, { date }?: {
80
+ date?: string;
81
+ }): Promise<TvSchedule>;
82
+ /**
83
+ * Gets betting odds for today's games from the NHL's odds partner in a
84
+ * country.
85
+ *
86
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
87
+ * @param params.countryCode Two-letter country code, e.g. US, CA
88
+ * @example https://api-web.nhle.com/v1/partner-game/US/now
89
+ */
90
+ export declare function partnerGameOdds(ctx: Context, { countryCode }: {
91
+ countryCode: string;
92
+ }): Promise<PartnerGameOdds>;
93
+ /**
94
+ * Gets every NHL season id, oldest first.
95
+ *
96
+ * @example https://api-web.nhle.com/v1/season
97
+ */
98
+ export declare function seasonIds(ctx: Context): Promise<SeasonId[]>;
99
+ /**
100
+ * Gets display metadata (names, headshots, logos) for players and teams.
101
+ * Lists you leave out or pass empty come back empty.
102
+ *
103
+ * @param params.players Player ids, e.g. [8478402]
104
+ * @param params.teams Team abbreviations, e.g. ['TOR', 'BUF']
105
+ * @example https://api-web.nhle.com/v1/meta?players=8478402&teams=TOR,BUF
106
+ */
107
+ export declare function meta(ctx: Context, { players, teams }?: {
108
+ players?: Id[];
109
+ teams?: string[];
110
+ }): Promise<Meta>;
111
+ /**
112
+ * Gets the caller's country, looked up from their IP address. The answer
113
+ * depends on where the request comes from.
114
+ *
115
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
116
+ * @example https://api-web.nhle.com/v1/location
117
+ */
118
+ export declare function location(ctx: Context): Promise<GeoLocation>;
119
+ /**
120
+ * Gets the teams whose local broadcast market covers a postal code. Empty
121
+ * for codes outside every market.
122
+ *
123
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
124
+ * @param params.postalCode Postal or ZIP code, e.g. 90210 or "M5V 3L9"
125
+ * @example https://api-web.nhle.com/v1/postal-lookup/90210
126
+ */
127
+ export declare function postalLookup(ctx: Context, { postalCode }: {
128
+ postalCode: string;
129
+ }): Promise<PostalLookupTeam[]>;
130
+ /**
131
+ * Checks that the stats API is up. Resolves `true` on success; it never
132
+ * resolves `false`, since any failure throws an `NHLApiException` subclass
133
+ * (or a network error).
134
+ *
135
+ * @throws ServerErrorException When the stats API answers 5xx
136
+ * @example https://api.nhle.com/stats/rest/ping
137
+ */
138
+ export declare function ping(ctx: Context): Promise<true>;
34
139
  export declare const miscApi: {
35
140
  readonly glossary: typeof glossary;
36
141
  readonly config: typeof config;
37
142
  readonly countries: typeof countries;
38
143
  readonly seasonSpecificRulesAndInfo: typeof seasonSpecificRulesAndInfo;
39
144
  readonly draftYearAndRounds: typeof draftYearAndRounds;
145
+ readonly componentSeasons: typeof componentSeasons;
146
+ readonly games: typeof games;
147
+ readonly tvSchedule: typeof tvSchedule;
148
+ readonly partnerGameOdds: typeof partnerGameOdds;
149
+ readonly seasonIds: typeof seasonIds;
150
+ readonly meta: typeof meta;
151
+ readonly location: typeof location;
152
+ readonly postalLookup: typeof postalLookup;
153
+ readonly ping: typeof ping;
40
154
  };
package/dist/api/misc.mjs CHANGED
@@ -1,8 +1,13 @@
1
+ import { andClauses, cayenneString } from '#src/api/query/cayenne.mjs';
2
+ import { normalizeDate } from '#src/api/schedule.mjs';
1
3
  import { Endpoint } from '#src/http-client.mjs';
2
- async function getData(ctx, resource) {
3
- const response = await (await ctx.get(Endpoint.API_CORE, resource)).json();
4
+ async function getData(ctx, resource, queryParams) {
5
+ const response = await (await ctx.get(Endpoint.API_CORE, resource, queryParams)).json();
4
6
  return response.data ?? [];
5
7
  }
8
+ async function getWeb(ctx, resource) {
9
+ return (await ctx.get(Endpoint.API_WEB_V1, resource)).json();
10
+ }
6
11
  /**
7
12
  * Gets the full NHL glossary of statistical terms and abbreviations.
8
13
  *
@@ -44,10 +49,150 @@ export async function seasonSpecificRulesAndInfo(ctx) {
44
49
  export async function draftYearAndRounds(ctx) {
45
50
  return getData(ctx, 'stats/rest/en/draft');
46
51
  }
52
+ /**
53
+ * Gets the season and game type the stats API currently serves by default.
54
+ *
55
+ * @example https://api.nhle.com/stats/rest/en/componentSeason
56
+ */
57
+ export async function componentSeasons(ctx) {
58
+ return getData(ctx, 'stats/rest/en/componentSeason');
59
+ }
60
+ function gamesClauses({ season, gameType, teamId, startDate, endDate, cayenneExp, }) {
61
+ const clauses = [];
62
+ if (season !== undefined && season !== null) {
63
+ clauses.push(`season=${season}`);
64
+ }
65
+ if (gameType !== undefined) {
66
+ clauses.push(`gameType=${gameType}`);
67
+ }
68
+ if (teamId !== undefined && teamId !== null) {
69
+ clauses.push(`homeTeamId=${teamId} or visitingTeamId=${teamId}`);
70
+ }
71
+ if (startDate !== undefined) {
72
+ clauses.push(`gameDate>=${cayenneString(normalizeDate(startDate))}`);
73
+ }
74
+ if (endDate !== undefined) {
75
+ clauses.push(`gameDate<=${cayenneString(normalizeDate(endDate))}`);
76
+ }
77
+ if (cayenneExp?.trim()) {
78
+ clauses.push(cayenneExp);
79
+ }
80
+ return clauses;
81
+ }
82
+ /**
83
+ * Gets games from the stats API. At least one filter is required:
84
+ * unfiltered, the API sends every game ever played (about 19 MB).
85
+ *
86
+ * @param params.season Season in YYYYYYYY format, e.g. 20232024
87
+ * @param params.gameType 1=Preseason, 2=Regular season, 3=Playoffs
88
+ * @param params.teamId NHL team id, home or away, e.g. 10
89
+ * @param params.startDate First game date, YYYY-MM-DD
90
+ * @param params.endDate Last game date, YYYY-MM-DD
91
+ * @param params.cayenneExp Extra filter expression, e.g. "homeScore>=7"
92
+ * @throws RangeError When no filter is given, or a date is not YYYY-MM-DD
93
+ * @example await client.misc.games({ season: 20232024, teamId: 10, gameType: 3 })
94
+ */
95
+ export async function games(ctx, params) {
96
+ const clauses = gamesClauses(params);
97
+ if (clauses.length === 0) {
98
+ throw new RangeError('Missing filter. Pass season, gameType, teamId, a date or cayenneExp.');
99
+ }
100
+ return getData(ctx, 'stats/rest/en/game', {
101
+ cayenneExp: andClauses(clauses),
102
+ });
103
+ }
104
+ /**
105
+ * Gets the national TV schedule for the week around a date, grouped by date.
106
+ *
107
+ * @param params.date Date in YYYY-MM-DD format. Defaults to "now".
108
+ * @example https://api-web.nhle.com/v1/network/tv-schedule/2023-10-15
109
+ */
110
+ export async function tvSchedule(ctx, { date } = {}) {
111
+ return getWeb(ctx, `network/tv-schedule/${date ?? 'now'}`);
112
+ }
113
+ /**
114
+ * Gets betting odds for today's games from the NHL's odds partner in a
115
+ * country.
116
+ *
117
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
118
+ * @param params.countryCode Two-letter country code, e.g. US, CA
119
+ * @example https://api-web.nhle.com/v1/partner-game/US/now
120
+ */
121
+ export async function partnerGameOdds(ctx, { countryCode }) {
122
+ return getWeb(ctx, `partner-game/${countryCode}/now`);
123
+ }
124
+ /**
125
+ * Gets every NHL season id, oldest first.
126
+ *
127
+ * @example https://api-web.nhle.com/v1/season
128
+ */
129
+ export async function seasonIds(ctx) {
130
+ return getWeb(ctx, 'season');
131
+ }
132
+ /**
133
+ * Gets display metadata (names, headshots, logos) for players and teams.
134
+ * Lists you leave out or pass empty come back empty.
135
+ *
136
+ * @param params.players Player ids, e.g. [8478402]
137
+ * @param params.teams Team abbreviations, e.g. ['TOR', 'BUF']
138
+ * @example https://api-web.nhle.com/v1/meta?players=8478402&teams=TOR,BUF
139
+ */
140
+ export async function meta(ctx, { players = [], teams = [] } = {}) {
141
+ const query = {};
142
+ if (players.length > 0) {
143
+ query.players = players.join(',');
144
+ }
145
+ if (teams.length > 0) {
146
+ query.teams = teams.join(',');
147
+ }
148
+ return (await ctx.get(Endpoint.API_WEB_V1, 'meta', query)).json();
149
+ }
150
+ /**
151
+ * Gets the caller's country, looked up from their IP address. The answer
152
+ * depends on where the request comes from.
153
+ *
154
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
155
+ * @example https://api-web.nhle.com/v1/location
156
+ */
157
+ export async function location(ctx) {
158
+ return getWeb(ctx, 'location');
159
+ }
160
+ /**
161
+ * Gets the teams whose local broadcast market covers a postal code. Empty
162
+ * for codes outside every market.
163
+ *
164
+ * @experimental Feeds an nhl.com widget; the shape may change without notice.
165
+ * @param params.postalCode Postal or ZIP code, e.g. 90210 or "M5V 3L9"
166
+ * @example https://api-web.nhle.com/v1/postal-lookup/90210
167
+ */
168
+ export async function postalLookup(ctx, { postalCode }) {
169
+ return getWeb(ctx, `postal-lookup/${encodeURIComponent(postalCode)}`);
170
+ }
171
+ /**
172
+ * Checks that the stats API is up. Resolves `true` on success; it never
173
+ * resolves `false`, since any failure throws an `NHLApiException` subclass
174
+ * (or a network error).
175
+ *
176
+ * @throws ServerErrorException When the stats API answers 5xx
177
+ * @example https://api.nhle.com/stats/rest/ping
178
+ */
179
+ export async function ping(ctx) {
180
+ await ctx.get(Endpoint.API_CORE, 'stats/rest/ping');
181
+ return true;
182
+ }
47
183
  export const miscApi = {
48
184
  glossary,
49
185
  config,
50
186
  countries,
51
187
  seasonSpecificRulesAndInfo,
52
188
  draftYearAndRounds,
189
+ componentSeasons,
190
+ games,
191
+ tvSchedule,
192
+ partnerGameOdds,
193
+ seasonIds,
194
+ meta,
195
+ location,
196
+ postalLookup,
197
+ ping,
53
198
  };