vairified 0.1.0 → 0.2.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 +250 -256
- package/dist/index.cjs +766 -819
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +821 -780
- package/dist/index.d.ts +821 -780
- package/dist/index.js +758 -813
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,538 +1,782 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* HTTP transport — internal. Not part of the public API.
|
|
3
3
|
*
|
|
4
|
+
* The transport is a thin wrapper around native `fetch` that:
|
|
5
|
+
*
|
|
6
|
+
* - Injects the API key header on every request.
|
|
7
|
+
* - Serializes query params (dropping `undefined`) and JSON bodies.
|
|
8
|
+
* - Applies a request timeout via `AbortController`.
|
|
9
|
+
* - Maps non-2xx responses to the right typed exception.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
4
12
|
* @module
|
|
5
13
|
*/
|
|
6
14
|
/**
|
|
7
|
-
*
|
|
15
|
+
* Values accepted as query parameters.
|
|
16
|
+
*
|
|
17
|
+
* `null` and `undefined` are silently dropped. Arrays are joined with
|
|
18
|
+
* `','`. Everything else is stringified.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
type QueryParams = Readonly<Record<string, string | number | boolean | readonly (string | number)[] | null | undefined>>;
|
|
23
|
+
/**
|
|
24
|
+
* Options passed to the internal HTTP layer.
|
|
25
|
+
*
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
interface RequestOptions {
|
|
29
|
+
readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
30
|
+
readonly path: string;
|
|
31
|
+
readonly query?: QueryParams;
|
|
32
|
+
readonly body?: unknown;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Transport configuration.
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
interface TransportConfig {
|
|
40
|
+
readonly baseUrl: string;
|
|
41
|
+
readonly apiKey: string;
|
|
42
|
+
readonly timeoutMs: number;
|
|
43
|
+
readonly fetch: typeof fetch;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Internal HTTP client. Holds no state between requests — each call
|
|
47
|
+
* builds a fresh `Request`, runs it, and returns the parsed body.
|
|
8
48
|
*
|
|
9
|
-
* @
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
declare class HttpTransport {
|
|
52
|
+
#private;
|
|
53
|
+
constructor(config: TransportConfig);
|
|
54
|
+
request<T>(options: RequestOptions): Promise<T>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Vairified SDK — Partner API v1 wire types.
|
|
59
|
+
*
|
|
60
|
+
* These are the raw shapes the server returns or accepts. Request
|
|
61
|
+
* types (e.g. {@link MatchBatch}, {@link SearchFilters}) are used as-is
|
|
62
|
+
* by the SDK. Response types (e.g. {@link PartnerMemberWire}) are
|
|
63
|
+
* wrapped in class instances by the SDK — see the `models/` folder.
|
|
64
|
+
*
|
|
65
|
+
* @module
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* Environment preset for the Vairified API.
|
|
69
|
+
*
|
|
70
|
+
* @category Client
|
|
71
|
+
*/
|
|
72
|
+
type VairifiedEnvironment = 'production' | 'staging' | 'local';
|
|
73
|
+
/**
|
|
74
|
+
* Options passed to the {@link Vairified} constructor.
|
|
75
|
+
*
|
|
76
|
+
* @category Client
|
|
10
77
|
*/
|
|
11
78
|
interface VairifiedOptions {
|
|
12
|
-
/** API key
|
|
79
|
+
/** Partner API key (`vair_pk_...`). Falls back to `VAIRIFIED_API_KEY`. */
|
|
13
80
|
apiKey?: string;
|
|
14
|
-
/** Environment preset
|
|
15
|
-
env?:
|
|
16
|
-
/**
|
|
81
|
+
/** Environment preset. Falls back to `VAIRIFIED_ENV` or `'production'`. */
|
|
82
|
+
env?: VairifiedEnvironment;
|
|
83
|
+
/** Explicit base URL. Takes precedence over `env`. */
|
|
17
84
|
baseUrl?: string;
|
|
18
|
-
/** Request timeout in milliseconds (
|
|
19
|
-
|
|
85
|
+
/** Request timeout in milliseconds. Defaults to 30_000 (30s). */
|
|
86
|
+
timeoutMs?: number;
|
|
87
|
+
/**
|
|
88
|
+
* Inject a custom `fetch` implementation. Defaults to the global
|
|
89
|
+
* `fetch`. Useful for test shims or non-Node environments.
|
|
90
|
+
*/
|
|
91
|
+
fetch?: typeof fetch;
|
|
20
92
|
}
|
|
21
93
|
/**
|
|
22
|
-
*
|
|
94
|
+
* Normalized gender tokens emitted by the Partner API.
|
|
23
95
|
*
|
|
24
|
-
* @category
|
|
96
|
+
* @category Members
|
|
25
97
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
98
|
+
type Gender = 'MALE' | 'FEMALE' | 'OTHER' | 'UNKNOWN';
|
|
99
|
+
/**
|
|
100
|
+
* Raw rating split — one slice of a player's rating for a specific
|
|
101
|
+
* category × age bracket.
|
|
102
|
+
*
|
|
103
|
+
* @category Members
|
|
104
|
+
*/
|
|
105
|
+
interface RatingSplitWire {
|
|
106
|
+
readonly rating: number;
|
|
107
|
+
readonly abbr: string;
|
|
33
108
|
}
|
|
34
109
|
/**
|
|
35
|
-
*
|
|
110
|
+
* Raw sport rating — a player's ratings for one sport.
|
|
36
111
|
*
|
|
37
|
-
* @category
|
|
112
|
+
* @category Members
|
|
38
113
|
*/
|
|
39
|
-
|
|
114
|
+
interface SportRatingWire {
|
|
115
|
+
readonly rating: number;
|
|
116
|
+
readonly abbr: string;
|
|
117
|
+
readonly ratingSplits: Readonly<Record<string, RatingSplitWire>>;
|
|
118
|
+
}
|
|
40
119
|
/**
|
|
41
|
-
*
|
|
120
|
+
* Grouped member status flags.
|
|
42
121
|
*
|
|
43
|
-
* @category
|
|
122
|
+
* @category Members
|
|
44
123
|
*/
|
|
45
|
-
interface
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
email?: string;
|
|
52
|
-
rating?: number;
|
|
53
|
-
isVairified?: boolean;
|
|
54
|
-
ratingSplits?: RatingSplitsData;
|
|
55
|
-
city?: string;
|
|
56
|
-
state?: string;
|
|
57
|
-
country?: string;
|
|
58
|
-
/** Scopes the player granted to your app */
|
|
59
|
-
grantedScopes?: string[];
|
|
124
|
+
interface MemberStatusWire {
|
|
125
|
+
readonly isVairified: boolean;
|
|
126
|
+
readonly isWheelchair: boolean;
|
|
127
|
+
readonly isAmbassador: boolean;
|
|
128
|
+
readonly isRater: boolean;
|
|
129
|
+
readonly isConnected: boolean;
|
|
60
130
|
}
|
|
61
131
|
/**
|
|
62
|
-
*
|
|
132
|
+
* Raw partner-facing member record returned by the Partner API.
|
|
63
133
|
*
|
|
64
|
-
* @category
|
|
134
|
+
* @category Members
|
|
65
135
|
*/
|
|
66
|
-
interface
|
|
67
|
-
|
|
68
|
-
id
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
136
|
+
interface PartnerMemberWire {
|
|
137
|
+
readonly memberId: number;
|
|
138
|
+
readonly id?: string;
|
|
139
|
+
readonly firstName: string;
|
|
140
|
+
readonly lastName: string;
|
|
141
|
+
readonly fullName: string;
|
|
142
|
+
readonly displayName: string;
|
|
143
|
+
readonly age?: number;
|
|
144
|
+
readonly city?: string;
|
|
145
|
+
readonly state?: string;
|
|
146
|
+
readonly zip?: string;
|
|
147
|
+
readonly country?: string;
|
|
148
|
+
readonly gender?: Gender;
|
|
149
|
+
readonly status: MemberStatusWire;
|
|
150
|
+
readonly sport?: Readonly<Record<string, SportRatingWire>>;
|
|
151
|
+
readonly activeLeagues?: readonly string[];
|
|
152
|
+
readonly email?: string;
|
|
153
|
+
readonly grantedScopes?: readonly string[];
|
|
78
154
|
}
|
|
79
155
|
/**
|
|
80
|
-
*
|
|
156
|
+
* Raw rating change notification.
|
|
81
157
|
*
|
|
82
|
-
* @category
|
|
158
|
+
* @category Members
|
|
159
|
+
*/
|
|
160
|
+
interface PartnerRatingUpdateWire {
|
|
161
|
+
readonly memberId: number;
|
|
162
|
+
readonly id?: string;
|
|
163
|
+
readonly displayName?: string;
|
|
164
|
+
readonly sport?: string;
|
|
165
|
+
readonly previousRating?: number;
|
|
166
|
+
readonly newRating?: number;
|
|
167
|
+
readonly changedAt?: string;
|
|
168
|
+
readonly ratingSplits?: Readonly<Record<string, RatingSplitWire>>;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Filters accepted by {@link MembersResource.search}.
|
|
172
|
+
*
|
|
173
|
+
* Most callers pass these as keyword arguments directly to `search()`;
|
|
174
|
+
* the SDK serializes them to query parameters for you.
|
|
175
|
+
*
|
|
176
|
+
* @category Members
|
|
83
177
|
*/
|
|
84
178
|
interface SearchFilters {
|
|
85
|
-
/**
|
|
179
|
+
/** Sport code (e.g. `'pickleball'`) or list of codes. */
|
|
180
|
+
sport?: string | readonly string[];
|
|
181
|
+
/** Partial name match (first or last). */
|
|
86
182
|
name?: string;
|
|
87
|
-
/**
|
|
183
|
+
/** Exact numeric member ID. */
|
|
184
|
+
memberId?: number | string;
|
|
88
185
|
city?: string;
|
|
89
|
-
/** State code (e.g., "TX") */
|
|
90
186
|
state?: string;
|
|
91
|
-
/** Country code (e.g., "US") */
|
|
92
187
|
country?: string;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
188
|
+
zip?: string;
|
|
189
|
+
location?: string;
|
|
190
|
+
gender?: Gender | Lowercase<Gender>;
|
|
191
|
+
/** When `true`, only return verified players. */
|
|
192
|
+
vairifiedOnly?: boolean;
|
|
193
|
+
/** When `true`, only return wheelchair players. */
|
|
194
|
+
wheelchair?: boolean;
|
|
195
|
+
/** Lower rating bound (2.0–8.0). */
|
|
96
196
|
ratingMin?: number;
|
|
97
|
-
/**
|
|
197
|
+
/** Upper rating bound (2.0–8.0). */
|
|
98
198
|
ratingMax?: number;
|
|
99
|
-
/**
|
|
100
|
-
gender?: 'MALE' | 'FEMALE';
|
|
101
|
-
/** Only verified players */
|
|
102
|
-
vairifiedOnly?: boolean;
|
|
103
|
-
/** Exact age */
|
|
199
|
+
/** Exact age. */
|
|
104
200
|
age?: number;
|
|
105
|
-
/**
|
|
201
|
+
/** Lower age bound. */
|
|
106
202
|
ageMin?: number;
|
|
107
|
-
/**
|
|
203
|
+
/** Upper age bound. */
|
|
108
204
|
ageMax?: number;
|
|
109
|
-
/** Field to sort by */
|
|
110
205
|
sortBy?: string;
|
|
111
|
-
/** Sort direction */
|
|
112
206
|
sortOrder?: 'asc' | 'desc';
|
|
113
|
-
/** Page
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
|
|
207
|
+
/** Page size requested per HTTP request (server cap 100). Default 20. */
|
|
208
|
+
pageSize?: number;
|
|
209
|
+
/**
|
|
210
|
+
* Maximum total results to iterate. When set, the async iterator
|
|
211
|
+
* stops after yielding this many items, regardless of page count.
|
|
212
|
+
*/
|
|
213
|
+
maxResults?: number;
|
|
117
214
|
}
|
|
118
215
|
/**
|
|
119
|
-
*
|
|
216
|
+
* One scored game within a {@link MatchInput}.
|
|
120
217
|
*
|
|
121
|
-
*
|
|
218
|
+
* `scores` contains one integer per team, in the same order as the
|
|
219
|
+
* parent match's `teams` list. For a standard 2-team game that's
|
|
220
|
+
* `[team1Score, team2Score]`. Longer lists are supported for
|
|
221
|
+
* n-team matches.
|
|
222
|
+
*
|
|
223
|
+
* All other fields override the parent match's defaults for this
|
|
224
|
+
* specific game (e.g. a championship game played to 15 when the rest
|
|
225
|
+
* of the match was to 11).
|
|
226
|
+
*
|
|
227
|
+
* @category Matches
|
|
228
|
+
*/
|
|
229
|
+
interface GameInput {
|
|
230
|
+
readonly scores: readonly number[];
|
|
231
|
+
readonly identifier?: string;
|
|
232
|
+
readonly winScore?: number;
|
|
233
|
+
readonly winBy?: number;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* One match to submit in a {@link MatchBatch}.
|
|
237
|
+
*
|
|
238
|
+
* A match is n-team × n-game:
|
|
239
|
+
*
|
|
240
|
+
* - `teams: [['p1', 'p2'], ['p3', 'p4']]` — standard doubles
|
|
241
|
+
* - `teams: [['p1'], ['p2']]` — singles
|
|
242
|
+
* - `teams: [['p1'], ['p2'], ['p3']]` — 3-way round robin
|
|
243
|
+
*
|
|
244
|
+
* Scores in each {@link GameInput} are parallel to the `teams` order.
|
|
245
|
+
*
|
|
246
|
+
* @category Matches
|
|
122
247
|
*/
|
|
123
248
|
interface MatchInput {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
/** Location (optional) */
|
|
141
|
-
location?: string;
|
|
142
|
-
/** Unique identifier (auto-generated if not provided) */
|
|
143
|
-
identifier?: string;
|
|
249
|
+
readonly identifier: string;
|
|
250
|
+
readonly teams: readonly (readonly string[])[];
|
|
251
|
+
readonly games: readonly GameInput[];
|
|
252
|
+
readonly sport?: string;
|
|
253
|
+
readonly bracket?: string;
|
|
254
|
+
readonly event?: string;
|
|
255
|
+
readonly location?: string;
|
|
256
|
+
readonly matchDate?: string;
|
|
257
|
+
readonly matchSource?: string;
|
|
258
|
+
readonly matchType?: string;
|
|
259
|
+
readonly winScore?: number;
|
|
260
|
+
readonly winBy?: number;
|
|
261
|
+
readonly extras?: Readonly<Record<string, unknown>>;
|
|
262
|
+
readonly originalId?: string;
|
|
263
|
+
readonly originalType?: string;
|
|
264
|
+
readonly clubId?: number;
|
|
144
265
|
}
|
|
145
266
|
/**
|
|
146
|
-
*
|
|
267
|
+
* Compressed bulk match submission.
|
|
147
268
|
*
|
|
148
|
-
*
|
|
269
|
+
* Top-level fields are defaults applied to every match in the
|
|
270
|
+
* {@link matches} list. Any match can override any field. `sport`,
|
|
271
|
+
* `winScore`, and `winBy` are **required** at the batch level — partners
|
|
272
|
+
* must tell the rater which sport the matches are in and what the
|
|
273
|
+
* winning conditions were so scores can be interpreted correctly.
|
|
274
|
+
*
|
|
275
|
+
* @category Matches
|
|
149
276
|
*/
|
|
150
|
-
interface
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
277
|
+
interface MatchBatch {
|
|
278
|
+
readonly sport: string;
|
|
279
|
+
readonly winScore: number;
|
|
280
|
+
readonly winBy: number;
|
|
281
|
+
readonly matches: readonly MatchInput[];
|
|
282
|
+
readonly bracket?: string;
|
|
283
|
+
readonly event?: string;
|
|
284
|
+
readonly location?: string;
|
|
285
|
+
readonly matchDate?: string;
|
|
286
|
+
readonly matchSource?: string;
|
|
287
|
+
readonly matchType?: string;
|
|
288
|
+
readonly extras?: Readonly<Record<string, unknown>>;
|
|
289
|
+
readonly identifier?: string;
|
|
290
|
+
readonly originalId?: string;
|
|
291
|
+
readonly originalType?: string;
|
|
292
|
+
readonly clubId?: number;
|
|
293
|
+
readonly dryRun?: boolean;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Raw result from a batch submission.
|
|
297
|
+
*
|
|
298
|
+
* @category Matches
|
|
299
|
+
*/
|
|
300
|
+
interface MatchBatchResultWire {
|
|
301
|
+
readonly success: boolean;
|
|
302
|
+
readonly numMatches: number;
|
|
303
|
+
readonly numGames: number;
|
|
304
|
+
readonly dryRun?: boolean;
|
|
305
|
+
readonly message?: string;
|
|
306
|
+
readonly errors?: readonly string[];
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Filters for {@link LeaderboardResource.list}.
|
|
310
|
+
*
|
|
311
|
+
* @category Leaderboards
|
|
312
|
+
*/
|
|
313
|
+
interface LeaderboardOptions {
|
|
314
|
+
readonly category?: string;
|
|
315
|
+
readonly ageBracket?: string;
|
|
316
|
+
readonly scope?: string;
|
|
317
|
+
readonly state?: string;
|
|
318
|
+
readonly city?: string;
|
|
319
|
+
readonly clubId?: string;
|
|
320
|
+
readonly gender?: Gender | Lowercase<Gender>;
|
|
321
|
+
readonly verifiedOnly?: boolean;
|
|
322
|
+
readonly minGames?: number;
|
|
323
|
+
readonly limit?: number;
|
|
324
|
+
readonly offset?: number;
|
|
325
|
+
readonly search?: string;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Options for {@link LeaderboardResource.rank}.
|
|
329
|
+
*
|
|
330
|
+
* @category Leaderboards
|
|
331
|
+
*/
|
|
332
|
+
interface PlayerRankOptions {
|
|
333
|
+
readonly category?: string;
|
|
334
|
+
readonly ageBracket?: string;
|
|
335
|
+
readonly scope?: string;
|
|
336
|
+
readonly state?: string;
|
|
337
|
+
readonly city?: string;
|
|
338
|
+
readonly clubId?: string;
|
|
339
|
+
/** Number of players on either side of the target. Default 5. */
|
|
340
|
+
readonly contextSize?: number;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Error envelope commonly returned by the Partner API on non-2xx status.
|
|
344
|
+
*
|
|
345
|
+
* @category Errors
|
|
346
|
+
*/
|
|
347
|
+
interface ApiErrorResponse {
|
|
348
|
+
readonly message?: string;
|
|
349
|
+
readonly error?: string;
|
|
350
|
+
readonly statusCode?: number;
|
|
221
351
|
}
|
|
222
352
|
|
|
223
353
|
/**
|
|
224
|
-
*
|
|
354
|
+
* {@link LeaderboardResource} — read-only leaderboard queries.
|
|
225
355
|
*
|
|
226
|
-
*
|
|
356
|
+
* @module
|
|
357
|
+
*/
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Read-only leaderboard queries.
|
|
361
|
+
*
|
|
362
|
+
* @category Resources
|
|
363
|
+
*/
|
|
364
|
+
declare class LeaderboardResource {
|
|
365
|
+
#private;
|
|
366
|
+
/** @internal */
|
|
367
|
+
constructor(http: HttpTransport);
|
|
368
|
+
/** Fetch a leaderboard page with optional filters. */
|
|
369
|
+
list(options?: LeaderboardOptions): Promise<Record<string, unknown>>;
|
|
370
|
+
/** Fetch a specific player's rank plus nearby players. */
|
|
371
|
+
rank(playerId: string, options?: PlayerRankOptions): Promise<Record<string, unknown>>;
|
|
372
|
+
/** List available leaderboard categories, brackets, and scopes. */
|
|
373
|
+
categories(): Promise<Record<string, unknown>>;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* {@link MatchBatchResult} — result of a batch match submission.
|
|
227
378
|
*
|
|
228
379
|
* @module
|
|
229
380
|
*/
|
|
230
381
|
|
|
231
|
-
/** Union type for player data from different endpoints */
|
|
232
|
-
type PlayerData = MemberData | PlayerSearchData;
|
|
233
382
|
/**
|
|
234
|
-
*
|
|
383
|
+
* Result of a {@link MatchesResource.submit} call.
|
|
235
384
|
*
|
|
236
|
-
* @
|
|
385
|
+
* {@link success} is `true` only when every match in the batch was
|
|
386
|
+
* accepted. Check {@link errors} for per-match validation failures.
|
|
387
|
+
*
|
|
388
|
+
* @category Matches
|
|
237
389
|
*/
|
|
238
|
-
declare class
|
|
239
|
-
|
|
240
|
-
readonly
|
|
241
|
-
|
|
242
|
-
readonly
|
|
243
|
-
|
|
244
|
-
readonly
|
|
245
|
-
constructor(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
* Access ratings by category name or use convenience properties.
|
|
251
|
-
*
|
|
252
|
-
* @category Models
|
|
253
|
-
*/
|
|
254
|
-
declare class RatingSplits {
|
|
255
|
-
/** Map of category names to rating splits */
|
|
256
|
-
readonly splits: Map<string, RatingSplit>;
|
|
257
|
-
constructor(data?: RatingSplitsData);
|
|
258
|
-
/** Get rating for a category */
|
|
259
|
-
get(category: string): number | undefined;
|
|
260
|
-
/** Open division rating */
|
|
261
|
-
get open(): number | undefined;
|
|
262
|
-
/** Gender-specific rating (same gender doubles) */
|
|
263
|
-
get gender(): number | undefined;
|
|
264
|
-
/** Mixed doubles rating */
|
|
265
|
-
get mixed(): number | undefined;
|
|
266
|
-
/** Recreational rating */
|
|
267
|
-
get recreational(): number | undefined;
|
|
268
|
-
/** Singles rating */
|
|
269
|
-
get singles(): number | undefined;
|
|
270
|
-
/** Best available verified rating */
|
|
271
|
-
get best(): number | undefined;
|
|
272
|
-
/** Convert to plain object */
|
|
273
|
-
toJSON(): Record<string, {
|
|
274
|
-
rating: number;
|
|
275
|
-
abbr: string;
|
|
276
|
-
}>;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* A player in the Vairified system.
|
|
280
|
-
*
|
|
281
|
-
* From public search, only limited data is available (display name, location, rating).
|
|
282
|
-
* For full profile data, use getMember() with OAuth consent.
|
|
283
|
-
*
|
|
284
|
-
* @category Models
|
|
285
|
-
*/
|
|
286
|
-
declare class Player {
|
|
287
|
-
/** External player ID (vair_mem_xxx format) */
|
|
288
|
-
readonly id: string;
|
|
289
|
-
/** Display name (First Name + Last Initial from search) */
|
|
290
|
-
readonly displayName?: string;
|
|
291
|
-
/** First name (only from connected member) */
|
|
292
|
-
readonly firstName?: string;
|
|
293
|
-
/** Last name (only from connected member) */
|
|
294
|
-
readonly lastName?: string;
|
|
295
|
-
/** Primary/overall rating (2.0-8.0) */
|
|
296
|
-
readonly rating: number;
|
|
297
|
-
/** Whether player is verified */
|
|
298
|
-
readonly isVairified: boolean;
|
|
299
|
-
/** Whether player has connected to your app */
|
|
300
|
-
readonly isConnected: boolean;
|
|
301
|
-
/** Ratings by category (only from connected member) */
|
|
302
|
-
readonly ratingSplits: RatingSplits;
|
|
303
|
-
/** City */
|
|
304
|
-
readonly city?: string;
|
|
305
|
-
/** State code */
|
|
306
|
-
readonly state?: string;
|
|
307
|
-
/** Country code */
|
|
308
|
-
readonly country?: string;
|
|
309
|
-
protected _client?: Vairified;
|
|
310
|
-
constructor(data: PlayerData, client?: Vairified);
|
|
311
|
-
/** Full name (or display name if full name not available) */
|
|
312
|
-
get name(): string;
|
|
313
|
-
/** Best verified rating */
|
|
314
|
-
get verifiedRating(): number | undefined;
|
|
390
|
+
declare class MatchBatchResult {
|
|
391
|
+
readonly success: boolean;
|
|
392
|
+
readonly numMatches: number;
|
|
393
|
+
readonly numGames: number;
|
|
394
|
+
readonly dryRun: boolean | null;
|
|
395
|
+
readonly message: string | null;
|
|
396
|
+
readonly errors: readonly string[] | null;
|
|
397
|
+
constructor(wire: MatchBatchResultWire);
|
|
398
|
+
/** Shorthand: successful submission with zero errors. */
|
|
399
|
+
get ok(): boolean;
|
|
400
|
+
/** Whether this was a dry-run (validation only, nothing persisted). */
|
|
401
|
+
get isDryRun(): boolean;
|
|
315
402
|
toString(): string;
|
|
316
403
|
}
|
|
404
|
+
|
|
317
405
|
/**
|
|
318
|
-
*
|
|
406
|
+
* {@link MatchesResource} — bulk match submission.
|
|
319
407
|
*
|
|
320
|
-
*
|
|
408
|
+
* @module
|
|
409
|
+
*/
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Match submission — one call submits a full batch.
|
|
321
413
|
*
|
|
322
|
-
* @category
|
|
414
|
+
* @category Resources
|
|
323
415
|
*/
|
|
324
|
-
declare class
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
416
|
+
declare class MatchesResource {
|
|
417
|
+
#private;
|
|
418
|
+
/** @internal */
|
|
419
|
+
constructor(http: HttpTransport);
|
|
420
|
+
/**
|
|
421
|
+
* Submit a {@link MatchBatch} for rating calculation.
|
|
422
|
+
*
|
|
423
|
+
* All players in every match must have granted the `match:submit`
|
|
424
|
+
* scope via OAuth (unless your API key has the
|
|
425
|
+
* `match:submit:trusted` scope, which skips per-player consent).
|
|
426
|
+
*
|
|
427
|
+
* Set `batch.dryRun = true` to validate without persisting.
|
|
428
|
+
*
|
|
429
|
+
* ```ts
|
|
430
|
+
* const result = await client.matches.submit({
|
|
431
|
+
* sport: 'pickleball',
|
|
432
|
+
* winScore: 11,
|
|
433
|
+
* winBy: 2,
|
|
434
|
+
* bracket: '4.0 Doubles',
|
|
435
|
+
* event: 'Weekly League',
|
|
436
|
+
* matchDate: '2026-04-11T14:00:00Z',
|
|
437
|
+
* matches: [
|
|
438
|
+
* {
|
|
439
|
+
* identifier: 'm1',
|
|
440
|
+
* teams: [['vair_mem_aaa', 'vair_mem_bbb'],
|
|
441
|
+
* ['vair_mem_ccc', 'vair_mem_ddd']],
|
|
442
|
+
* games: [{ scores: [11, 8] }, { scores: [11, 5] }],
|
|
443
|
+
* },
|
|
444
|
+
* ],
|
|
445
|
+
* });
|
|
446
|
+
* if (result.ok) {
|
|
447
|
+
* console.log(`Submitted ${result.numGames} games`);
|
|
448
|
+
* }
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
submit(batch: MatchBatch): Promise<MatchBatchResult>;
|
|
452
|
+
/** Send a test payload to a webhook URL. */
|
|
453
|
+
testWebhook(webhookUrl: string): Promise<Record<string, unknown>>;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* {@link SportRating} — a player's ratings for one sport.
|
|
458
|
+
*
|
|
459
|
+
* @module
|
|
460
|
+
*/
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* A player's ratings for a single sport.
|
|
464
|
+
*
|
|
465
|
+
* The top-level `rating` / `abbr` is the primary rating for that sport
|
|
466
|
+
* (conventionally the overall-open bracket). Every category × age
|
|
467
|
+
* bracket the player has played is also available via {@link get},
|
|
468
|
+
* {@link has}, subscript-style access, and iteration.
|
|
469
|
+
*
|
|
470
|
+
* ```ts
|
|
471
|
+
* const pb = member.sport.get('pickleball');
|
|
472
|
+
* if (pb) {
|
|
473
|
+
* console.log(pb.rating, pb.abbr); // 3.915 VO
|
|
474
|
+
* console.log(pb.get('overall-open')?.rating); // 3.915
|
|
475
|
+
* console.log(pb.has('singles-40+')); // false
|
|
476
|
+
* console.log(pb.size); // 3
|
|
477
|
+
* for (const [key, split] of pb) {
|
|
478
|
+
* console.log(key, split.rating);
|
|
479
|
+
* }
|
|
480
|
+
* }
|
|
481
|
+
* ```
|
|
482
|
+
*
|
|
483
|
+
* @category Members
|
|
484
|
+
*/
|
|
485
|
+
declare class SportRating {
|
|
486
|
+
#private;
|
|
487
|
+
/** Primary rating for this sport. */
|
|
488
|
+
readonly rating: number;
|
|
489
|
+
/** Category abbreviation for the primary rating (e.g. `'VO'`). */
|
|
490
|
+
readonly abbr: string;
|
|
491
|
+
constructor(wire: SportRatingWire);
|
|
492
|
+
/**
|
|
493
|
+
* Look up a rating split by key (e.g. `'overall-open'`,
|
|
494
|
+
* `'singles-12-13'`, `'gender-40+'`). Returns `undefined` if the
|
|
495
|
+
* player has no rating for that bracket.
|
|
496
|
+
*/
|
|
497
|
+
get(key: string): RatingSplitWire | undefined;
|
|
498
|
+
/** Whether the player has a rating for the given split key. */
|
|
499
|
+
has(key: string): boolean;
|
|
500
|
+
/** Number of rating splits. */
|
|
501
|
+
get size(): number;
|
|
502
|
+
/** All split keys the player has ratings for. */
|
|
503
|
+
keys(): IterableIterator<string>;
|
|
504
|
+
/** All rating splits the player has. */
|
|
505
|
+
values(): IterableIterator<RatingSplitWire>;
|
|
506
|
+
/** `[key, split]` pairs for every rating split. */
|
|
507
|
+
entries(): IterableIterator<[string, RatingSplitWire]>;
|
|
508
|
+
/**
|
|
509
|
+
* `for (const [key, split] of sportRating) { ... }` — iterate every
|
|
510
|
+
* rating split the player has in this sport.
|
|
511
|
+
*/
|
|
512
|
+
[Symbol.iterator](): IterableIterator<[string, RatingSplitWire]>;
|
|
334
513
|
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* {@link Member} — partner-facing player record.
|
|
517
|
+
*
|
|
518
|
+
* @module
|
|
519
|
+
*/
|
|
520
|
+
|
|
335
521
|
/**
|
|
336
|
-
*
|
|
522
|
+
* Map-like wrapper around a player's sport → {@link SportRating}.
|
|
337
523
|
*
|
|
338
|
-
*
|
|
524
|
+
* Supports `.get(code)`, `.has(code)`, `.size`, and iteration so the
|
|
525
|
+
* shape feels native:
|
|
339
526
|
*
|
|
340
|
-
* @example
|
|
341
527
|
* ```ts
|
|
342
|
-
*
|
|
343
|
-
* const
|
|
344
|
-
* event: 'Weekly League',
|
|
345
|
-
* bracket: '4.0 Doubles',
|
|
346
|
-
* date: new Date(),
|
|
347
|
-
* team1: ['player1_id', 'player2_id'],
|
|
348
|
-
* team2: ['player3_id', 'player4_id'],
|
|
349
|
-
* scores: [[11, 9], [11, 7]],
|
|
350
|
-
* });
|
|
351
|
-
*
|
|
352
|
-
* // Singles match: 11-8, 9-11, 11-6
|
|
353
|
-
* const match = new Match({
|
|
354
|
-
* event: 'Club Singles',
|
|
355
|
-
* bracket: 'Open Singles',
|
|
356
|
-
* date: new Date(),
|
|
357
|
-
* team1: ['player1_id'],
|
|
358
|
-
* team2: ['player2_id'],
|
|
359
|
-
* scores: [[11, 8], [9, 11], [11, 6]],
|
|
360
|
-
* });
|
|
528
|
+
* member.sport.get('pickleball')?.rating
|
|
529
|
+
* for (const [code, rating] of member.sport) { ... }
|
|
361
530
|
* ```
|
|
531
|
+
*
|
|
532
|
+
* @category Members
|
|
362
533
|
*/
|
|
363
|
-
declare class
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
readonly team2: readonly string[];
|
|
374
|
-
/** Game scores */
|
|
375
|
-
readonly scores: readonly [number, number][];
|
|
376
|
-
/** Match type */
|
|
377
|
-
readonly matchType: string;
|
|
378
|
-
/** Match source */
|
|
379
|
-
readonly source: string;
|
|
380
|
-
/** Location */
|
|
381
|
-
readonly location?: string;
|
|
382
|
-
/** Unique identifier */
|
|
383
|
-
readonly identifier: string;
|
|
384
|
-
/** Match ID (set after submission) */
|
|
385
|
-
id?: string;
|
|
386
|
-
constructor(data: MatchInput);
|
|
387
|
-
/** Match format: SINGLES or DOUBLES */
|
|
388
|
-
get format(): 'SINGLES' | 'DOUBLES';
|
|
389
|
-
/** Team that won (1 or 2). Returns 0 if tie. */
|
|
390
|
-
get winner(): 0 | 1 | 2;
|
|
391
|
-
/** Score summary like "11-9, 11-7" */
|
|
392
|
-
get scoreSummary(): string;
|
|
393
|
-
/** Convert to API request format */
|
|
394
|
-
toJSON(): MatchApiData;
|
|
534
|
+
declare class MemberSportMap {
|
|
535
|
+
#private;
|
|
536
|
+
constructor(wire: Readonly<Record<string, SportRatingWire>> | undefined);
|
|
537
|
+
get(sport: string): SportRating | undefined;
|
|
538
|
+
has(sport: string): boolean;
|
|
539
|
+
get size(): number;
|
|
540
|
+
keys(): IterableIterator<string>;
|
|
541
|
+
values(): IterableIterator<SportRating>;
|
|
542
|
+
entries(): IterableIterator<[string, SportRating]>;
|
|
543
|
+
[Symbol.iterator](): IterableIterator<[string, SportRating]>;
|
|
395
544
|
}
|
|
396
545
|
/**
|
|
397
|
-
*
|
|
546
|
+
* A partner-facing player record.
|
|
398
547
|
*
|
|
399
|
-
* @
|
|
548
|
+
* Returned by {@link MembersResource.get} (full detail, requires an
|
|
549
|
+
* active OAuth connection) and {@link MembersResource.search} (limited
|
|
550
|
+
* detail for public search).
|
|
551
|
+
*
|
|
552
|
+
* Rating data lives under {@link sport} — keyed by sport code. The
|
|
553
|
+
* backend returns only the sports the player has ratings in, or only
|
|
554
|
+
* the sports requested via the `sport=` query filter. Use
|
|
555
|
+
* {@link ratingFor} to fetch the primary rating for a specific sport
|
|
556
|
+
* with a sensible default.
|
|
557
|
+
*
|
|
558
|
+
* @category Members
|
|
400
559
|
*/
|
|
401
|
-
declare class
|
|
402
|
-
|
|
403
|
-
readonly
|
|
404
|
-
|
|
405
|
-
readonly
|
|
406
|
-
|
|
407
|
-
readonly
|
|
408
|
-
|
|
409
|
-
readonly
|
|
410
|
-
|
|
411
|
-
readonly
|
|
412
|
-
|
|
413
|
-
readonly
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
560
|
+
declare class Member {
|
|
561
|
+
readonly memberId: number;
|
|
562
|
+
readonly id: string | null;
|
|
563
|
+
readonly firstName: string;
|
|
564
|
+
readonly lastName: string;
|
|
565
|
+
readonly fullName: string;
|
|
566
|
+
readonly displayName: string;
|
|
567
|
+
readonly age: number | null;
|
|
568
|
+
readonly city: string | null;
|
|
569
|
+
readonly state: string | null;
|
|
570
|
+
readonly zip: string | null;
|
|
571
|
+
readonly country: string | null;
|
|
572
|
+
readonly gender: Gender | null;
|
|
573
|
+
readonly status: MemberStatusWire;
|
|
574
|
+
readonly sport: MemberSportMap;
|
|
575
|
+
readonly activeLeagues: readonly string[] | null;
|
|
576
|
+
readonly email: string | null;
|
|
577
|
+
readonly grantedScopes: readonly string[] | null;
|
|
578
|
+
constructor(wire: PartnerMemberWire);
|
|
579
|
+
/** Full name — alias for {@link fullName}, matching common usage. */
|
|
580
|
+
get name(): string;
|
|
581
|
+
/** The list of sport codes this player has ratings in. */
|
|
582
|
+
get sports(): readonly string[];
|
|
583
|
+
/**
|
|
584
|
+
* Primary rating for a given sport.
|
|
585
|
+
*
|
|
586
|
+
* @param sport Sport code — defaults to `'pickleball'`.
|
|
587
|
+
* @returns The primary rating value, or `null` if the player has no
|
|
588
|
+
* ratings for that sport.
|
|
589
|
+
*/
|
|
590
|
+
ratingFor(sport?: string): number | null;
|
|
591
|
+
/**
|
|
592
|
+
* Get a specific rating split for a sport.
|
|
593
|
+
*
|
|
594
|
+
* @param key Split key (e.g. `'overall-open'`).
|
|
595
|
+
* @param sport Sport code — defaults to `'pickleball'`.
|
|
596
|
+
*/
|
|
597
|
+
split(key: string, sport?: string): RatingSplitWire | null;
|
|
598
|
+
/** Compact summary for console output. */
|
|
599
|
+
toString(): string;
|
|
419
600
|
}
|
|
601
|
+
|
|
420
602
|
/**
|
|
421
|
-
*
|
|
603
|
+
* {@link RatingUpdate} — a single rating change notification.
|
|
422
604
|
*
|
|
423
|
-
* @
|
|
605
|
+
* @module
|
|
606
|
+
*/
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* A single rating change notification.
|
|
610
|
+
*
|
|
611
|
+
* Returned by {@link MembersResource.ratingUpdates} (polling) and
|
|
612
|
+
* delivered via webhook callbacks to partners that have registered a
|
|
613
|
+
* webhook URL and have subscribers.
|
|
614
|
+
*
|
|
615
|
+
* @category Members
|
|
424
616
|
*/
|
|
425
617
|
declare class RatingUpdate {
|
|
426
|
-
|
|
427
|
-
readonly id: string;
|
|
428
|
-
|
|
429
|
-
readonly
|
|
430
|
-
|
|
431
|
-
readonly
|
|
432
|
-
|
|
433
|
-
readonly
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
get change(): number;
|
|
442
|
-
/** Whether rating improved */
|
|
618
|
+
readonly memberId: number;
|
|
619
|
+
readonly id: string | null;
|
|
620
|
+
readonly displayName: string | null;
|
|
621
|
+
readonly sport: string | null;
|
|
622
|
+
readonly previousRating: number | null;
|
|
623
|
+
readonly newRating: number | null;
|
|
624
|
+
readonly changedAt: string | null;
|
|
625
|
+
readonly ratingSplits: Readonly<Record<string, RatingSplitWire>> | null;
|
|
626
|
+
constructor(wire: PartnerRatingUpdateWire);
|
|
627
|
+
/**
|
|
628
|
+
* Rating change amount — `newRating - previousRating`. Returns `null`
|
|
629
|
+
* if either rating is missing from the update payload.
|
|
630
|
+
*/
|
|
631
|
+
get delta(): number | null;
|
|
632
|
+
/** `true` when the new rating is strictly higher than the previous. */
|
|
443
633
|
get improved(): boolean;
|
|
444
|
-
/** Fetch the member associated with this update */
|
|
445
|
-
getMember(): Promise<Member>;
|
|
446
634
|
toString(): string;
|
|
447
635
|
}
|
|
636
|
+
|
|
448
637
|
/**
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
* @
|
|
452
|
-
*/
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
638
|
+
* {@link MembersResource} — member lookups, search, and rating updates.
|
|
639
|
+
*
|
|
640
|
+
* @module
|
|
641
|
+
*/
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Member operations — get a single member, auto-paginating search,
|
|
645
|
+
* find by name, and polling for rating change notifications.
|
|
646
|
+
*
|
|
647
|
+
* @category Resources
|
|
648
|
+
*/
|
|
649
|
+
declare class MembersResource {
|
|
650
|
+
#private;
|
|
651
|
+
/** @internal */
|
|
652
|
+
constructor(http: HttpTransport);
|
|
653
|
+
/**
|
|
654
|
+
* Get a connected member by external ID.
|
|
655
|
+
*
|
|
656
|
+
* **Requires an active OAuth connection** between your partner app
|
|
657
|
+
* and the player. Use the OAuth flow on `client.oauth` first.
|
|
658
|
+
*
|
|
659
|
+
* @param playerId External player ID in `vair_mem_xxx` format.
|
|
660
|
+
* @param options.sport Optional sport filter — single code or list.
|
|
661
|
+
* When omitted, the response contains every sport the player has
|
|
662
|
+
* ratings in.
|
|
663
|
+
* @throws {@link NotFoundError} if the external ID is unknown.
|
|
664
|
+
* @throws {@link VairifiedError} if the player has not connected to
|
|
665
|
+
* your app (403) or the request otherwise fails.
|
|
666
|
+
*
|
|
667
|
+
* @example
|
|
668
|
+
* ```ts
|
|
669
|
+
* const member = await client.members.get('vair_mem_xxx');
|
|
670
|
+
* console.log(member.name, member.ratingFor('pickleball'));
|
|
671
|
+
*
|
|
672
|
+
* // Just pickleball
|
|
673
|
+
* const member2 = await client.members.get('vair_mem_xxx', { sport: 'pickleball' });
|
|
674
|
+
*
|
|
675
|
+
* // Multiple sports
|
|
676
|
+
* const member3 = await client.members.get('vair_mem_xxx', {
|
|
677
|
+
* sport: ['pickleball', 'padel'],
|
|
678
|
+
* });
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
get(playerId: string, options?: {
|
|
682
|
+
sport?: string | readonly string[];
|
|
683
|
+
}): Promise<Member>;
|
|
684
|
+
/**
|
|
685
|
+
* Search for members, yielding each match as a {@link Member}.
|
|
686
|
+
*
|
|
687
|
+
* This is an **auto-paginating async iterator** — it fetches pages
|
|
688
|
+
* from the server lazily as you iterate, so you can stream through
|
|
689
|
+
* thousands of results without holding them all in memory:
|
|
690
|
+
*
|
|
691
|
+
* ```ts
|
|
692
|
+
* for await (const m of client.members.search({ city: 'Austin' })) {
|
|
693
|
+
* console.log(m.name, m.ratingFor('pickleball'));
|
|
694
|
+
* }
|
|
695
|
+
* ```
|
|
696
|
+
*
|
|
697
|
+
* Stop early by `break`-ing out of the loop, or cap the total with
|
|
698
|
+
* `maxResults`.
|
|
699
|
+
*/
|
|
700
|
+
search(filters?: SearchFilters): AsyncGenerator<Member, void, void>;
|
|
701
|
+
/**
|
|
702
|
+
* Return the first search hit for a name, or `null`.
|
|
703
|
+
*
|
|
704
|
+
* Convenience for the common "look up by name" case:
|
|
705
|
+
*
|
|
706
|
+
* ```ts
|
|
707
|
+
* const mike = await client.members.find('Mike Barker');
|
|
708
|
+
* if (mike) {
|
|
709
|
+
* console.log(mike.ratingFor('pickleball'));
|
|
710
|
+
* }
|
|
711
|
+
* ```
|
|
712
|
+
*/
|
|
713
|
+
find(name: string): Promise<Member | null>;
|
|
714
|
+
/**
|
|
715
|
+
* Poll for rating change notifications.
|
|
716
|
+
*
|
|
717
|
+
* Returns a list of {@link RatingUpdate} objects for every player
|
|
718
|
+
* whose rating has changed since the last poll. Members are
|
|
719
|
+
* considered subscribed when they have an active OAuth connection
|
|
720
|
+
* with the `webhook:subscribe` scope.
|
|
721
|
+
*/
|
|
722
|
+
ratingUpdates(): Promise<readonly RatingUpdate[]>;
|
|
477
723
|
}
|
|
478
724
|
|
|
479
725
|
/**
|
|
480
|
-
* Vairified OAuth
|
|
726
|
+
* Vairified OAuth helpers and type definitions.
|
|
481
727
|
*
|
|
482
|
-
*
|
|
728
|
+
* Use the {@link OAuthResource} on `client.oauth` for the full flow —
|
|
729
|
+
* these helpers exist for partners who need to build authorization URLs
|
|
730
|
+
* or validate scopes outside the client (e.g. in a frontend that only
|
|
731
|
+
* handles the redirect step).
|
|
483
732
|
*
|
|
484
733
|
* @module
|
|
485
734
|
*/
|
|
486
735
|
/**
|
|
487
|
-
*
|
|
736
|
+
* Every OAuth scope the Vairified authorization server accepts.
|
|
737
|
+
*
|
|
738
|
+
* Declaring this as a string union (rather than a free-form `string`)
|
|
739
|
+
* lets TypeScript catch typos at authoring time:
|
|
740
|
+
*
|
|
741
|
+
* ```ts
|
|
742
|
+
* const scopes: OAuthScope[] = ['profile:read', 'rating:read']; // ok
|
|
743
|
+
* const bad: OAuthScope[] = ['profile:read', 'rating']; // type error
|
|
744
|
+
* ```
|
|
488
745
|
*
|
|
489
746
|
* @category OAuth
|
|
490
747
|
*/
|
|
491
|
-
|
|
492
|
-
readonly 'profile:read': "Access your name, location, and verification status";
|
|
493
|
-
readonly 'profile:email': "Access your email address";
|
|
494
|
-
readonly 'rating:read': "View your current rating and rating splits";
|
|
495
|
-
readonly 'rating:history': "View your complete rating history";
|
|
496
|
-
readonly 'match:submit': "Submit match results on your behalf";
|
|
497
|
-
readonly 'webhook:subscribe': "Receive notifications when your rating changes";
|
|
498
|
-
};
|
|
748
|
+
type OAuthScope = 'profile:read' | 'profile:email' | 'rating:read' | 'rating:history' | 'match:submit' | 'webhook:subscribe';
|
|
499
749
|
/**
|
|
500
|
-
*
|
|
750
|
+
* Human-readable description for every OAuth scope.
|
|
501
751
|
*
|
|
502
752
|
* @category OAuth
|
|
503
753
|
*/
|
|
504
|
-
|
|
754
|
+
declare const SCOPES: Readonly<Record<OAuthScope, string>>;
|
|
505
755
|
/**
|
|
506
|
-
*
|
|
756
|
+
* The scopes automatically requested when none are specified.
|
|
507
757
|
*
|
|
508
758
|
* @category OAuth
|
|
509
759
|
*/
|
|
510
|
-
declare const DEFAULT_SCOPES: OAuthScope[];
|
|
760
|
+
declare const DEFAULT_SCOPES: readonly OAuthScope[];
|
|
511
761
|
/**
|
|
512
|
-
*
|
|
762
|
+
* Configuration for building an authorization URL manually.
|
|
513
763
|
*
|
|
514
764
|
* @category OAuth
|
|
515
765
|
*/
|
|
516
766
|
interface OAuthConfig {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
redirectUri: string;
|
|
521
|
-
/** Vairified API base URL */
|
|
522
|
-
baseUrl?: string;
|
|
767
|
+
readonly apiKey: string;
|
|
768
|
+
readonly redirectUri: string;
|
|
769
|
+
readonly baseUrl?: string;
|
|
523
770
|
}
|
|
524
771
|
/**
|
|
525
|
-
* Response from starting an OAuth authorization.
|
|
772
|
+
* Response from starting an OAuth authorization flow.
|
|
526
773
|
*
|
|
527
774
|
* @category OAuth
|
|
528
775
|
*/
|
|
529
776
|
interface AuthorizationResponse {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
code: string;
|
|
534
|
-
/** CSRF state parameter */
|
|
535
|
-
state?: string;
|
|
777
|
+
readonly authorizationUrl: string;
|
|
778
|
+
readonly code: string;
|
|
779
|
+
readonly state?: string;
|
|
536
780
|
}
|
|
537
781
|
/**
|
|
538
782
|
* Response from exchanging an authorization code for tokens.
|
|
@@ -540,443 +784,236 @@ interface AuthorizationResponse {
|
|
|
540
784
|
* @category OAuth
|
|
541
785
|
*/
|
|
542
786
|
interface TokenResponse {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
expiresIn: number;
|
|
549
|
-
/** Granted scopes */
|
|
550
|
-
scope: string[];
|
|
551
|
-
/** Connected player's external ID */
|
|
552
|
-
playerId: string;
|
|
787
|
+
readonly accessToken: string;
|
|
788
|
+
readonly refreshToken: string | null;
|
|
789
|
+
readonly expiresIn: number;
|
|
790
|
+
readonly scope: readonly string[];
|
|
791
|
+
readonly playerId: string;
|
|
553
792
|
}
|
|
554
793
|
/**
|
|
555
794
|
* Build the URL to redirect users to for OAuth authorization.
|
|
556
795
|
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
* @param config - OAuth configuration
|
|
561
|
-
* @param scopes - Permission scopes to request
|
|
562
|
-
* @param state - CSRF protection state parameter
|
|
563
|
-
* @returns URL to redirect the user to
|
|
564
|
-
*
|
|
565
|
-
* @example
|
|
566
|
-
* ```ts
|
|
567
|
-
* const url = getAuthorizationUrl(
|
|
568
|
-
* {
|
|
569
|
-
* apiKey: 'vair_pk_xxx',
|
|
570
|
-
* redirectUri: 'https://myapp.com/oauth/callback',
|
|
571
|
-
* },
|
|
572
|
-
* ['profile:read', 'rating:read'],
|
|
573
|
-
* );
|
|
574
|
-
* // Redirect user to this URL
|
|
575
|
-
* window.location.href = url;
|
|
576
|
-
* ```
|
|
796
|
+
* Prefer {@link OAuthResource.authorize} on a Vairified client — this
|
|
797
|
+
* helper is only useful when you need to construct the URL without
|
|
798
|
+
* making an HTTP call first (for example, in a pure-frontend handoff).
|
|
577
799
|
*
|
|
578
800
|
* @category OAuth
|
|
579
801
|
*/
|
|
580
|
-
declare function getAuthorizationUrl(config: OAuthConfig,
|
|
802
|
+
declare function getAuthorizationUrl(config: OAuthConfig, options?: {
|
|
803
|
+
scopes?: readonly OAuthScope[];
|
|
804
|
+
state?: string;
|
|
805
|
+
}): string;
|
|
581
806
|
/**
|
|
582
|
-
* Check
|
|
583
|
-
*
|
|
584
|
-
* @param scope - Scope string to validate
|
|
585
|
-
* @returns True if scope is valid
|
|
807
|
+
* Check whether a scope string is one the Vairified server accepts.
|
|
586
808
|
*
|
|
587
809
|
* @category OAuth
|
|
588
810
|
*/
|
|
589
811
|
declare function validateScope(scope: string): scope is OAuthScope;
|
|
590
812
|
/**
|
|
591
|
-
* Get a human-readable description of
|
|
813
|
+
* Get a human-readable description of an OAuth scope.
|
|
592
814
|
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
815
|
+
* Returns `"Unknown scope: {scope}"` for unrecognized scopes so this
|
|
816
|
+
* function is safe to call on user-supplied input.
|
|
595
817
|
*
|
|
596
818
|
* @category OAuth
|
|
597
819
|
*/
|
|
598
|
-
declare function describeScope(scope:
|
|
820
|
+
declare function describeScope(scope: string): string;
|
|
599
821
|
/**
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
* @param scopes - List of scope strings
|
|
603
|
-
* @returns Array of objects with scope and description
|
|
822
|
+
* Describe multiple scopes at once.
|
|
604
823
|
*
|
|
605
824
|
* @category OAuth
|
|
606
825
|
*/
|
|
607
|
-
declare function describeScopes(scopes:
|
|
608
|
-
scope:
|
|
826
|
+
declare function describeScopes(scopes: readonly string[]): readonly {
|
|
827
|
+
scope: string;
|
|
609
828
|
description: string;
|
|
610
|
-
}
|
|
829
|
+
}[];
|
|
611
830
|
/**
|
|
612
|
-
* Generate a random state
|
|
831
|
+
* Generate a cryptographically-random CSRF state token suitable for
|
|
832
|
+
* use with {@link OAuthResource.authorize}.
|
|
613
833
|
*
|
|
614
|
-
*
|
|
834
|
+
* Uses the Web Crypto API (available in Node 19+ and all modern
|
|
835
|
+
* browsers). The returned string is URL-safe base64 of 32 random bytes.
|
|
615
836
|
*
|
|
616
837
|
* @category OAuth
|
|
617
838
|
*/
|
|
618
839
|
declare function generateState(): string;
|
|
619
840
|
|
|
620
841
|
/**
|
|
621
|
-
*
|
|
842
|
+
* {@link OAuthResource} — OAuth 2.0 flow for player consent.
|
|
622
843
|
*
|
|
623
|
-
*
|
|
844
|
+
* @module
|
|
845
|
+
*/
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* OAuth 2.0 flow for obtaining player consent.
|
|
849
|
+
*
|
|
850
|
+
* Typical flow:
|
|
851
|
+
*
|
|
852
|
+
* 1. {@link authorize} — start an authorization, get a URL to redirect
|
|
853
|
+
* the player to.
|
|
854
|
+
* 2. Player approves on the Vairified site and is redirected back to
|
|
855
|
+
* your `redirectUri` with a `code` query parameter.
|
|
856
|
+
* 3. {@link exchangeToken} — swap the code for access and refresh
|
|
857
|
+
* tokens plus the player's external ID.
|
|
858
|
+
* 4. Store the refresh token and call {@link refresh} when the access
|
|
859
|
+
* token expires.
|
|
860
|
+
* 5. {@link revoke} — disconnect a player from your app.
|
|
861
|
+
*
|
|
862
|
+
* @category Resources
|
|
863
|
+
*/
|
|
864
|
+
declare class OAuthResource {
|
|
865
|
+
#private;
|
|
866
|
+
/** @internal */
|
|
867
|
+
constructor(http: HttpTransport);
|
|
868
|
+
/**
|
|
869
|
+
* Start an OAuth authorization flow.
|
|
870
|
+
*
|
|
871
|
+
* @throws {@link OAuthError} with `errorCode: 'invalid_scope'` if a
|
|
872
|
+
* requested scope is not in the accepted list.
|
|
873
|
+
*/
|
|
874
|
+
authorize(options: {
|
|
875
|
+
redirectUri: string;
|
|
876
|
+
scopes?: readonly OAuthScope[];
|
|
877
|
+
state?: string;
|
|
878
|
+
}): Promise<AuthorizationResponse>;
|
|
879
|
+
/** Exchange an authorization code for access and refresh tokens. */
|
|
880
|
+
exchangeToken(options: {
|
|
881
|
+
code: string;
|
|
882
|
+
redirectUri: string;
|
|
883
|
+
}): Promise<TokenResponse>;
|
|
884
|
+
/** Refresh an expired access token using a refresh token. */
|
|
885
|
+
refresh(refreshToken: string): Promise<TokenResponse>;
|
|
886
|
+
/** Revoke a player's OAuth connection to your app. */
|
|
887
|
+
revoke(playerId: string): Promise<Record<string, unknown>>;
|
|
888
|
+
/** Return the list of OAuth scopes the server currently supports. */
|
|
889
|
+
availableScopes(): Promise<readonly {
|
|
890
|
+
name: string;
|
|
891
|
+
description: string;
|
|
892
|
+
}[]>;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* {@link Vairified} — the main entry point of the SDK.
|
|
624
897
|
*
|
|
625
898
|
* @module
|
|
626
899
|
*/
|
|
627
900
|
|
|
628
|
-
declare const ENVIRONMENTS: {
|
|
629
|
-
readonly production: "https://api-next.vairified.com/api/v1";
|
|
630
|
-
readonly staging: "https://api-staging.vairified.com/api/v1";
|
|
631
|
-
readonly local: "http://localhost:3001/api/v1";
|
|
632
|
-
};
|
|
633
901
|
/**
|
|
634
|
-
*
|
|
902
|
+
* Environment preset → base URL mapping.
|
|
903
|
+
*
|
|
904
|
+
* Partners can switch between production, staging, and local development
|
|
905
|
+
* without memorizing hostnames.
|
|
635
906
|
*
|
|
636
907
|
* @category Client
|
|
637
908
|
*/
|
|
638
|
-
|
|
909
|
+
declare const ENVIRONMENTS: Readonly<Record<VairifiedEnvironment, string>>;
|
|
639
910
|
/**
|
|
640
|
-
*
|
|
911
|
+
* Async client for the Vairified Partner API.
|
|
641
912
|
*
|
|
642
|
-
*
|
|
913
|
+
* The client is organized around sub-resources that mirror the REST
|
|
914
|
+
* structure — {@link members}, {@link matches}, {@link oauth},
|
|
915
|
+
* {@link leaderboard}. Each sub-resource is a thin wrapper around the
|
|
916
|
+
* HTTP transport on this object.
|
|
643
917
|
*
|
|
644
|
-
*
|
|
645
|
-
* ```ts
|
|
646
|
-
* const client = new Vairified({ apiKey: 'vair_pk_xxx' });
|
|
918
|
+
* ## Lifecycle
|
|
647
919
|
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
920
|
+
* The client holds no persistent connections itself — it's safe to
|
|
921
|
+
* create one per request if you want. But for typical usage, wrap it
|
|
922
|
+
* in `await using` so resources are cleaned up deterministically:
|
|
651
923
|
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
924
|
+
* ```ts
|
|
925
|
+
* await using client = new Vairified({ apiKey: 'vair_pk_xxx' });
|
|
926
|
+
*
|
|
927
|
+
* const member = await client.members.get('vair_mem_xxx');
|
|
928
|
+
* console.log(member.name, member.ratingFor('pickleball'));
|
|
657
929
|
*
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
* event: 'Weekly League',
|
|
661
|
-
* bracket: '4.0 Doubles',
|
|
662
|
-
* date: new Date(),
|
|
663
|
-
* team1: ['p1', 'p2'],
|
|
664
|
-
* team2: ['p3', 'p4'],
|
|
665
|
-
* scores: [[11, 9], [11, 7]],
|
|
666
|
-
* });
|
|
667
|
-
* const result = await client.submitMatch(match);
|
|
668
|
-
* if (result.ok) {
|
|
669
|
-
* console.log(`Submitted ${result.numGames} games`);
|
|
930
|
+
* for await (const m of client.members.search({ city: 'Austin' })) {
|
|
931
|
+
* console.log(m.name);
|
|
670
932
|
* }
|
|
671
933
|
* ```
|
|
672
934
|
*
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
*
|
|
935
|
+
* `await using` requires TypeScript 5.2+ and Node 20+. If you can't
|
|
936
|
+
* use it, just call `await client.close()` manually when you're done.
|
|
937
|
+
*
|
|
938
|
+
* @category Client
|
|
676
939
|
*/
|
|
677
940
|
declare class Vairified {
|
|
678
|
-
|
|
941
|
+
#private;
|
|
942
|
+
/** The resolved API key this client is using. */
|
|
679
943
|
readonly apiKey: string;
|
|
680
|
-
/**
|
|
944
|
+
/** The resolved base URL (production, staging, local, or custom). */
|
|
681
945
|
readonly baseUrl: string;
|
|
682
|
-
/**
|
|
946
|
+
/** The resolved environment name. */
|
|
683
947
|
readonly env: VairifiedEnvironment;
|
|
684
|
-
/** Request timeout in
|
|
685
|
-
readonly
|
|
948
|
+
/** Request timeout in milliseconds. */
|
|
949
|
+
readonly timeoutMs: number;
|
|
950
|
+
/** Member operations — get, search, find, ratingUpdates. */
|
|
951
|
+
readonly members: MembersResource;
|
|
952
|
+
/** Match submission — submit, testWebhook. */
|
|
953
|
+
readonly matches: MatchesResource;
|
|
954
|
+
/** OAuth flow — authorize, exchangeToken, refresh, revoke. */
|
|
955
|
+
readonly oauth: OAuthResource;
|
|
956
|
+
/** Leaderboard queries — list, rank, categories. */
|
|
957
|
+
readonly leaderboard: LeaderboardResource;
|
|
686
958
|
constructor(options?: VairifiedOptions);
|
|
687
|
-
private getEnvVar;
|
|
688
|
-
private getEnvApiKey;
|
|
689
|
-
private getHeaders;
|
|
690
|
-
private handleError;
|
|
691
|
-
private request;
|
|
692
|
-
/**
|
|
693
|
-
* Get a connected member by their external ID.
|
|
694
|
-
*
|
|
695
|
-
* **Requires OAuth Connection**: The player must have connected their
|
|
696
|
-
* account to your application via OAuth before you can access their data.
|
|
697
|
-
*
|
|
698
|
-
* @param playerId - External player ID (vair_mem_xxx format)
|
|
699
|
-
* @returns Member object with profile and rating data
|
|
700
|
-
* @throws NotFoundError if member is not found or invalid ID format
|
|
701
|
-
* @throws ForbiddenError if player has not connected to your app
|
|
702
|
-
*
|
|
703
|
-
* @example
|
|
704
|
-
* ```ts
|
|
705
|
-
* const member = await client.getMember('vair_mem_0ABC123def456GHI789jk');
|
|
706
|
-
* console.log(member.name, member.rating);
|
|
707
|
-
* console.log(member.ratingSplits.open); // Open division rating
|
|
708
|
-
* console.log(member.grantedScopes); // ['profile:read', 'rating:read']
|
|
709
|
-
* ```
|
|
710
|
-
*/
|
|
711
|
-
getMember(playerId: string): Promise<Member>;
|
|
712
|
-
/**
|
|
713
|
-
* Search for players.
|
|
714
|
-
*
|
|
715
|
-
* @param filters - Search filters
|
|
716
|
-
* @returns SearchResults with players and pagination
|
|
717
|
-
*
|
|
718
|
-
* @example
|
|
719
|
-
* ```ts
|
|
720
|
-
* const results = await client.search({
|
|
721
|
-
* city: 'Austin',
|
|
722
|
-
* ratingMin: 4.0,
|
|
723
|
-
* vairifiedOnly: true,
|
|
724
|
-
* });
|
|
725
|
-
*
|
|
726
|
-
* for (const player of results) {
|
|
727
|
-
* console.log(player.name, player.rating);
|
|
728
|
-
* }
|
|
729
|
-
*
|
|
730
|
-
* // Pagination
|
|
731
|
-
* if (results.hasMore) {
|
|
732
|
-
* const nextPage = await results.nextPage();
|
|
733
|
-
* }
|
|
734
|
-
* ```
|
|
735
|
-
*/
|
|
736
|
-
search(filters?: SearchFilters): Promise<SearchResults>;
|
|
737
|
-
/**
|
|
738
|
-
* Find a single player by name.
|
|
739
|
-
*
|
|
740
|
-
* @param name - Player name to search for
|
|
741
|
-
* @returns Player if found, undefined otherwise
|
|
742
|
-
*
|
|
743
|
-
* @example
|
|
744
|
-
* ```ts
|
|
745
|
-
* const player = await client.findPlayer('John Smith');
|
|
746
|
-
* if (player) {
|
|
747
|
-
* console.log(player.rating);
|
|
748
|
-
* }
|
|
749
|
-
* ```
|
|
750
|
-
*/
|
|
751
|
-
findPlayer(name: string): Promise<Player | undefined>;
|
|
752
|
-
/**
|
|
753
|
-
* Submit a single match.
|
|
754
|
-
*
|
|
755
|
-
* @param match - Match object with teams and scores
|
|
756
|
-
* @returns MatchResult with submission status
|
|
757
|
-
*
|
|
758
|
-
* @example
|
|
759
|
-
* ```ts
|
|
760
|
-
* const match = new Match({
|
|
761
|
-
* event: 'Weekly League',
|
|
762
|
-
* bracket: '4.0 Doubles',
|
|
763
|
-
* date: new Date(),
|
|
764
|
-
* team1: ['p1', 'p2'],
|
|
765
|
-
* team2: ['p3', 'p4'],
|
|
766
|
-
* scores: [[11, 9], [11, 7]],
|
|
767
|
-
* });
|
|
768
|
-
*
|
|
769
|
-
* const result = await client.submitMatch(match);
|
|
770
|
-
* if (result.ok) {
|
|
771
|
-
* console.log(`Submitted ${result.numGames} games`);
|
|
772
|
-
* }
|
|
773
|
-
* ```
|
|
774
|
-
*/
|
|
775
|
-
submitMatch(match: Match): Promise<MatchResult>;
|
|
776
|
-
/**
|
|
777
|
-
* Submit multiple matches in a batch.
|
|
778
|
-
*
|
|
779
|
-
* @param matches - List of Match objects
|
|
780
|
-
* @returns MatchResult with submission status
|
|
781
|
-
*
|
|
782
|
-
* @example
|
|
783
|
-
* ```ts
|
|
784
|
-
* const result = await client.submitMatches([match1, match2, match3]);
|
|
785
|
-
* console.log(`Submitted ${result.numGames} games from ${result.numMatches} matches`);
|
|
786
|
-
*
|
|
787
|
-
* if (result.dryRun) {
|
|
788
|
-
* console.log('This was a dry run - no data persisted');
|
|
789
|
-
* }
|
|
790
|
-
* ```
|
|
791
|
-
*/
|
|
792
|
-
submitMatches(matches: Match[]): Promise<MatchResult>;
|
|
793
|
-
/**
|
|
794
|
-
* Get rating updates for subscribed members.
|
|
795
|
-
*
|
|
796
|
-
* Members are subscribed when you call getMember().
|
|
797
|
-
*
|
|
798
|
-
* @returns List of RatingUpdate objects
|
|
799
|
-
*
|
|
800
|
-
* @example
|
|
801
|
-
* ```ts
|
|
802
|
-
* const updates = await client.getRatingUpdates();
|
|
803
|
-
* for (const update of updates) {
|
|
804
|
-
* console.log(`${update.memberId}: ${update.previousRating} → ${update.newRating}`);
|
|
805
|
-
* if (update.improved) {
|
|
806
|
-
* const member = await update.getMember();
|
|
807
|
-
* console.log(`${member.name} improved!`);
|
|
808
|
-
* }
|
|
809
|
-
* }
|
|
810
|
-
* ```
|
|
811
|
-
*/
|
|
812
|
-
getRatingUpdates(): Promise<RatingUpdate[]>;
|
|
813
|
-
/**
|
|
814
|
-
* Test webhook endpoint.
|
|
815
|
-
*
|
|
816
|
-
* @param webhookUrl - URL to send test webhook to
|
|
817
|
-
* @returns Test result
|
|
818
|
-
*/
|
|
819
|
-
testWebhook(webhookUrl: string): Promise<Record<string, unknown>>;
|
|
820
|
-
/**
|
|
821
|
-
* Start an OAuth authorization flow.
|
|
822
|
-
*
|
|
823
|
-
* This creates a pending authorization and returns the URL where
|
|
824
|
-
* users should be redirected to approve access.
|
|
825
|
-
*
|
|
826
|
-
* @param redirectUri - Your application's callback URL
|
|
827
|
-
* @param scopes - Permission scopes to request (defaults to profile:read, rating:read)
|
|
828
|
-
* @param state - CSRF protection state parameter (recommended)
|
|
829
|
-
* @returns AuthorizationResponse with the URL to redirect users to
|
|
830
|
-
* @throws OAuthError if the authorization fails to start
|
|
831
|
-
*
|
|
832
|
-
* @example
|
|
833
|
-
* ```ts
|
|
834
|
-
* const auth = await client.startOAuth(
|
|
835
|
-
* 'https://myapp.com/callback',
|
|
836
|
-
* ['profile:read', 'rating:read', 'match:submit'],
|
|
837
|
-
* 'random_csrf_token',
|
|
838
|
-
* );
|
|
839
|
-
* // Redirect user to auth.authorizationUrl
|
|
840
|
-
* window.location.href = auth.authorizationUrl;
|
|
841
|
-
* ```
|
|
842
|
-
*
|
|
843
|
-
* @category OAuth
|
|
844
|
-
*/
|
|
845
|
-
startOAuth(redirectUri: string, scopes?: OAuthScope[], state?: string): Promise<AuthorizationResponse>;
|
|
846
959
|
/**
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
* Call this after the user approves access and is redirected back
|
|
850
|
-
* to your application with a code parameter.
|
|
851
|
-
*
|
|
852
|
-
* @param code - Authorization code from the callback URL
|
|
853
|
-
* @param redirectUri - Must match the redirectUri used in startOAuth
|
|
854
|
-
* @returns TokenResponse with access_token, refresh_token, and player_id
|
|
855
|
-
* @throws OAuthError if the code is invalid or expired
|
|
856
|
-
*
|
|
857
|
-
* @example
|
|
858
|
-
* ```ts
|
|
859
|
-
* // After user is redirected to: https://myapp.com/callback?code=xxx
|
|
860
|
-
* const tokens = await client.exchangeToken(
|
|
861
|
-
* new URL(window.location.href).searchParams.get('code')!,
|
|
862
|
-
* 'https://myapp.com/callback',
|
|
863
|
-
* );
|
|
864
|
-
* // Store tokens.accessToken and tokens.refreshToken securely
|
|
865
|
-
* // Use tokens.playerId to identify the connected player
|
|
866
|
-
* ```
|
|
867
|
-
*
|
|
868
|
-
* @category OAuth
|
|
869
|
-
*/
|
|
870
|
-
exchangeToken(code: string, redirectUri: string): Promise<TokenResponse>;
|
|
871
|
-
/**
|
|
872
|
-
* Refresh an expired access token.
|
|
873
|
-
*
|
|
874
|
-
* Use this when an access token expires to obtain a new one
|
|
875
|
-
* without requiring the user to re-authorize.
|
|
876
|
-
*
|
|
877
|
-
* @param refreshToken - The refresh token from a previous token exchange
|
|
878
|
-
* @returns TokenResponse with new access_token and optionally a new refresh_token
|
|
879
|
-
* @throws OAuthError if the refresh token is invalid or revoked
|
|
880
|
-
*
|
|
881
|
-
* @example
|
|
882
|
-
* ```ts
|
|
883
|
-
* try {
|
|
884
|
-
* const newTokens = await client.refreshAccessToken(storedRefreshToken);
|
|
885
|
-
* // Update stored tokens
|
|
886
|
-
* } catch (e) {
|
|
887
|
-
* if (e instanceof OAuthError && e.errorCode === 'invalid_grant') {
|
|
888
|
-
* // Refresh token revoked, user needs to re-authorize
|
|
889
|
-
* }
|
|
890
|
-
* }
|
|
891
|
-
* ```
|
|
892
|
-
*
|
|
893
|
-
* @category OAuth
|
|
894
|
-
*/
|
|
895
|
-
refreshAccessToken(refreshToken: string): Promise<TokenResponse>;
|
|
896
|
-
/**
|
|
897
|
-
* Revoke a player's OAuth connection.
|
|
898
|
-
*
|
|
899
|
-
* This disconnects the player from your application. You will no
|
|
900
|
-
* longer be able to access their data or submit matches on their behalf.
|
|
960
|
+
* API usage statistics for the current API key.
|
|
901
961
|
*
|
|
902
|
-
*
|
|
903
|
-
* @throws OAuthError if the revocation fails
|
|
904
|
-
*
|
|
905
|
-
* @example
|
|
906
|
-
* ```ts
|
|
907
|
-
* await client.revokeConnection('vair_mem_0ABC123def456GHI789jk');
|
|
908
|
-
* // Player is now disconnected
|
|
909
|
-
* ```
|
|
910
|
-
*
|
|
911
|
-
* @category OAuth
|
|
962
|
+
* Returns rate-limit status, request counts, and quota usage.
|
|
912
963
|
*/
|
|
913
|
-
|
|
964
|
+
usage(): Promise<Record<string, unknown>>;
|
|
914
965
|
/**
|
|
915
|
-
*
|
|
916
|
-
*
|
|
917
|
-
* @returns List of scope objects with id, name, and description
|
|
966
|
+
* Release any resources held by the client.
|
|
918
967
|
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
* for (const scope of scopes) {
|
|
923
|
-
* console.log(`${scope.id}: ${scope.description}`);
|
|
924
|
-
* }
|
|
925
|
-
* ```
|
|
926
|
-
*
|
|
927
|
-
* @category OAuth
|
|
968
|
+
* The current transport is stateless, so this is a no-op today, but
|
|
969
|
+
* partners should still call it (or use `await using`) so the SDK
|
|
970
|
+
* can add connection pooling later without breaking them.
|
|
928
971
|
*/
|
|
929
|
-
|
|
930
|
-
id: string;
|
|
931
|
-
name: string;
|
|
932
|
-
description: string;
|
|
933
|
-
}>>;
|
|
972
|
+
close(): Promise<void>;
|
|
934
973
|
/**
|
|
935
|
-
*
|
|
936
|
-
*
|
|
937
|
-
* @returns Usage statistics (requests, limits, etc.)
|
|
938
|
-
*
|
|
939
|
-
* @example
|
|
940
|
-
* ```ts
|
|
941
|
-
* const usage = await client.getUsage();
|
|
942
|
-
* console.log(`Requests today: ${usage.requestsToday}`);
|
|
943
|
-
* console.log(`Rate limit: ${usage.rateLimit}/hour`);
|
|
944
|
-
* ```
|
|
945
|
-
*
|
|
946
|
-
* @category Client
|
|
974
|
+
* Explicit resource management hook — enables
|
|
975
|
+
* `await using client = new Vairified({ ... })` (TypeScript 5.2+).
|
|
947
976
|
*/
|
|
948
|
-
|
|
977
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
978
|
+
/** Compact summary for console output. */
|
|
979
|
+
toString(): string;
|
|
949
980
|
}
|
|
950
981
|
|
|
951
982
|
/**
|
|
952
|
-
* Vairified SDK
|
|
983
|
+
* Vairified SDK — error hierarchy.
|
|
984
|
+
*
|
|
985
|
+
* All SDK errors inherit from {@link VairifiedError}, so a single
|
|
986
|
+
* `catch (err: unknown) { if (err instanceof VairifiedError) ... }`
|
|
987
|
+
* covers everything. HTTP-status-specific subclasses (auth, not found,
|
|
988
|
+
* rate limit, validation) are thrown automatically by the HTTP layer.
|
|
953
989
|
*
|
|
954
990
|
* @module
|
|
955
991
|
*/
|
|
956
992
|
/**
|
|
957
|
-
* Base
|
|
993
|
+
* Base class for every error thrown by the Vairified SDK.
|
|
958
994
|
*
|
|
959
995
|
* @category Errors
|
|
960
996
|
*/
|
|
961
997
|
declare class VairifiedError extends Error {
|
|
962
|
-
/** HTTP status code */
|
|
963
|
-
statusCode?: number;
|
|
964
|
-
/**
|
|
965
|
-
response?: unknown;
|
|
998
|
+
/** HTTP status code (if the error came from an API response). */
|
|
999
|
+
readonly statusCode?: number;
|
|
1000
|
+
/** Raw response body parsed as JSON when available. */
|
|
1001
|
+
readonly response?: unknown;
|
|
966
1002
|
constructor(message: string, statusCode?: number, response?: unknown);
|
|
967
1003
|
}
|
|
968
1004
|
/**
|
|
969
|
-
*
|
|
1005
|
+
* Thrown on HTTP 429 responses. Carries the `Retry-After` header value
|
|
1006
|
+
* when the server provides one.
|
|
970
1007
|
*
|
|
971
1008
|
* @category Errors
|
|
972
1009
|
*/
|
|
973
1010
|
declare class RateLimitError extends VairifiedError {
|
|
974
|
-
/** Seconds to wait before retrying */
|
|
975
|
-
retryAfter?: number;
|
|
1011
|
+
/** Seconds to wait before retrying, or `undefined` if the server didn't say. */
|
|
1012
|
+
readonly retryAfter?: number;
|
|
976
1013
|
constructor(message?: string, retryAfter?: number, response?: unknown);
|
|
977
1014
|
}
|
|
978
1015
|
/**
|
|
979
|
-
*
|
|
1016
|
+
* Thrown on HTTP 401 — invalid or missing API key.
|
|
980
1017
|
*
|
|
981
1018
|
* @category Errors
|
|
982
1019
|
*/
|
|
@@ -984,7 +1021,7 @@ declare class AuthenticationError extends VairifiedError {
|
|
|
984
1021
|
constructor(message?: string, response?: unknown);
|
|
985
1022
|
}
|
|
986
1023
|
/**
|
|
987
|
-
*
|
|
1024
|
+
* Thrown on HTTP 404 — the resource doesn't exist.
|
|
988
1025
|
*
|
|
989
1026
|
* @category Errors
|
|
990
1027
|
*/
|
|
@@ -992,7 +1029,9 @@ declare class NotFoundError extends VairifiedError {
|
|
|
992
1029
|
constructor(message?: string, response?: unknown);
|
|
993
1030
|
}
|
|
994
1031
|
/**
|
|
995
|
-
*
|
|
1032
|
+
* Thrown on HTTP 400 — the server rejected the request payload.
|
|
1033
|
+
*
|
|
1034
|
+
* Inspect {@link VairifiedError.response} for field-level details.
|
|
996
1035
|
*
|
|
997
1036
|
* @category Errors
|
|
998
1037
|
*/
|
|
@@ -1000,16 +1039,18 @@ declare class ValidationError extends VairifiedError {
|
|
|
1000
1039
|
constructor(message?: string, response?: unknown);
|
|
1001
1040
|
}
|
|
1002
1041
|
/**
|
|
1003
|
-
*
|
|
1004
|
-
*
|
|
1005
|
-
* This can occur during authorization, token exchange, refresh, or revocation.
|
|
1042
|
+
* Thrown by {@link OAuthResource} methods when authorization, token
|
|
1043
|
+
* exchange, refresh, or revocation fails.
|
|
1006
1044
|
*
|
|
1007
1045
|
* @category Errors
|
|
1008
1046
|
*/
|
|
1009
1047
|
declare class OAuthError extends VairifiedError {
|
|
1010
|
-
/**
|
|
1011
|
-
|
|
1048
|
+
/**
|
|
1049
|
+
* OAuth error code such as `'invalid_grant'`, `'invalid_scope'`,
|
|
1050
|
+
* or `'expired_token'`. Check this to branch on the specific failure.
|
|
1051
|
+
*/
|
|
1052
|
+
readonly errorCode?: string;
|
|
1012
1053
|
constructor(message?: string, errorCode?: string, response?: unknown);
|
|
1013
1054
|
}
|
|
1014
1055
|
|
|
1015
|
-
export { AuthenticationError, type AuthorizationResponse, DEFAULT_SCOPES,
|
|
1056
|
+
export { type ApiErrorResponse, AuthenticationError, type AuthorizationResponse, DEFAULT_SCOPES, ENVIRONMENTS, type GameInput, type Gender, type LeaderboardOptions, LeaderboardResource, type MatchBatch, MatchBatchResult, type MatchBatchResultWire, type MatchInput, MatchesResource, Member, MemberSportMap, type MemberStatusWire, MembersResource, NotFoundError, type OAuthConfig, OAuthError, OAuthResource, type OAuthScope, type PartnerMemberWire, type PartnerRatingUpdateWire, type PlayerRankOptions, RateLimitError, type RatingSplitWire, RatingUpdate, SCOPES, type SearchFilters, SportRating, type SportRatingWire, type TokenResponse, Vairified, type VairifiedEnvironment, VairifiedError, type VairifiedOptions, ValidationError, describeScope, describeScopes, generateState, getAuthorizationUrl, validateScope };
|