nhl-api-ts 0.0.0-stage → 0.1.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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -2
  3. package/dist/api/edge.d.mts +179 -0
  4. package/dist/api/edge.mjs +184 -0
  5. package/dist/api/game-center.d.mts +83 -0
  6. package/dist/api/game-center.mjs +74 -0
  7. package/dist/api/helpers.d.mts +46 -0
  8. package/dist/api/helpers.mjs +106 -0
  9. package/dist/api/misc.d.mts +40 -0
  10. package/dist/api/misc.mjs +43 -0
  11. package/dist/api/players.d.mts +27 -0
  12. package/dist/api/players.mjs +18 -0
  13. package/dist/api/query/builder.d.mts +20 -0
  14. package/dist/api/query/builder.mjs +28 -0
  15. package/dist/api/query/errors.d.mts +3 -0
  16. package/dist/api/query/errors.mjs +6 -0
  17. package/dist/api/query/filters/base.d.mts +4 -0
  18. package/dist/api/query/filters/base.mjs +2 -0
  19. package/dist/api/query/filters/decision.d.mts +13 -0
  20. package/dist/api/query/filters/decision.mjs +26 -0
  21. package/dist/api/query/filters/draft.d.mts +15 -0
  22. package/dist/api/query/filters/draft.mjs +27 -0
  23. package/dist/api/query/filters/experience.d.mts +9 -0
  24. package/dist/api/query/filters/experience.mjs +17 -0
  25. package/dist/api/query/filters/franchise.d.mts +9 -0
  26. package/dist/api/query/filters/franchise.mjs +15 -0
  27. package/dist/api/query/filters/game-type.d.mts +10 -0
  28. package/dist/api/query/filters/game-type.mjs +16 -0
  29. package/dist/api/query/filters/goalie-sorts.d.mts +3 -0
  30. package/dist/api/query/filters/goalie-sorts.mjs +55 -0
  31. package/dist/api/query/filters/home-road.d.mts +9 -0
  32. package/dist/api/query/filters/home-road.mjs +16 -0
  33. package/dist/api/query/filters/index.d.mts +14 -0
  34. package/dist/api/query/filters/index.mjs +14 -0
  35. package/dist/api/query/filters/nationality.d.mts +12 -0
  36. package/dist/api/query/filters/nationality.mjs +19 -0
  37. package/dist/api/query/filters/opponent.d.mts +10 -0
  38. package/dist/api/query/filters/opponent.mjs +16 -0
  39. package/dist/api/query/filters/position.d.mts +16 -0
  40. package/dist/api/query/filters/position.mjs +28 -0
  41. package/dist/api/query/filters/season.d.mts +14 -0
  42. package/dist/api/query/filters/season.mjs +24 -0
  43. package/dist/api/query/filters/shoot-catch.d.mts +9 -0
  44. package/dist/api/query/filters/shoot-catch.mjs +16 -0
  45. package/dist/api/query/filters/status.d.mts +20 -0
  46. package/dist/api/query/filters/status.mjs +28 -0
  47. package/dist/api/query/filters.d.mts +93 -0
  48. package/dist/api/query/filters.mjs +118 -0
  49. package/dist/api/query/index.d.mts +4 -0
  50. package/dist/api/query/index.mjs +4 -0
  51. package/dist/api/query/sorting/goalie-sorts.d.mts +6 -0
  52. package/dist/api/query/sorting/goalie-sorts.mjs +59 -0
  53. package/dist/api/query/sorting/sorting-options.d.mts +11 -0
  54. package/dist/api/query/sorting/sorting-options.mjs +93 -0
  55. package/dist/api/schedule.d.mts +116 -0
  56. package/dist/api/schedule.mjs +131 -0
  57. package/dist/api/standings.d.mts +28 -0
  58. package/dist/api/standings.mjs +38 -0
  59. package/dist/api/stats.d.mts +148 -0
  60. package/dist/api/stats.mjs +148 -0
  61. package/dist/api/teams.d.mts +58 -0
  62. package/dist/api/teams.mjs +91 -0
  63. package/dist/cli/colors.d.mts +14 -0
  64. package/dist/cli/colors.mjs +13 -0
  65. package/dist/cli/commands.d.mts +27 -0
  66. package/dist/cli/commands.mjs +695 -0
  67. package/dist/cli/run.d.mts +9 -0
  68. package/dist/cli/run.mjs +313 -0
  69. package/dist/cli.d.mts +2 -0
  70. package/dist/cli.mjs +13 -0
  71. package/dist/config.d.mts +20 -0
  72. package/dist/config.mjs +4 -0
  73. package/dist/context.d.mts +6 -0
  74. package/dist/context.mjs +1 -0
  75. package/dist/errors.d.mts +35 -0
  76. package/dist/errors.mjs +49 -0
  77. package/dist/http-client.d.mts +27 -0
  78. package/dist/http-client.mjs +95 -0
  79. package/dist/index.d.mts +21 -0
  80. package/dist/index.mjs +15 -0
  81. package/dist/logging.d.mts +14 -0
  82. package/dist/logging.mjs +13 -0
  83. package/dist/nhl-client.d.mts +97 -0
  84. package/dist/nhl-client.mjs +40 -0
  85. package/dist/utils.d.mts +5 -0
  86. package/dist/utils.mjs +3 -0
  87. package/package.json +77 -3
@@ -0,0 +1,148 @@
1
+ import { goalieStatsSorts } from '#src/api/query/sorting/goalie-sorts.mjs';
2
+ import { defaultSortForReport, } from '#src/api/query/sorting/sorting-options.mjs';
3
+ import { Endpoint } from '#src/http-client.mjs';
4
+ /**
5
+ * Gets all game types played by a team throughout their history.
6
+ *
7
+ * @param params.teamAbbr Team abbreviation, e.g. BUF, TOR
8
+ * @example https://api-web.nhle.com/v1/club-stats-season/TOR
9
+ */
10
+ export const gametypesPerSeasonDirectoryByTeam = async (ctx, { teamAbbr }) => (await ctx.get(Endpoint.API_WEB_V1, `club-stats-season/${teamAbbr}`)).json();
11
+ /**
12
+ * Gets a player's career statistics and biographical information.
13
+ *
14
+ * @param params.playerId NHL player id, e.g. 8481528
15
+ * @example https://api-web.nhle.com/v1/player/8481528/landing
16
+ */
17
+ export const playerCareerStats = async (ctx, { playerId }) => (await ctx.get(Endpoint.API_WEB_V1, `player/${playerId}/landing`)).json();
18
+ /**
19
+ * Gets a player's game log for a specific season and game type.
20
+ *
21
+ * @param params.playerId NHL player id, e.g. 8481528
22
+ * @param params.seasonId Season in YYYYYYYY format, e.g. 20232024
23
+ * @param params.gameType 1=Preseason, 2=Regular season, 3=Playoffs
24
+ * @example https://api-web.nhle.com/v1/player/8481528/game-log/20232024/2
25
+ */
26
+ export const playerGameLog = async (ctx, { playerId, seasonId, gameType, }) => {
27
+ const data = await (await ctx.get(Endpoint.API_WEB_V1, `player/${playerId}/game-log/${seasonId}/${gameType}`)).json();
28
+ return data.gameLog ?? [];
29
+ };
30
+ /**
31
+ * Retrieves team summary statistics across one or more seasons.
32
+ *
33
+ * @example await client.stats.teamSummary({ startSeason: '20232024', endSeason: '20232024' })
34
+ */
35
+ export const teamSummary = async (ctx, { startSeason, endSeason, gameTypeId = 2, isGame = false, isAggregate = false, sortExpr, start = 0, limit = 50, factCayenneExp = 'gamesPlayed>1', defaultCayenneExp, }) => {
36
+ const effectiveSortExpr = sortExpr && sortExpr.length > 0
37
+ ? sortExpr
38
+ : [
39
+ { property: 'points', direction: 'DESC' },
40
+ { property: 'wins', direction: 'DESC' },
41
+ { property: 'teamId', direction: 'ASC' },
42
+ ];
43
+ const effectiveCayenneExp = defaultCayenneExp ??
44
+ `gameTypeId=${gameTypeId} and seasonId<=${endSeason} and seasonId>=${startSeason}`;
45
+ const qParams = {
46
+ isAggregate,
47
+ isGame,
48
+ start,
49
+ limit,
50
+ factCayenneExp,
51
+ sort: JSON.stringify(effectiveSortExpr),
52
+ cayenneExp: effectiveCayenneExp,
53
+ };
54
+ const response = await (await ctx.get(Endpoint.API_STATS, 'en/team/summary', qParams)).json();
55
+ return response.data;
56
+ };
57
+ /**
58
+ * Gets simplified skater statistics summary for specified seasons and
59
+ * franchises.
60
+ *
61
+ * @example await client.stats.skaterStatsSummary({ startSeason: '20232024', endSeason: '20232024', franchiseId: 10 })
62
+ */
63
+ export const skaterStatsSummary = async (ctx, { startSeason, endSeason, franchiseId, gameTypeId = 2, aggregate = false, sortExpr, start = 0, limit = 25, factCayenneExp = 'gamesPlayed>=1', defaultCayenneExp, }) => {
64
+ const effectiveSortExpr = sortExpr && sortExpr.length > 0
65
+ ? sortExpr
66
+ : [
67
+ { property: 'points', direction: 'DESC' },
68
+ { property: 'gamesPlayed', direction: 'ASC' },
69
+ { property: 'playerId', direction: 'ASC' },
70
+ ];
71
+ const baseCayenneExp = defaultCayenneExp ??
72
+ `gameTypeId=${gameTypeId} and seasonId<=${endSeason} and seasonId>=${startSeason}`;
73
+ const effectiveCayenneExp = !defaultCayenneExp && franchiseId
74
+ ? `franchiseId=${franchiseId} and ${baseCayenneExp}`
75
+ : baseCayenneExp;
76
+ const qParams = {
77
+ isAggregate: aggregate,
78
+ isGame: false,
79
+ start,
80
+ limit,
81
+ factCayenneExp,
82
+ sort: JSON.stringify(effectiveSortExpr),
83
+ cayenneExp: effectiveCayenneExp,
84
+ };
85
+ const response = await (await ctx.get(Endpoint.API_STATS, 'en/skater/summary', qParams)).json();
86
+ return response.data;
87
+ };
88
+ /**
89
+ * Retrieves skater statistics using a query context and specified report
90
+ * type. Returns the full response (`{ data, total }`).
91
+ *
92
+ * @example
93
+ * const context = buildQuery([
94
+ * filter.season('20232024', '20232024'),
95
+ * filter.position(PositionTypes.CENTER),
96
+ * ]);
97
+ * await client.stats.skaterStatsWithQueryContext({ queryContext: context, reportType: 'summary' });
98
+ */
99
+ export const skaterStatsWithQueryContext = async (ctx, { queryContext, reportType, sortExpr, aggregate = false, start = 0, limit = 25, }) => {
100
+ const effectiveSortExpr = sortExpr && sortExpr.length > 0
101
+ ? sortExpr
102
+ : defaultSortForReport(reportType);
103
+ const qParams = {
104
+ isAggregate: aggregate,
105
+ isGame: false,
106
+ start,
107
+ limit,
108
+ factCayenneExp: queryContext.factQuery,
109
+ sort: JSON.stringify(effectiveSortExpr),
110
+ cayenneExp: queryContext.query,
111
+ };
112
+ return (await ctx.get(Endpoint.API_STATS, `en/skater/${reportType}`, qParams)).json();
113
+ };
114
+ /**
115
+ * Retrieves goalie statistics with various filtering and aggregation
116
+ * options.
117
+ *
118
+ * @example await client.stats.goalieStatsSummary({ startSeason: '20232024', statsType: 'advanced' })
119
+ */
120
+ export const goalieStatsSummary = async (ctx, { startSeason, endSeason, statsType = 'summary', gameTypeId = 2, franchiseId, aggregate = false, sortExpr, start = 0, limit = 25, factCayenneExp, defaultCayenneExp, }) => {
121
+ const effectiveEndSeason = endSeason === undefined || endSeason === null ? startSeason : endSeason;
122
+ const effectiveSortExpr = sortExpr && sortExpr.length > 0 ? sortExpr : goalieStatsSorts(statsType);
123
+ const baseCayenneExp = defaultCayenneExp ??
124
+ `gameTypeId=${gameTypeId} and seasonId<=${effectiveEndSeason} and seasonId>=${startSeason}`;
125
+ const effectiveCayenneExp = franchiseId
126
+ ? `franchiseId=${franchiseId} and ${baseCayenneExp}`
127
+ : baseCayenneExp;
128
+ const qParams = {
129
+ isAggregate: aggregate,
130
+ isGame: false,
131
+ start,
132
+ limit,
133
+ factCayenneExp,
134
+ sort: JSON.stringify(effectiveSortExpr),
135
+ cayenneExp: effectiveCayenneExp,
136
+ };
137
+ const response = await (await ctx.get(Endpoint.API_STATS, `en/goalie/${statsType}`, qParams)).json();
138
+ return response.data ?? [];
139
+ };
140
+ export const statsApi = {
141
+ gametypesPerSeasonDirectoryByTeam,
142
+ playerCareerStats,
143
+ playerGameLog,
144
+ teamSummary,
145
+ skaterStatsSummary,
146
+ skaterStatsWithQueryContext,
147
+ goalieStatsSummary,
148
+ };
@@ -0,0 +1,58 @@
1
+ import type { Context } from '#src/context.mjs';
2
+ import type { Id, JsonObject } from '#src/utils.mjs';
3
+ export interface Team {
4
+ conference: {
5
+ abbr: string;
6
+ name: string;
7
+ };
8
+ division: {
9
+ abbr: string;
10
+ name: string;
11
+ };
12
+ name: string;
13
+ common_name: string;
14
+ abbr: string;
15
+ logo: string;
16
+ franchise_id?: number;
17
+ }
18
+ /** Converts a raw standings entry into a `Team`. */
19
+ export declare function toTeam(teamData: JsonObject): Team;
20
+ /**
21
+ * Adds a `franchise_id` to each team that has a matching franchise. Teams
22
+ * without a match are returned unchanged (no `franchise_id` key).
23
+ */
24
+ export declare function withFranchiseIds(teams: readonly Team[], franchises: readonly JsonObject[]): Team[];
25
+ /**
26
+ * Get a list of all NHL teams with conference, division, and franchise info.
27
+ *
28
+ * Team list is derived from the standings for the given date, then enriched
29
+ * with franchise ids.
30
+ *
31
+ * @param params.date Date in YYYY-MM-DD format. Defaults to "now".
32
+ * @example await client.teams.teams()
33
+ */
34
+ export declare const teams: (ctx: Context, { date }?: {
35
+ date?: string;
36
+ }) => Promise<Team[]>;
37
+ /**
38
+ * Get the roster for the given team and season.
39
+ *
40
+ * @param params.teamAbbr Team abbreviation, e.g. BUF, TOR
41
+ * @param params.season Season in YYYYYYYY format, e.g. 20232024
42
+ * @example https://api-web.nhle.com/v1/roster/BUF/20232024
43
+ */
44
+ export declare const teamRoster: (ctx: Context, { teamAbbr, season }: {
45
+ teamAbbr: string;
46
+ season: Id;
47
+ }) => Promise<JsonObject>;
48
+ /**
49
+ * Get a list of all past and current NHL franchises.
50
+ *
51
+ * @example https://api.nhle.com/stats/rest/en/franchise
52
+ */
53
+ export declare const franchises: (ctx: Context) => Promise<JsonObject[]>;
54
+ export declare const teamsApi: {
55
+ readonly teams: typeof teams;
56
+ readonly teamRoster: typeof teamRoster;
57
+ readonly franchises: typeof franchises;
58
+ };
@@ -0,0 +1,91 @@
1
+ import { Endpoint } from '#src/http-client.mjs';
2
+ async function fetchStandingsData(ctx, date) {
3
+ const response = await (await ctx.get(Endpoint.API_WEB_V1, `standings/${date}`)).json();
4
+ return response.standings ?? [];
5
+ }
6
+ /** Converts a raw standings entry into a `Team`. */
7
+ export function toTeam(teamData) {
8
+ const nestedDefault = (key) => teamData[key]?.default ?? '';
9
+ return {
10
+ conference: {
11
+ abbr: teamData.conferenceAbbrev ?? '',
12
+ name: teamData.conferenceName ?? '',
13
+ },
14
+ division: {
15
+ abbr: teamData.divisionAbbrev ?? '',
16
+ name: teamData.divisionName ?? '',
17
+ },
18
+ name: nestedDefault('teamName'),
19
+ common_name: nestedDefault('teamCommonName'),
20
+ abbr: nestedDefault('teamAbbrev'),
21
+ logo: teamData.teamLogo ?? '',
22
+ };
23
+ }
24
+ /** Find franchise ID for a team name, with fallbacks for known name mismatches. */
25
+ function findFranchiseId(teamName, lookup) {
26
+ if (lookup.has(teamName)) {
27
+ return lookup.get(teamName);
28
+ }
29
+ // "Montreal Canadiens" vs "Montréal Canadiens", Utah's renames, etc.
30
+ for (const partial of ['Canadiens', 'Utah']) {
31
+ if (teamName.includes(partial)) {
32
+ for (const [franchiseName, franchiseId] of lookup) {
33
+ if (franchiseName.includes(partial)) {
34
+ return franchiseId;
35
+ }
36
+ }
37
+ return undefined;
38
+ }
39
+ }
40
+ return undefined;
41
+ }
42
+ /**
43
+ * Adds a `franchise_id` to each team that has a matching franchise. Teams
44
+ * without a match are returned unchanged (no `franchise_id` key).
45
+ */
46
+ export function withFranchiseIds(teams, franchises) {
47
+ const lookup = new Map();
48
+ for (const franchise of franchises) {
49
+ const fullName = franchise.fullName ?? '';
50
+ const franchiseId = franchise.id;
51
+ if (fullName && franchiseId) {
52
+ lookup.set(fullName, franchiseId);
53
+ }
54
+ }
55
+ return teams.map((team) => {
56
+ const franchiseId = findFranchiseId(team.name ?? '', lookup);
57
+ return franchiseId ? { ...team, franchise_id: franchiseId } : { ...team };
58
+ });
59
+ }
60
+ /**
61
+ * Get a list of all NHL teams with conference, division, and franchise info.
62
+ *
63
+ * Team list is derived from the standings for the given date, then enriched
64
+ * with franchise ids.
65
+ *
66
+ * @param params.date Date in YYYY-MM-DD format. Defaults to "now".
67
+ * @example await client.teams.teams()
68
+ */
69
+ export const teams = async (ctx, { date = 'now' } = {}) => {
70
+ const standingsData = await fetchStandingsData(ctx, date);
71
+ const franchiseData = await franchises(ctx);
72
+ return withFranchiseIds(standingsData.map(toTeam), franchiseData);
73
+ };
74
+ /**
75
+ * Get the roster for the given team and season.
76
+ *
77
+ * @param params.teamAbbr Team abbreviation, e.g. BUF, TOR
78
+ * @param params.season Season in YYYYYYYY format, e.g. 20232024
79
+ * @example https://api-web.nhle.com/v1/roster/BUF/20232024
80
+ */
81
+ export const teamRoster = async (ctx, { teamAbbr, season }) => (await ctx.get(Endpoint.API_WEB_V1, `roster/${teamAbbr}/${season}`)).json();
82
+ /**
83
+ * Get a list of all past and current NHL franchises.
84
+ *
85
+ * @example https://api.nhle.com/stats/rest/en/franchise
86
+ */
87
+ export const franchises = async (ctx) => {
88
+ const response = await (await ctx.get(Endpoint.API_STATS, 'en/franchise')).json();
89
+ return response.data ?? [];
90
+ };
91
+ export const teamsApi = { teams, teamRoster, franchises };
@@ -0,0 +1,14 @@
1
+ import { styleText } from 'node:util';
2
+ export type Style = Parameters<typeof styleText>[0];
3
+ export declare const toStdout: (format: Style) => (text: string) => string;
4
+ export declare const toStderr: (format: Style) => (text: string) => string;
5
+ export declare const colors: {
6
+ dim: (text: string) => string;
7
+ pass: (text: string) => string;
8
+ fail: (text: string) => string;
9
+ ok: (text: string) => string;
10
+ success: (text: string) => string;
11
+ error: (text: string) => string;
12
+ warn: (text: string) => string;
13
+ bold: (text: string) => string;
14
+ };
@@ -0,0 +1,13 @@
1
+ import { styleText } from 'node:util';
2
+ export const toStdout = (format) => (text) => styleText(format, text, { stream: process.stdout });
3
+ export const toStderr = (format) => (text) => styleText(format, text, { stream: process.stderr });
4
+ export const colors = {
5
+ dim: toStdout('dim'),
6
+ pass: toStdout(['bold', 'green']),
7
+ fail: toStdout(['bold', 'red']),
8
+ ok: toStdout('green'),
9
+ success: toStdout(['bold', 'green']),
10
+ error: toStderr('red'),
11
+ warn: toStderr('yellow'),
12
+ bold: toStderr('bold'),
13
+ };
@@ -0,0 +1,27 @@
1
+ import type { NHLClient } from '#src/nhl-client.mjs';
2
+ export type ArgType = 'string' | 'int' | 'number' | 'boolean' | 'list' | 'int-list' | 'json';
3
+ export interface ArgSpec {
4
+ /** SDK parameter name (camelCase). The CLI flag is its kebab-case form. */
5
+ name: string;
6
+ type: ArgType;
7
+ description: string;
8
+ required?: boolean;
9
+ /** Shown in help only; the SDK applies its own defaults. */
10
+ default?: string;
11
+ choices?: readonly string[];
12
+ }
13
+ export interface CommandSpec {
14
+ name: string;
15
+ description: string;
16
+ args: ArgSpec[];
17
+ run: (client: NHLClient, values: any) => Promise<unknown>;
18
+ }
19
+ export interface ModuleSpec {
20
+ name: string;
21
+ description: string;
22
+ commands: CommandSpec[];
23
+ }
24
+ /** Thrown for invalid command-line input (exit code 2). */
25
+ export declare class UsageError extends Error {
26
+ }
27
+ export declare const MODULES: ModuleSpec[];