nhl-api-ts 0.2.0 → 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 (51) hide show
  1. package/README.md +81 -9
  2. package/dist/api/draft.d.mts +61 -0
  3. package/dist/api/draft.mjs +68 -0
  4. package/dist/api/edge.d.mts +221 -24
  5. package/dist/api/edge.mjs +276 -27
  6. package/dist/api/game-center.d.mts +63 -15
  7. package/dist/api/game-center.mjs +67 -8
  8. package/dist/api/helpers.d.mts +6 -6
  9. package/dist/api/helpers.mjs +6 -6
  10. package/dist/api/misc.d.mts +120 -6
  11. package/dist/api/misc.mjs +162 -7
  12. package/dist/api/players.d.mts +59 -7
  13. package/dist/api/players.mjs +85 -4
  14. package/dist/api/query/cayenne.d.mts +4 -0
  15. package/dist/api/query/cayenne.mjs +13 -0
  16. package/dist/api/query/sorting/sorting-options.d.mts +8 -0
  17. package/dist/api/query/sorting/sorting-options.mjs +30 -0
  18. package/dist/api/schedule.d.mts +36 -23
  19. package/dist/api/schedule.mjs +40 -16
  20. package/dist/api/standings.d.mts +3 -3
  21. package/dist/api/standings.mjs +4 -4
  22. package/dist/api/stats.d.mts +105 -16
  23. package/dist/api/stats.mjs +145 -41
  24. package/dist/api/teams.d.mts +48 -8
  25. package/dist/api/teams.mjs +59 -7
  26. package/dist/cli/colors.d.mts +2 -2
  27. package/dist/cli/colors.mjs +6 -2
  28. package/dist/cli/commands.mjs +521 -46
  29. package/dist/cli/run.mjs +7 -5
  30. package/dist/http-client.d.mts +2 -1
  31. package/dist/http-client.mjs +10 -3
  32. package/dist/index.d.mts +8 -2
  33. package/dist/index.mjs +3 -0
  34. package/dist/nhl-client.d.mts +70 -15
  35. package/dist/nhl-client.mjs +40 -17
  36. package/dist/types/common.d.mts +0 -1
  37. package/dist/types/draft.d.mts +97 -0
  38. package/dist/types/draft.mjs +1 -0
  39. package/dist/types/edge.d.mts +301 -5
  40. package/dist/types/game-center.d.mts +277 -119
  41. package/dist/types/index.d.mts +1 -0
  42. package/dist/types/misc.d.mts +101 -0
  43. package/dist/types/misc.mjs +0 -1
  44. package/dist/types/players.d.mts +23 -2
  45. package/dist/types/schedule.d.mts +50 -62
  46. package/dist/types/standings.d.mts +1 -2
  47. package/dist/types/stats.d.mts +313 -111
  48. package/dist/types/teams.d.mts +29 -1
  49. package/dist/utils.d.mts +1 -1
  50. package/dist/utils.mjs +3 -1
  51. package/package.json +7 -28
@@ -5,7 +5,9 @@ import { SKATER_REPORT_TYPES } from '#src/api/query/sorting/sorting-options.mjs'
5
5
  export class UsageError extends Error {
6
6
  }
7
7
  // ---- Reusable argument specs ------------------------------------------------
8
- const req = (spec) => ({ ...spec, required: true });
8
+ function req(spec) {
9
+ return { ...spec, required: true };
10
+ }
9
11
  const teamAbbr = req({
10
12
  name: 'teamAbbr',
11
13
  type: 'string',
@@ -26,11 +28,13 @@ const playerId = req({
26
28
  type: 'string',
27
29
  description: 'NHL player id, e.g. 8478402',
28
30
  });
29
- const date = (description = 'Date in YYYY-MM-DD format') => ({
30
- name: 'date',
31
- type: 'string',
32
- description,
33
- });
31
+ function date(description = 'Date in YYYY-MM-DD format') {
32
+ return {
33
+ name: 'date',
34
+ type: 'string',
35
+ description,
36
+ };
37
+ }
34
38
  const gameTypeId = {
35
39
  name: 'gameTypeId',
36
40
  type: 'int',
@@ -48,40 +52,74 @@ const start = {
48
52
  description: 'Pagination offset',
49
53
  default: '0',
50
54
  };
51
- const limit = (def) => ({
52
- name: 'limit',
53
- type: 'int',
54
- description: 'Max results',
55
- default: def,
56
- });
57
- const factCayenneExp = (def) => ({
58
- name: 'factCayenneExp',
59
- type: 'string',
60
- description: 'Base fact filter expression',
61
- default: def,
62
- });
55
+ function limit(def) {
56
+ return {
57
+ name: 'limit',
58
+ type: 'int',
59
+ description: 'Max results',
60
+ default: def,
61
+ };
62
+ }
63
+ function factCayenneExp(def) {
64
+ return {
65
+ name: 'factCayenneExp',
66
+ type: 'string',
67
+ description: 'Base fact filter expression',
68
+ default: def,
69
+ };
70
+ }
63
71
  const defaultCayenneExp = {
64
72
  name: 'defaultCayenneExp',
65
73
  type: 'string',
66
74
  description: 'Overrides the generated cayenneExp filter entirely',
67
75
  };
68
- const apiSleepRate = (def) => ({
69
- name: 'apiSleepRate',
70
- type: 'number',
71
- description: 'Seconds to sleep between per-team requests',
72
- default: def,
73
- });
76
+ const currentSeason = {
77
+ ...season,
78
+ description: `${season.description}. Defaults to current`,
79
+ };
80
+ const nowSeason = {
81
+ ...season,
82
+ description: `${season.description}. Defaults to now`,
83
+ };
84
+ const draftSeason = {
85
+ name: 'season',
86
+ type: 'string',
87
+ description: 'Draft year in YYYY format, e.g. 2023. Defaults to now',
88
+ };
89
+ const seasonGameType = {
90
+ name: 'gameType',
91
+ type: 'int',
92
+ description: '2=Regular season, 3=Playoffs (only used with --season)',
93
+ default: '2',
94
+ };
95
+ const allTimeSeason = {
96
+ ...season,
97
+ description: `${season.description}. Defaults to every season`,
98
+ };
99
+ function leaderCategories(choices) {
100
+ return {
101
+ name: 'categories',
102
+ type: 'list',
103
+ description: `Comma-separated categories (${choices.join(', ')}). Defaults to all`,
104
+ };
105
+ }
106
+ const leaderLimit = {
107
+ name: 'limit',
108
+ type: 'int',
109
+ description: 'Rows per category (-1 for all)',
110
+ default: '5',
111
+ };
112
+ function apiSleepRate(def) {
113
+ return {
114
+ name: 'apiSleepRate',
115
+ type: 'number',
116
+ description: 'Seconds to sleep between per-team requests',
117
+ default: def,
118
+ };
119
+ }
74
120
  // ---- Edge -------------------------------------------------------------------
75
- const edgeSeasonArgs = [
76
- { ...season, description: `${season.description}. Defaults to current` },
77
- {
78
- name: 'gameType',
79
- type: 'int',
80
- description: '2=Regular season, 3=Playoffs (only used with --season)',
81
- default: '2',
82
- },
83
- ];
84
- const edgeCommand = (name, method, idKind, description) => {
121
+ const edgeSeasonArgs = [currentSeason, seasonGameType];
122
+ function edgeCommand(name, method, idKind, description, extraArgs = []) {
85
123
  const idArg = idKind === 'player'
86
124
  ? [playerId]
87
125
  : idKind === 'team'
@@ -96,12 +134,62 @@ const edgeCommand = (name, method, idKind, description) => {
96
134
  return {
97
135
  name,
98
136
  description,
99
- args: [...idArg, ...edgeSeasonArgs],
137
+ args: [...idArg, ...extraArgs, ...edgeSeasonArgs],
100
138
  run: (client, values) =>
101
139
  // biome-ignore lint/suspicious/noExplicitAny: dispatch by method name
102
140
  client.edge[method].call(client.edge, values),
103
141
  };
142
+ }
143
+ const edgePositions = {
144
+ name: 'positions',
145
+ type: 'string',
146
+ description: 'Player positions',
147
+ default: 'all',
148
+ choices: ['all', 'forwards', 'defense'],
104
149
  };
150
+ const edgeStrength = {
151
+ name: 'strength',
152
+ type: 'string',
153
+ description: 'all, es (even strength), pp (power play) or pk (penalty kill)',
154
+ default: 'all',
155
+ choices: ['all', 'es', 'pp', 'pk'],
156
+ };
157
+ const edgeShotLocationCategory = {
158
+ name: 'category',
159
+ type: 'string',
160
+ description: 'Shot area: all, high (danger), mid (range) or long (range)',
161
+ default: 'all',
162
+ choices: ['all', 'high', 'mid', 'long'],
163
+ };
164
+ function edgeSortBy(choices) {
165
+ return req({
166
+ name: 'sortBy',
167
+ type: 'string',
168
+ description: 'Metric to rank by',
169
+ choices,
170
+ });
171
+ }
172
+ const edgeZoneSortBy = req({
173
+ name: 'sortBy',
174
+ type: 'string',
175
+ description: 'Zone to rank by',
176
+ choices: ['offensive', 'neutral', 'defensive'],
177
+ });
178
+ const distanceSortBy = edgeSortBy([
179
+ 'total',
180
+ 'per-60',
181
+ 'max-game',
182
+ 'max-period',
183
+ ]);
184
+ const skatingSpeedSortBy = edgeSortBy(['max', 'over-22', '20-22', '18-20']);
185
+ const shotSpeedSortBy = edgeSortBy([
186
+ 'max',
187
+ 'over-100',
188
+ '90-99',
189
+ '80-89',
190
+ '70-79',
191
+ ]);
192
+ const shotLocationSortBy = edgeSortBy(['sog', 'goals', 'shooting-pctg']);
105
193
  // ---- Stats query-context filters --------------------------------------------
106
194
  const queryFilterArgs = [
107
195
  {
@@ -247,15 +335,45 @@ export const MODULES = [
247
335
  {
248
336
  name: 'team-roster',
249
337
  description: 'Roster for a team and season',
250
- args: [teamAbbr, req(season)],
338
+ args: [teamAbbr, currentSeason],
251
339
  run: (client, values) => client.teams.teamRoster(values),
252
340
  },
341
+ {
342
+ name: 'roster-seasons',
343
+ description: 'Every season a team has a roster for',
344
+ args: [teamAbbr],
345
+ run: (client, values) => client.teams.rosterSeasons(values),
346
+ },
347
+ {
348
+ name: 'team-scoreboard',
349
+ description: "A team's recent and upcoming games",
350
+ args: [teamAbbr],
351
+ run: (client, values) => client.teams.teamScoreboard(values),
352
+ },
253
353
  {
254
354
  name: 'franchises',
255
355
  description: 'All past and current NHL franchises',
256
356
  args: [],
257
357
  run: (client) => client.teams.franchises(),
258
358
  },
359
+ {
360
+ name: 'stats-teams',
361
+ description: 'Every team in the stats API, past and present',
362
+ args: [],
363
+ run: (client) => client.teams.statsTeams(),
364
+ },
365
+ {
366
+ name: 'team-by-id',
367
+ description: 'One stats API team by its team id',
368
+ args: [
369
+ req({
370
+ name: 'teamId',
371
+ type: 'string',
372
+ description: 'NHL team id, e.g. 10',
373
+ }),
374
+ ],
375
+ run: (client, values) => client.teams.teamById(values),
376
+ },
259
377
  ],
260
378
  },
261
379
  {
@@ -314,13 +432,13 @@ export const MODULES = [
314
432
  {
315
433
  name: 'team-season-schedule',
316
434
  description: "A team's full season schedule",
317
- args: [teamAbbr, req(season)],
435
+ args: [teamAbbr, nowSeason],
318
436
  run: (client, values) => client.schedule.teamSeasonSchedule(values),
319
437
  },
320
438
  {
321
439
  name: 'calendar-schedule',
322
440
  description: 'Schedule in calendar format for a date',
323
- args: [req(date())],
441
+ args: [date('Date in YYYY-MM-DD format. Defaults to now')],
324
442
  run: (client, values) => client.schedule.calendarSchedule(values),
325
443
  },
326
444
  {
@@ -342,6 +460,19 @@ export const MODULES = [
342
460
  ],
343
461
  run: (client, values) => client.schedule.playoffSeriesSchedule(values),
344
462
  },
463
+ {
464
+ name: 'playoff-series-meta',
465
+ description: 'Round title and seeded teams of one playoff series',
466
+ args: [
467
+ req({ name: 'year', type: 'string', description: 'Year, e.g. 2024' }),
468
+ req({
469
+ name: 'series',
470
+ type: 'string',
471
+ description: 'Series letter: a-h first round ... o final',
472
+ }),
473
+ ],
474
+ run: (client, values) => client.schedule.playoffSeriesMeta(values),
475
+ },
345
476
  {
346
477
  name: 'playoff-bracket',
347
478
  description: 'Full playoff bracket for a year',
@@ -406,6 +537,37 @@ export const MODULES = [
406
537
  args: [gameId],
407
538
  run: (client, values) => client.gameCenter.gameStory(values),
408
539
  },
540
+ {
541
+ name: 'scoreboard',
542
+ description: 'Every game in the week around a date, grouped by date',
543
+ args: [date('Date in YYYY-MM-DD format. Defaults to now')],
544
+ run: (client, values) => client.gameCenter.scoreboard(values),
545
+ },
546
+ {
547
+ name: 'wsc-play-by-play',
548
+ description: 'Flat play-by-play feed used by the nhl.com game story',
549
+ args: [gameId],
550
+ run: (client, values) => client.gameCenter.wscPlayByPlay(values),
551
+ },
552
+ {
553
+ name: 'play-replay',
554
+ description: 'Replay card for one play-by-play event',
555
+ args: [
556
+ gameId,
557
+ req({
558
+ name: 'eventNumber',
559
+ type: 'string',
560
+ description: "The play's eventId from play-by-play, e.g. 193",
561
+ }),
562
+ ],
563
+ run: (client, values) => client.gameCenter.playReplay(values),
564
+ },
565
+ {
566
+ name: 'game-meta',
567
+ description: 'Teams, season state and game state for a game',
568
+ args: [gameId],
569
+ run: (client, values) => client.gameCenter.gameMeta(values),
570
+ },
409
571
  ],
410
572
  },
411
573
  {
@@ -429,19 +591,63 @@ export const MODULES = [
429
591
  description: "A player's game log for a season",
430
592
  args: [
431
593
  playerId,
432
- req({
594
+ {
433
595
  name: 'seasonId',
434
596
  type: 'string',
435
- description: 'Season in YYYYYYYY format',
436
- }),
437
- req({
597
+ description: 'Season in YYYYYYYY format. Defaults to now',
598
+ },
599
+ {
438
600
  name: 'gameType',
439
601
  type: 'int',
440
- description: '1=Preseason, 2=Regular, 3=Playoffs',
441
- }),
602
+ description: '1=Preseason, 2=Regular, 3=Playoffs (only used with --season-id)',
603
+ default: '2',
604
+ },
442
605
  ],
443
606
  run: (client, values) => client.stats.playerGameLog(values),
444
607
  },
608
+ {
609
+ name: 'skater-stats-leaders',
610
+ description: 'Skater stats leaders by category for a season',
611
+ args: [
612
+ currentSeason,
613
+ seasonGameType,
614
+ leaderCategories([
615
+ 'goals',
616
+ 'assists',
617
+ 'points',
618
+ 'plusMinus',
619
+ 'penaltyMins',
620
+ 'goalsPp',
621
+ 'goalsSh',
622
+ 'faceoffLeaders',
623
+ 'toi',
624
+ ]),
625
+ leaderLimit,
626
+ ],
627
+ run: (client, values) => client.stats.skaterStatsLeaders(values),
628
+ },
629
+ {
630
+ name: 'goalie-stats-leaders',
631
+ description: 'Goalie stats leaders by category for a season',
632
+ args: [
633
+ currentSeason,
634
+ seasonGameType,
635
+ leaderCategories([
636
+ 'wins',
637
+ 'shutouts',
638
+ 'savePctg',
639
+ 'goalsAgainstAverage',
640
+ ]),
641
+ leaderLimit,
642
+ ],
643
+ run: (client, values) => client.stats.goalieStatsLeaders(values),
644
+ },
645
+ {
646
+ name: 'club-stats',
647
+ description: "A team's skater and goalie stats for a season",
648
+ args: [teamAbbr, nowSeason, seasonGameType],
649
+ run: (client, values) => client.stats.clubStats(values),
650
+ },
445
651
  {
446
652
  name: 'team-summary',
447
653
  description: 'Team summary stats across seasons',
@@ -575,6 +781,52 @@ export const MODULES = [
575
781
  ],
576
782
  run: (client, values) => client.stats.goalieStatsSummary(values),
577
783
  },
784
+ {
785
+ name: 'skater-leaders',
786
+ description: 'Top 10 single-season skater records for a stat (stats API)',
787
+ args: [
788
+ req({
789
+ name: 'attribute',
790
+ type: 'string',
791
+ description: 'Stat to rank by',
792
+ choices: ['points', 'goals', 'assists', 'gamesPlayed'],
793
+ }),
794
+ allTimeSeason,
795
+ ],
796
+ run: (client, values) => client.stats.skaterLeaders(values),
797
+ },
798
+ {
799
+ name: 'goalie-leaders',
800
+ description: 'Top 10 single-season goalie records for a stat (stats API)',
801
+ args: [
802
+ req({
803
+ name: 'attribute',
804
+ type: 'string',
805
+ description: 'Stat to rank by',
806
+ choices: [
807
+ 'gaa',
808
+ 'savePctg',
809
+ 'shutouts',
810
+ 'timeOnIce',
811
+ 'gamesPlayed',
812
+ ],
813
+ }),
814
+ allTimeSeason,
815
+ ],
816
+ run: (client, values) => client.stats.goalieLeaders(values),
817
+ },
818
+ {
819
+ name: 'skater-milestones',
820
+ description: 'Career milestones active skaters are approaching',
821
+ args: [],
822
+ run: (client) => client.stats.skaterMilestones(),
823
+ },
824
+ {
825
+ name: 'goalie-milestones',
826
+ description: 'Career milestones active goalies are approaching',
827
+ args: [],
828
+ run: (client) => client.stats.goalieMilestones(),
829
+ },
578
830
  ],
579
831
  },
580
832
  {
@@ -604,11 +856,29 @@ export const MODULES = [
604
856
  edgeCommand('team-landing', 'teamLanding', 'none', 'EDGE team landing page (league leaders)'),
605
857
  edgeCommand('team-shot-speed-detail', 'teamShotSpeedDetail', 'team', 'EDGE team shot speed'),
606
858
  edgeCommand('team-skating-speed-detail', 'teamSkatingSpeedDetail', 'team', 'EDGE team skating speed'),
859
+ edgeCommand('team-comparison', 'teamComparison', 'team', 'EDGE team comparison stats'),
860
+ edgeCommand('skater-distance-top-10', 'skaterDistanceTop10', 'none', 'EDGE top 10 skaters by skating distance', [edgePositions, edgeStrength, distanceSortBy]),
861
+ edgeCommand('skater-speed-top-10', 'skaterSpeedTop10', 'none', 'EDGE top 10 skaters by skating speed', [edgePositions, skatingSpeedSortBy]),
862
+ edgeCommand('skater-zone-time-top-10', 'skaterZoneTimeTop10', 'none', 'EDGE top 10 skaters by zone time', [edgePositions, edgeStrength, edgeZoneSortBy]),
863
+ edgeCommand('skater-shot-speed-top-10', 'skaterShotSpeedTop10', 'none', 'EDGE top 10 skaters by shot speed', [edgePositions, shotSpeedSortBy]),
864
+ edgeCommand('skater-shot-location-top-10', 'skaterShotLocationTop10', 'none', 'EDGE top 10 skaters by shot location', [edgePositions, shotLocationSortBy, edgeShotLocationCategory]),
865
+ edgeCommand('goalie-5v5-top-10', 'goalie5v5Top10', 'none', 'EDGE top 10 goalies at 5v5', [edgeSortBy(['save-pctg', 'save-pctg-close', 'shots', 'shots-per-60'])]),
866
+ edgeCommand('goalie-shot-location-top-10', 'goalieShotLocationTop10', 'none', 'EDGE top 10 goalies by shot location', [
867
+ edgeSortBy(['save-pctg', 'saves', 'goals-against', 'shots-against']),
868
+ edgeShotLocationCategory,
869
+ ]),
870
+ edgeCommand('goalie-save-percentage-top-10', 'goalieSavePercentageTop10', 'none', 'EDGE top 10 goalies by games above .900', [edgeSortBy(['games', 'pctg'])]),
871
+ edgeCommand('team-skating-distance-top-10', 'teamSkatingDistanceTop10', 'none', 'EDGE top 10 teams by skating distance', [edgePositions, edgeStrength, distanceSortBy]),
872
+ edgeCommand('team-skating-speed-top-10', 'teamSkatingSpeedTop10', 'none', 'EDGE top 10 teams by skating speed', [edgePositions, skatingSpeedSortBy]),
873
+ edgeCommand('team-zone-time-top-10', 'teamZoneTimeTop10', 'none', 'EDGE top 10 teams by zone time', [edgeStrength, edgeZoneSortBy]),
874
+ edgeCommand('team-shot-speed-top-10', 'teamShotSpeedTop10', 'none', 'EDGE top 10 teams by shot speed', [edgePositions, shotSpeedSortBy]),
875
+ edgeCommand('team-shot-location-top-10', 'teamShotLocationTop10', 'none', 'EDGE top 10 teams by shot location', [edgePositions, shotLocationSortBy, edgeShotLocationCategory]),
876
+ edgeCommand('by-the-numbers', 'byTheNumbers', 'none', 'EDGE league highlights (latest night, or season bests with --season)'),
607
877
  ],
608
878
  },
609
879
  {
610
880
  name: 'players',
611
- description: 'Prospects and team rosters',
881
+ description: 'Prospects, team rosters and player search',
612
882
  commands: [
613
883
  {
614
884
  name: 'prospects-by-team',
@@ -619,9 +889,110 @@ export const MODULES = [
619
889
  {
620
890
  name: 'players-by-team',
621
891
  description: "A team's roster for a season",
622
- args: [teamAbbr, req(season)],
892
+ args: [teamAbbr, currentSeason],
623
893
  run: (client, values) => client.players.playersByTeam(values),
624
894
  },
895
+ {
896
+ name: 'player-spotlight',
897
+ description: 'Players featured in the nhl.com spotlight',
898
+ args: [],
899
+ run: (client) => client.players.playerSpotlight(),
900
+ },
901
+ {
902
+ name: 'player-search',
903
+ description: 'Search every player (needs a filter). At most 5 rows per page; page with --start',
904
+ args: [
905
+ {
906
+ name: 'name',
907
+ type: 'string',
908
+ description: 'Case-insensitive part of the full name, e.g. matth',
909
+ },
910
+ {
911
+ name: 'teamId',
912
+ type: 'string',
913
+ description: 'NHL team id of the current team, e.g. 10',
914
+ },
915
+ {
916
+ name: 'position',
917
+ type: 'string',
918
+ description: 'Position; F matches every forward',
919
+ choices: ['C', 'L', 'R', 'D', 'G', 'F'],
920
+ },
921
+ {
922
+ name: 'cayenneExp',
923
+ type: 'string',
924
+ description: 'Extra filter, e.g. sweaterNumber=34',
925
+ },
926
+ {
927
+ name: 'sort',
928
+ type: 'string',
929
+ description: 'Field to sort by, e.g. lastName',
930
+ },
931
+ {
932
+ name: 'dir',
933
+ type: 'string',
934
+ description: 'Sort direction',
935
+ choices: ['ASC', 'DESC'],
936
+ },
937
+ start,
938
+ {
939
+ name: 'include',
940
+ type: 'list',
941
+ description: 'Comma-separated fields to return, e.g. id,fullName',
942
+ },
943
+ {
944
+ name: 'exclude',
945
+ type: 'list',
946
+ description: 'Comma-separated fields to leave out',
947
+ },
948
+ ],
949
+ run: (client, values) => client.players.playerSearch(values),
950
+ },
951
+ ],
952
+ },
953
+ {
954
+ name: 'draft',
955
+ description: 'Draft rankings, picks and the live draft tracker',
956
+ commands: [
957
+ {
958
+ name: 'rankings',
959
+ description: 'Central Scouting rankings for one prospect category',
960
+ args: [
961
+ draftSeason,
962
+ {
963
+ name: 'category',
964
+ type: 'int',
965
+ description: '1=NA skater, 2=Intl skater, 3=NA goalie, 4=Intl goalie (only used with --season)',
966
+ default: '1',
967
+ choices: ['1', '2', '3', '4'],
968
+ },
969
+ ],
970
+ run: (client, values) => client.draft.rankings(values),
971
+ },
972
+ {
973
+ name: 'tracker',
974
+ description: 'Live draft tracker for the current draft',
975
+ args: [],
976
+ run: (client) => client.draft.tracker(),
977
+ },
978
+ {
979
+ name: 'picks',
980
+ description: 'Picks of a draft. Without --season, round 1 of the current draft',
981
+ args: [
982
+ draftSeason,
983
+ {
984
+ name: 'round',
985
+ type: 'string',
986
+ description: 'Round 1-7 or all (only used with --season)',
987
+ default: 'all',
988
+ choices: ['1', '2', '3', '4', '5', '6', '7', 'all'],
989
+ },
990
+ ],
991
+ run: (client, { round, ...values }) => client.draft.picks({
992
+ ...values,
993
+ round: round === undefined || round === 'all' ? round : Number(round),
994
+ }),
995
+ },
625
996
  ],
626
997
  },
627
998
  {
@@ -658,6 +1029,110 @@ export const MODULES = [
658
1029
  args: [],
659
1030
  run: (client) => client.misc.draftYearAndRounds(),
660
1031
  },
1032
+ {
1033
+ name: 'component-seasons',
1034
+ description: 'Season and game type the stats API serves by default',
1035
+ args: [],
1036
+ run: (client) => client.misc.componentSeasons(),
1037
+ },
1038
+ {
1039
+ name: 'ping',
1040
+ description: 'Check that the stats API is up (prints true)',
1041
+ args: [],
1042
+ run: (client) => client.misc.ping(),
1043
+ },
1044
+ {
1045
+ name: 'games',
1046
+ description: 'Games from the stats API (needs at least one filter)',
1047
+ args: [
1048
+ season,
1049
+ {
1050
+ name: 'gameType',
1051
+ type: 'int',
1052
+ description: '1=Preseason, 2=Regular season, 3=Playoffs',
1053
+ },
1054
+ {
1055
+ name: 'teamId',
1056
+ type: 'string',
1057
+ description: 'NHL team id, home or away, e.g. 10',
1058
+ },
1059
+ {
1060
+ name: 'startDate',
1061
+ type: 'string',
1062
+ description: 'First game date, YYYY-MM-DD',
1063
+ },
1064
+ {
1065
+ name: 'endDate',
1066
+ type: 'string',
1067
+ description: 'Last game date, YYYY-MM-DD',
1068
+ },
1069
+ {
1070
+ name: 'cayenneExp',
1071
+ type: 'string',
1072
+ description: 'Extra filter, e.g. homeScore>=7',
1073
+ },
1074
+ ],
1075
+ run: (client, values) => client.misc.games(values),
1076
+ },
1077
+ {
1078
+ name: 'tv-schedule',
1079
+ description: 'National TV broadcasts for the week around a date',
1080
+ args: [date('Date in YYYY-MM-DD format. Defaults to now')],
1081
+ run: (client, values) => client.misc.tvSchedule(values),
1082
+ },
1083
+ {
1084
+ name: 'partner-game-odds',
1085
+ description: "Betting odds for today's games from a country's partner",
1086
+ args: [
1087
+ req({
1088
+ name: 'countryCode',
1089
+ type: 'string',
1090
+ description: 'Two-letter country code, e.g. US, CA',
1091
+ }),
1092
+ ],
1093
+ run: (client, values) => client.misc.partnerGameOdds(values),
1094
+ },
1095
+ {
1096
+ name: 'season-ids',
1097
+ description: 'Every NHL season id, oldest first',
1098
+ args: [],
1099
+ run: (client) => client.misc.seasonIds(),
1100
+ },
1101
+ {
1102
+ name: 'meta',
1103
+ description: 'Display metadata for players and teams',
1104
+ args: [
1105
+ {
1106
+ name: 'players',
1107
+ type: 'int-list',
1108
+ description: 'Comma-separated player ids, e.g. 8478402,8476945',
1109
+ },
1110
+ {
1111
+ name: 'teams',
1112
+ type: 'list',
1113
+ description: 'Comma-separated team abbreviations, e.g. TOR,BUF',
1114
+ },
1115
+ ],
1116
+ run: (client, values) => client.misc.meta(values),
1117
+ },
1118
+ {
1119
+ name: 'location',
1120
+ description: "The caller's country, from their IP address",
1121
+ args: [],
1122
+ run: (client) => client.misc.location(),
1123
+ },
1124
+ {
1125
+ name: 'postal-lookup',
1126
+ description: 'Teams whose broadcast market covers a postal code',
1127
+ args: [
1128
+ req({
1129
+ name: 'postalCode',
1130
+ type: 'string',
1131
+ description: 'Postal or ZIP code, e.g. 90210',
1132
+ }),
1133
+ ],
1134
+ run: (client, values) => client.misc.postalLookup(values),
1135
+ },
661
1136
  ],
662
1137
  },
663
1138
  {