irdata_js 0.2.1 → 0.4.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # irdata_js
2
2
 
3
- JavaScript library to interact with the iRacing /data API.
3
+ A JavaScript library to interact with the iRacing /data API.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,6 +8,34 @@ JavaScript library to interact with the iRacing /data API.
8
8
  npm install irdata_js
9
9
  ```
10
10
 
11
+ ## Compatibility
12
+
13
+ - **Node.js**: v20.0.0 or newer.
14
+ - **Browsers**: Modern browsers supporting ES2022 (Chrome 100+, Firefox 100+, Safari 15.4+).
15
+
16
+ ## Client Registration
17
+
18
+ Before using the library, you must register your application with iRacing to obtain a Client ID and configure your Redirect URI.
19
+
20
+ Please refer to the [official iRacing Client Registration documentation](https://oauth.iracing.com/oauth2/book/client_registration.html).
21
+
22
+ > [!NOTE]
23
+ > It may take up to **10 business days** for registration requests to be processed.
24
+
25
+ ## CDN Usage
26
+
27
+ For direct usage in the browser without a build step, you can load the library via a CDN. The library is exposed as the global `irdata` variable.
28
+
29
+ ```html
30
+ <script src="https://unpkg.com/irdata_js/dist/index.global.js"></script>
31
+ <script>
32
+ const client = new irdata.IRacingClient({
33
+ clientId: 'YOUR_CLIENT_ID',
34
+ redirectUri: 'YOUR_REDIRECT_URI',
35
+ });
36
+ </script>
37
+ ```
38
+
11
39
  ## Quick Start
12
40
 
13
41
  The library supports OAuth 2.0 authentication.
@@ -18,18 +46,54 @@ The library supports OAuth 2.0 authentication.
18
46
  import { IRacingClient } from 'irdata_js';
19
47
 
20
48
  const client = new IRacingClient({
21
- auth: {
22
- clientId: 'YOUR_CLIENT_ID', // Required for OAuth
23
- redirectUri: 'YOUR_REDIRECT_URI', // Required for OAuth
24
- },
49
+ clientId: 'YOUR_CLIENT_ID', // Required for OAuth
50
+ redirectUri: 'YOUR_REDIRECT_URI', // Required for OAuth
25
51
  });
26
52
  ```
27
53
 
54
+ ### Configuration
55
+
56
+ The `IRacingClient` constructor accepts two optional configuration objects: `AuthConfig` and `ProxyConfig`.
57
+
58
+ ```javascript
59
+ const authConfig = {
60
+ clientId: 'YOUR_CLIENT_ID',
61
+ redirectUri: 'YOUR_REDIRECT_URI',
62
+ };
63
+
64
+ const proxyConfig = {
65
+ apiUrl: 'https://your-proxy.com/data',
66
+ fileProxyUrl: 'https://your-proxy.com/passthrough',
67
+ authBaseUrl: 'https://your-proxy.com/oauth2',
68
+ tokenEndpoint: 'https://your-proxy.com/token',
69
+ };
70
+
71
+ const client = new IRacingClient(authConfig, proxyConfig);
72
+ ```
73
+
74
+ #### AuthConfig
75
+
76
+ | Property | Type | Required | Description |
77
+ | :------------ | :------- | :------- | :---------------------------------------------------------------- |
78
+ | `clientId` | `string` | **Yes** | Your iRacing OAuth client ID. |
79
+ | `redirectUri` | `string` | **Yes** | The URI iRacing will redirect to after successful authentication. |
80
+
81
+ #### ProxyConfig
82
+
83
+ Since the iRacing API and S3 buckets do not support CORS, you need to use a proxy for browser-based applications. If you provide a `ProxyConfig` object, the following fields are mandatory (except `authBaseUrl`).
84
+
85
+ | Property | Type | Required | Description |
86
+ | :-------------- | :------- | :------- | :-------------------------------------------------------------------------------------------------- |
87
+ | `apiUrl` | `string` | **Yes** | The base URL for API requests. |
88
+ | `fileProxyUrl` | `string` | **Yes** | A proxy URL for fetching S3 files. The original S3 URL will be appended as a `url` query parameter. |
89
+ | `tokenEndpoint` | `string` | **Yes** | The specific endpoint for token exchange. |
90
+ | `authBaseUrl` | `string` | No | The base URL for OAuth authorization. Defaults to `https://oauth.iracing.com/oauth2`. |
91
+
28
92
  ### 2. Authentication
29
93
 
30
94
  #### Web / Browser (OAuth 2.0 PKCE)
31
95
 
32
- To authenticate in the browser, you need to generate an authorization URL, redirect the user, and then handle the callback.
96
+ To authenticate in the browser, you need to generate an authorization URL, redirect the user, and then handle the return.
33
97
 
34
98
  **Step 1: Generate Auth URL and Redirect**
35
99
 
@@ -38,18 +102,26 @@ const url = await client.auth.generateAuthUrl();
38
102
  window.location.href = url;
39
103
  ```
40
104
 
41
- **Step 2: Handle Callback**
105
+ **Step 2: Handle Return & Restore Session**
42
106
 
43
- On your redirect page, capture the `code` from the URL:
107
+ Simply call `handleAuthentication()` on every page that uses the library. This single method handles:
108
+ - Exchanging the authorization code (when returning from the iRacing login page).
109
+ - Refreshing the access token (if a refresh token is stored).
110
+ - Verifying an existing session.
44
111
 
45
112
  ```javascript
46
- const params = new URLSearchParams(window.location.search);
47
- const code = params.get('code');
113
+ // This should run on every page load of your application,
114
+ // including the redirectUri page.
115
+ const isAuthenticated = await client.auth.handleAuthentication();
116
+ ```
48
117
 
49
- if (code) {
50
- await client.auth.handleCallback(code);
51
- // Success! The client is now authenticated with an access token.
52
- }
118
+ #### Manual Session Management
119
+
120
+ If you have obtained an access token (and refresh token) through other means (e.g., server-side authentication), you can manually set the session on the client.
121
+
122
+ ```javascript
123
+ // Set the access token (and optional refresh token)
124
+ client.auth.setSession('YOUR_ACCESS_TOKEN', 'YOUR_REFRESH_TOKEN');
53
125
  ```
54
126
 
55
127
  ### 3. Fetch Data
@@ -60,10 +132,13 @@ Once authenticated, you can call any endpoint using `getData`. This method handl
60
132
  try {
61
133
  // Call an endpoint directly
62
134
  const { data, metadata } = await client.getData('/member/info');
63
-
135
+
64
136
  console.log(data); // The actual API response
137
+ console.log(metadata.contentType); // Response content type (e.g. 'application/json')
65
138
  console.log(metadata.sizeBytes); // Response size in bytes
66
- console.log(metadata.chunksDetected); // Boolean indicating if data is chunked
139
+ console.log(metadata.fetchTimeMs); // Fetch duration in milliseconds
140
+ console.log(metadata.chunkCount); // Number of chunks (0 if not chunked)
141
+ console.log(metadata.chunkRows); // Total rows across all chunks (valid if chunkCount > 0)
67
142
  } catch (error) {
68
143
  console.error('Failed to fetch member info:', error);
69
144
  }
@@ -71,14 +146,14 @@ try {
71
146
 
72
147
  ### 4. Handling Large Datasets (Chunks)
73
148
 
74
- Some iRacing endpoints (like large result sets) return data in multiple "chunks" hosted on S3. When `metadata.chunksDetected` is true, you can use the library to fetch the rest of the data.
149
+ Some iRacing endpoints (like large result sets) return data in multiple "chunks" hosted on S3. When `metadata.chunkCount` is greater than 0, you can use the library to fetch the rest of the data.
75
150
 
76
151
  #### Fetch all chunks at once
77
152
 
78
153
  ```javascript
79
154
  const result = await client.getData('/results/get');
80
155
 
81
- if (result.metadata.chunksDetected) {
156
+ if (result.metadata.chunkCount > 0) {
82
157
  // Fetch and merge all chunks into a single array
83
158
  const { data: allResults } = await client.getChunks(result.data);
84
159
  console.log('Total results:', allResults.length);
@@ -90,9 +165,9 @@ if (result.metadata.chunksDetected) {
90
165
  For extremely large datasets, you might want to fetch chunks one by one:
91
166
 
92
167
  ```javascript
93
- if (result.metadata.chunksDetected) {
94
- const totalChunks = result.data.chunk_info.chunk_file_names.length;
95
-
168
+ if (result.metadata.chunkCount > 0) {
169
+ const totalChunks = result.metadata.chunkCount;
170
+
96
171
  for (let i = 0; i < totalChunks; i++) {
97
172
  const { data: chunk } = await client.getChunk(result.data, i);
98
173
  console.log(`Processing chunk ${i + 1}/${totalChunks}`);
@@ -100,6 +175,18 @@ if (result.metadata.chunksDetected) {
100
175
  }
101
176
  ```
102
177
 
178
+ > **Note:** iRacing's API incorrectly returns `application/octet-stream` as the `Content-Type` for JSON chunks. This library automatically detects and parses these as JSON.
179
+
180
+ ## The Proxy Requirement (CORS)
181
+
182
+ The iRacing API (`members-ng.iracing.com`) and its associated S3 data links do not provide CORS (`Cross-Origin Resource Sharing`) headers for third-party domains. This means that direct requests from a web browser to the API will be blocked by the browser's security policies.
183
+
184
+ This behavior is intentional by iRacing to better protect their business and operations and is unlikely to change (see [this message by their head of operations](https://forums.iracing.com/discussion/comment/772334/#Comment_772334)).
185
+
186
+ To use this library in a web application, you must route your requests through a proxy server that adds the necessary CORS headers or resides on the same domain as your application.
187
+
188
+ For development and as a reference implementation, this repository includes a `proxy_server.js` that demonstrates how to implement such a workaround. See the [Development](#development) section for more details on how to use it.
189
+
103
190
  ## Development
104
191
 
105
192
  ### Build
@@ -112,7 +199,9 @@ npm run build
112
199
 
113
200
  This repository includes a local development proxy server and a demo application to test the OAuth flow and API interaction, avoiding CORS issues during development.
114
201
 
115
- 1. Create a file named `config.json` in the `demo/` directory (ignored by git) with your configuration:
202
+ 1. Create a file named `config.json` in the `demo/` directory (ignored by git) with your configuration. See the [Configuration](#configuration) section for details on the `ProxyConfig` and `AuthConfig` structures which map to this JSON file.
203
+
204
+ **Example `demo/config.json`:**
116
205
 
117
206
  ```json
118
207
  {
@@ -127,23 +216,17 @@ This repository includes a local development proxy server and a demo application
127
216
  }
128
217
  ```
129
218
 
130
- * `port`: The port the proxy server will listen on.
131
- * `basePath`: The path prefix where the static files and proxy endpoints are served from.
132
- * `redirectPath`: The path the proxy server intercepts for OAuth callbacks.
133
- * `auth`: Your iRacing API credentials. Note that `tokenEndpoint` should include the `basePath`.
134
-
135
219
  2. Start the proxy server:
136
220
 
137
221
  ```bash
138
222
  npm run dev
139
223
  ```
140
224
 
141
- *This command automatically generates the `demo/index.html` from the template using your configuration and starts the proxy server.*
142
- *Depending on your system configuration, you might need elevated privileges (e.g., `sudo`) to listen on port 80.*
225
+ _This command automatically generates the `demo/index.html` from the template using your configuration and starts the proxy server._
226
+ _Depending on your system configuration, you might need elevated privileges (e.g., `sudo`) to listen on port 80._
143
227
 
144
228
  3. Open `http://127.0.0.1/irdata_js/` (or your configured `basePath`) in your browser.
145
- * The demo app is configured to use the local proxy endpoints (e.g., `/irdata_js/token`, `/irdata_js/data`, `/irdata_js/passthrough`) to bypass CORS restrictions.
146
-
229
+ - The demo app is configured to use the local proxy endpoints (e.g., `/irdata_js/token`, `/irdata_js/data`, `/irdata_js/passthrough`) to bypass CORS restrictions.
147
230
 
148
231
  ## License
149
232