gametime-api-client 1.2.1 → 1.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 (3) hide show
  1. package/README.md +2 -0
  2. package/dist/index.js +50 -1
  3. package/package.json +3 -13
package/README.md CHANGED
@@ -107,6 +107,8 @@ const csv = await gametime.situations.exportCsv(id, 'nba');
107
107
  writeFileSync('austin-reaves-q4-down-1-15.csv', csv);
108
108
  ```
109
109
 
110
+ `situations.create` automatically retries transient upstream failures (`429`, `502`, `503`, `504`) with capped exponential backoff. This keeps client usage simple, but heavily rate-limited periods can increase response time.
111
+
110
112
  ## API reference
111
113
 
112
114
  | Method | Description |
package/dist/index.js CHANGED
@@ -22,6 +22,11 @@ class ApiError extends Error {
22
22
  this.name = "GametimeApiError";
23
23
  }
24
24
  }
25
+ const CREATE_SITUATION_RETRY = {
26
+ maxAttempts: 5,
27
+ baseDelayMs: 600,
28
+ maxDelayMs: 12000,
29
+ };
25
30
  async function request(baseUrl, path, init) {
26
31
  const url = `${baseUrl.replace(/\/$/, "")}${path}`;
27
32
  const res = await fetch(url, {
@@ -35,6 +40,25 @@ async function request(baseUrl, path, init) {
35
40
  }
36
41
  return body;
37
42
  }
43
+ async function requestWithRetry(run, shouldRetry, options = {}) {
44
+ const maxAttempts = sanitizePositiveInt(options.maxAttempts, CREATE_SITUATION_RETRY.maxAttempts);
45
+ const baseDelayMs = sanitizePositiveInt(options.baseDelayMs, CREATE_SITUATION_RETRY.baseDelayMs);
46
+ const maxDelayMs = sanitizePositiveInt(options.maxDelayMs, CREATE_SITUATION_RETRY.maxDelayMs);
47
+ let lastError;
48
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
49
+ try {
50
+ return await run();
51
+ }
52
+ catch (error) {
53
+ lastError = error;
54
+ if (!shouldRetry(error) || attempt >= maxAttempts) {
55
+ throw error;
56
+ }
57
+ await sleep(calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs));
58
+ }
59
+ }
60
+ throw lastError;
61
+ }
38
62
  function get(baseUrl, path) {
39
63
  return request(baseUrl, path, { method: "GET" });
40
64
  }
@@ -77,7 +101,7 @@ export function createClient(options = {}) {
77
101
  };
78
102
  const situations = {
79
103
  create(params) {
80
- return post(baseUrl, "/v1/situations", params);
104
+ return requestWithRetry(() => post(baseUrl, "/v1/situations", params), isRetryableCreateSituationError);
81
105
  },
82
106
  analysis(id, sport) {
83
107
  return get(baseUrl, `/v1/situations/${encodeURIComponent(id)}/analysis?sport=${sport}`);
@@ -94,3 +118,28 @@ export function createClient(options = {}) {
94
118
  /** Pre-built client using default hosted API URL */
95
119
  export const gametime = createClient();
96
120
  export { ApiError };
121
+ function isRetryableCreateSituationError(error) {
122
+ if (!(error instanceof ApiError)) {
123
+ return false;
124
+ }
125
+ const status = error.status;
126
+ if (status === 429 || status === 502 || status === 503 || status === 504) {
127
+ return true;
128
+ }
129
+ const upstreamStatus = error.details?.status;
130
+ return upstreamStatus === 429;
131
+ }
132
+ function calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs) {
133
+ const exponential = Math.min(maxDelayMs, baseDelayMs * (2 ** (attempt - 1)));
134
+ const jitter = Math.floor(Math.random() * Math.min(250, Math.max(1, Math.floor(exponential * 0.25))));
135
+ return Math.min(maxDelayMs, exponential + jitter);
136
+ }
137
+ function sanitizePositiveInt(value, fallback) {
138
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
139
+ return fallback;
140
+ }
141
+ return Math.floor(value);
142
+ }
143
+ function sleep(ms) {
144
+ return new Promise((resolve) => setTimeout(resolve, ms));
145
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gametime-api-client",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "JavaScript client for Gametime API - live sports data, player analysis, and predictions",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,22 +12,12 @@
12
12
  "default": "./dist/index.js"
13
13
  }
14
14
  },
15
- "files": [
16
- "dist"
17
- ],
15
+ "files": ["dist"],
18
16
  "scripts": {
19
17
  "build": "tsc",
20
18
  "prepublishOnly": "npm run build"
21
19
  },
22
- "keywords": [
23
- "gametime",
24
- "sports",
25
- "api",
26
- "nba",
27
- "soccer",
28
- "live",
29
- "prediction"
30
- ],
20
+ "keywords": ["gametime", "sports", "api", "nba", "soccer", "live", "prediction"],
31
21
  "author": "",
32
22
  "license": "MIT",
33
23
  "devDependencies": {