vairified 0.3.2 → 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
@@ -69,12 +69,13 @@ const member = await client.members.get('vair_mem_xxx');
69
69
  console.log(member.name); // Full name
70
70
  console.log(member.displayName); // "Mike B."
71
71
  console.log(member.ratingFor('pickleball')); // 3.915
72
- console.log(member.status.isVairified); // true
72
+ console.log(member.sport.get('pickleball')?.isVairified); // true (per-sport)
73
73
 
74
74
  // Dict-like access to rating splits for a specific sport
75
75
  const pb = member.sport.get('pickleball');
76
76
  if (pb) {
77
77
  console.log(pb.rating, pb.abbr); // 3.915 VO
78
+ console.log(pb.isVairified, pb.isVairPro); // per-sport status flags
78
79
  console.log(pb.get('overall-open')?.rating); // 3.915
79
80
  console.log(pb.has('singles-open')); // true
80
81
  for (const [key, split] of pb) {
@@ -357,6 +358,60 @@ export VAIRIFIED_ENV="staging" # optional; default: production
357
358
  const client = new Vairified(); // reads both env vars
358
359
  ```
359
360
 
361
+ ## React Native
362
+
363
+ The SDK keeps its **zero-dependency** promise on React Native too — it doesn't bundle
364
+ any polyfills. Instead it feature-detects the platform primitives it needs and expects
365
+ your app to provide the two that Hermes lacks.
366
+
367
+ ### Required polyfills
368
+
369
+ Install them and import each **once, at your app entry** (e.g. the top of `index.js`),
370
+ before any SDK call:
371
+
372
+ ```bash
373
+ npm install react-native-get-random-values react-native-url-polyfill
374
+ ```
375
+
376
+ ```ts
377
+ // index.js — must run before `import { Vairified } from 'vairified'`
378
+ import 'react-native-get-random-values'; // Web Crypto for generateState()
379
+ import 'react-native-url-polyfill/auto'; // WHATWG URL / URLSearchParams
380
+ ```
381
+
382
+ - **`react-native-get-random-values`** backs `crypto.getRandomValues`, which
383
+ `generateState()` uses for CSRF tokens. Without it, `generateState()` throws a
384
+ descriptive error (not a bare `ReferenceError`); you can also skip it and pass your
385
+ own high-entropy `state` string to `oauth.authorize()`.
386
+ - **`react-native-url-polyfill`** provides a complete `URL`/`URLSearchParams`. Hermes'
387
+ built-ins are incomplete, so request-URL and authorization-URL building need this.
388
+
389
+ ### Pass `apiKey` and `env` explicitly
390
+
391
+ React Native has no `process.env`, so the `VAIRIFIED_API_KEY` / `VAIRIFIED_ENV` fallbacks
392
+ never resolve there (the SDK guards against the missing global rather than crashing).
393
+ Always construct the client explicitly:
394
+
395
+ ```ts
396
+ const client = new Vairified({ apiKey: 'vair_pk_xxx', env: 'production' });
397
+ ```
398
+
399
+ ### Token topology — never ship the API key in the app
400
+
401
+ The secret partner API key (`X-API-Key`) **must never ship in a mobile app binary**.
402
+ Split the OAuth flow across the app and your backend:
403
+
404
+ 1. **App:** open the authorization URL using your public `client_id` (your `PartnerApp`
405
+ slug) — build it with `getAuthorizationUrl({ redirectUri, clientId })` — and capture
406
+ the `myapp://callback` deep link to read the `code` (and `state`).
407
+ 2. **Your backend:** perform the code exchange there with a `Vairified` client that holds
408
+ the secret key — `client.oauth.exchangeToken({ code, redirectUri })`, and likewise
409
+ `refresh()` / `revoke()`. The SDK injects `X-API-Key` on these calls, so they belong
410
+ on the server, never in the app.
411
+
412
+ The app sends the captured `code` to your backend over your own authenticated channel;
413
+ the backend returns only the resulting access token (or a session) to the app.
414
+
360
415
  ## Error Handling
361
416
 
362
417
  The SDK maps HTTP status codes to typed exceptions. All typed exceptions inherit from
@@ -410,7 +465,8 @@ member.displayName // "Mike B."
410
465
  member.firstName / lastName
411
466
  member.gender // 'MALE' | 'FEMALE' | 'OTHER' | 'UNKNOWN' | null
412
467
  member.age / city / state / zip / country
413
- member.status.isVairified // grouped status flags
468
+ member.status.isWheelchair // global status flags
469
+ member.status.isAmbassador
414
470
  member.status.isConnected
415
471
  member.sport // MemberSportMap
416
472
  member.sports // readonly string[] of sport codes
@@ -418,12 +474,19 @@ member.ratingFor('pickleball') // number | null
418
474
  member.split('overall-open') // RatingSplitWire | null
419
475
  ```
420
476
 
477
+ VAIRification & VAIR-Pro status are **per-sport** — read them off each
478
+ `member.sport` entry, not `member.status` (see `SportRating` below).
479
+
421
480
  ### `SportRating` (dict-like)
422
481
 
423
482
  ```ts
424
483
  const pb = member.sport.get('pickleball');
425
484
  pb?.rating // Primary rating for this sport
426
485
  pb?.abbr // "VO", "VG", etc.
486
+ pb?.isVairified // per-sport VAIRified flag (Vairified#783)
487
+ pb?.isRater // per-sport rater flag
488
+ pb?.isVairPro // per-sport VAIR-Pro flag
489
+ pb?.isVairProStatus // 'PENDING' | 'ACTIVE' | null
427
490
  pb?.get('overall-open') // Any split key
428
491
  pb?.size // Number of splits
429
492
  pb?.has('singles-40+') // Membership check
@@ -432,6 +495,16 @@ for (const [key, split] of pb ?? []) { /* iterate */ }
432
495
 
433
496
  ## Migrating
434
497
 
498
+ **From 0.3.x → 0.4.0 (breaking):** VAIRification & VAIR-Pro status are now
499
+ **per-sport** (Vairified#783). `isVairified`, `isRater`, `isVairPro`, and
500
+ `isVairProStatus` moved off the member `status` object onto each per-sport
501
+ entry — read them via `member.sport.get(code)?.isVairified` instead of
502
+ `member.status.isVairified`. The `status` object keeps only the genuinely
503
+ global flags (`isWheelchair`, `isAmbassador`, `isConnected`). This mirrors
504
+ the backend: a player can be VAIRified / a VAIR Pro in one sport but not
505
+ another. Publish only after the backend #788 reaches production — against
506
+ the old prod shape the per-sport flags default to `false`/`null`.
507
+
435
508
  **From 0.2.x → 0.3.0:** All OAuth scope strings gained a `user:` prefix
436
509
  (`profile:read` → `user:profile:read`). Update any hardcoded scope arrays.
437
510
  New: `members.getBulk()`, `matches.tournamentImport()`, `webhooks.deliveries()`.
package/dist/index.cjs CHANGED
@@ -419,10 +419,22 @@ var SportRating = class {
419
419
  rating;
420
420
  /** Category abbreviation for the primary rating (e.g. `'VO'`). */
421
421
  abbr;
422
+ /** Player is VAIRified in this sport (has a verified, non-recreational rating). */
423
+ isVairified;
424
+ /** Player is an active VAIR Pro (can rate) in this sport. Alias of {@link isVairPro}. */
425
+ isRater;
426
+ /** Player is an active VAIR Pro (can rate) in this sport. */
427
+ isVairPro;
428
+ /** VAIR-Pro lifecycle status in this sport (`'ACTIVE'` / `'PENDING'` / `null`). */
429
+ isVairProStatus;
422
430
  #splits;
423
431
  constructor(wire) {
424
432
  this.rating = wire.rating;
425
433
  this.abbr = wire.abbr;
434
+ this.isVairified = wire.isVairified ?? false;
435
+ this.isRater = wire.isRater ?? false;
436
+ this.isVairPro = wire.isVairPro ?? false;
437
+ this.isVairProStatus = wire.isVairProStatus ?? null;
426
438
  this.#splits = new Map(Object.entries(wire.ratingSplits ?? {}));
427
439
  Object.freeze(this);
428
440
  }
@@ -873,13 +885,31 @@ function describeScopes(scopes) {
873
885
  }));
874
886
  }
875
887
  function generateState() {
876
- const bytes = new Uint8Array(32);
877
- crypto.getRandomValues(bytes);
878
- let binary = "";
879
- for (const byte of bytes) {
880
- binary += String.fromCharCode(byte);
888
+ const webCrypto = globalThis.crypto;
889
+ if (typeof webCrypto?.getRandomValues !== "function") {
890
+ throw new Error(
891
+ "generateState() needs Web Crypto (crypto.getRandomValues), which is unavailable in this runtime. Node 19+ and browsers have it built in; on React Native / Hermes, install 'react-native-get-random-values' and import it once at your app entry before using the SDK \u2014 or pass your own high-entropy `state` string to oauth.authorize()."
892
+ );
881
893
  }
882
- return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
894
+ const bytes = new Uint8Array(32);
895
+ webCrypto.getRandomValues(bytes);
896
+ return base64UrlNoPad(bytes);
897
+ }
898
+ var B64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
899
+ function base64UrlNoPad(bytes) {
900
+ let out = "";
901
+ for (let i = 0; i < bytes.length; i += 3) {
902
+ const b0 = bytes[i] ?? 0;
903
+ const b1 = bytes[i + 1] ?? 0;
904
+ const b2 = bytes[i + 2] ?? 0;
905
+ const hasB1 = i + 1 < bytes.length;
906
+ const hasB2 = i + 2 < bytes.length;
907
+ out += B64URL_ALPHABET[b0 >> 2] ?? "";
908
+ out += B64URL_ALPHABET[(b0 & 3) << 4 | b1 >> 4] ?? "";
909
+ if (hasB1) out += B64URL_ALPHABET[(b1 & 15) << 2 | b2 >> 6] ?? "";
910
+ if (hasB2) out += B64URL_ALPHABET[b2 & 63] ?? "";
911
+ }
912
+ return out;
883
913
  }
884
914
  function ensureProfileRead(scopes) {
885
915
  if (scopes.includes("user:profile:read")) {
@@ -1081,6 +1111,14 @@ var ENVIRONMENTS = Object.freeze({
1081
1111
  local: "http://localhost:3001/api/v1"
1082
1112
  });
1083
1113
  var DEFAULT_TIMEOUT_MS = 3e4;
1114
+ function readEnv(name) {
1115
+ try {
1116
+ if (typeof process === "undefined") return void 0;
1117
+ return process.env?.[name];
1118
+ } catch {
1119
+ return void 0;
1120
+ }
1121
+ }
1084
1122
  var Vairified = class {
1085
1123
  /** The resolved API key this client is using. */
1086
1124
  apiKey;
@@ -1102,7 +1140,7 @@ var Vairified = class {
1102
1140
  webhooks;
1103
1141
  #transport;
1104
1142
  constructor(options = {}) {
1105
- const apiKey = options.apiKey ?? process.env.VAIRIFIED_API_KEY ?? "";
1143
+ const apiKey = options.apiKey ?? readEnv("VAIRIFIED_API_KEY") ?? "";
1106
1144
  if (apiKey.length === 0) {
1107
1145
  throw new Error("API key required. Pass { apiKey } or set VAIRIFIED_API_KEY.");
1108
1146
  }
@@ -1111,7 +1149,7 @@ var Vairified = class {
1111
1149
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
1112
1150
  this.env = options.env ?? "production";
1113
1151
  } else {
1114
- const envName = options.env ?? process.env.VAIRIFIED_ENV ?? "production";
1152
+ const envName = options.env ?? readEnv("VAIRIFIED_ENV") ?? "production";
1115
1153
  if (options.env && !(envName in ENVIRONMENTS)) {
1116
1154
  throw new Error(
1117
1155
  `Unknown environment: ${envName}. Use one of: ${Object.keys(ENVIRONMENTS).join(", ")}`
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/leaderboard.ts","../src/models/match-batch-result.ts","../src/models/tournament-import-result.ts","../src/resources/matches.ts","../src/models/sport-rating.ts","../src/models/member.ts","../src/models/rating-update.ts","../src/resources/members.ts","../src/oauth.ts","../src/resources/oauth.ts","../src/models/webhook-delivery.ts","../src/resources/webhooks.ts","../src/client.ts"],"sourcesContent":["/**\n * Vairified SDK — Partner API v1.\n *\n * The Vairified Partner API lets you read player ratings, submit match\n * results, and subscribe to rating change notifications for\n * integrations in leagues, tournaments, and club-management software.\n *\n * ```ts\n * import { Vairified } from 'vairified';\n *\n * await using client = new Vairified({ apiKey: 'vair_pk_xxx' });\n *\n * // Look up a connected player\n * const member = await client.members.get('vair_mem_xxx');\n * console.log(member.name, member.ratingFor('pickleball'));\n *\n * // Auto-paginating search\n * for await (const player of client.members.search({ city: 'Austin' })) {\n * console.log(player.displayName);\n * }\n *\n * // Submit a bulk match batch\n * const result = await client.matches.submit({\n * sport: 'pickleball',\n * winScore: 11,\n * winBy: 2,\n * bracket: '4.0 Doubles',\n * event: 'Weekly League',\n * matchDate: '2026-04-11T14:00:00Z',\n * matches: [\n * {\n * identifier: 'm1',\n * teams: [['vair_mem_aaa', 'vair_mem_bbb'],\n * ['vair_mem_ccc', 'vair_mem_ddd']],\n * games: [{ scores: [11, 8] }, { scores: [11, 5] }],\n * },\n * ],\n * });\n * console.log(`Submitted ${result.numGames} games`);\n * ```\n *\n * See https://vairified.github.io/vairified.js for full documentation.\n *\n * @packageDocumentation\n * @module vairified\n */\n\n// ---- Client ----\nexport { ENVIRONMENTS, Vairified } from './client.js';\n// ---- Error classes ----\nexport {\n AuthenticationError,\n NotFoundError,\n OAuthError,\n RateLimitError,\n VairifiedError,\n ValidationError,\n} from './errors.js';\n\n// ---- Response models ----\nexport {\n MatchBatchResult,\n Member,\n MemberSportMap,\n RatingUpdate,\n SportRating,\n TournamentImportResult,\n WebhookDeliveriesResult,\n WebhookDelivery,\n} from './models/index.js';\nexport type {\n AuthorizationResponse,\n OAuthConfig,\n OAuthScope,\n TokenResponse,\n} from './oauth.js';\n// ---- OAuth helpers ----\nexport {\n DEFAULT_SCOPES,\n describeScope,\n describeScopes,\n generateState,\n getAuthorizationUrl,\n SCOPES,\n validateScope,\n} from './oauth.js';\n// ---- Resource classes (typically accessed via client.*) ----\nexport {\n LeaderboardResource,\n MatchesResource,\n MembersResource,\n OAuthResource,\n WebhooksResource,\n} from './resources/index.js';\n// ---- Types (request shapes + wire types) ----\nexport type {\n ApiErrorResponse,\n GameInput,\n Gender,\n LeaderboardOptions,\n MatchBatch,\n MatchBatchResultWire,\n MatchInput,\n MemberStatusWire,\n PartnerMemberWire,\n PartnerRatingUpdateWire,\n PlayerRankOptions,\n RatingSplitWire,\n SearchFilters,\n SportRatingWire,\n TournamentImportResultWire,\n VairifiedEnvironment,\n VairifiedOptions,\n WebhookDeliveriesResultWire,\n WebhookDeliveryWire,\n} from './types.js';\n","/**\n * Vairified SDK — error hierarchy.\n *\n * All SDK errors inherit from {@link VairifiedError}, so a single\n * `catch (err: unknown) { if (err instanceof VairifiedError) ... }`\n * covers everything. HTTP-status-specific subclasses (auth, not found,\n * rate limit, validation) are thrown automatically by the HTTP layer.\n *\n * @module\n */\n\n/**\n * Base class for every error thrown by the Vairified SDK.\n *\n * @category Errors\n */\nexport class VairifiedError extends Error {\n /** HTTP status code (if the error came from an API response). */\n readonly statusCode?: number;\n /** Raw response body parsed as JSON when available. */\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = 'VairifiedError';\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/**\n * Thrown on HTTP 429 responses. Carries the `Retry-After` header value\n * when the server provides one.\n *\n * @category Errors\n */\nexport class RateLimitError extends VairifiedError {\n /** Seconds to wait before retrying, or `undefined` if the server didn't say. */\n readonly retryAfter?: number;\n\n constructor(message = 'Rate limit exceeded', retryAfter?: number, response?: unknown) {\n super(message, 429, response);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Thrown on HTTP 401 — invalid or missing API key.\n *\n * @category Errors\n */\nexport class AuthenticationError extends VairifiedError {\n constructor(message = 'Invalid API key', response?: unknown) {\n super(message, 401, response);\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown on HTTP 404 — the resource doesn't exist.\n *\n * @category Errors\n */\nexport class NotFoundError extends VairifiedError {\n constructor(message = 'Resource not found', response?: unknown) {\n super(message, 404, response);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Thrown on HTTP 400 — the server rejected the request payload.\n *\n * Inspect {@link VairifiedError.response} for field-level details.\n *\n * @category Errors\n */\nexport class ValidationError extends VairifiedError {\n constructor(message = 'Validation error', response?: unknown) {\n super(message, 400, response);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Thrown by {@link OAuthResource} methods when authorization, token\n * exchange, refresh, or revocation fails.\n *\n * @category Errors\n */\nexport class OAuthError extends VairifiedError {\n /**\n * OAuth error code such as `'invalid_grant'`, `'invalid_scope'`,\n * or `'expired_token'`. Check this to branch on the specific failure.\n */\n readonly errorCode?: string;\n\n constructor(message = 'OAuth error', errorCode?: string, response?: unknown) {\n super(message, undefined, response);\n this.name = 'OAuthError';\n this.errorCode = errorCode;\n }\n}\n","/**\n * HTTP transport — internal. Not part of the public API.\n *\n * The transport is a thin wrapper around native `fetch` that:\n *\n * - Injects the API key header on every request.\n * - Serializes query params (dropping `undefined`) and JSON bodies.\n * - Applies a request timeout via `AbortController`.\n * - Maps non-2xx responses to the right typed exception.\n *\n * @internal\n * @module\n */\n\nimport {\n AuthenticationError,\n NotFoundError,\n RateLimitError,\n VairifiedError,\n ValidationError,\n} from './errors.js';\nimport type { ApiErrorResponse } from './types.js';\n\n/**\n * Values accepted as query parameters.\n *\n * `null` and `undefined` are silently dropped. Arrays are joined with\n * `','`. Everything else is stringified.\n *\n * @internal\n */\nexport type QueryParams = Readonly<\n Record<string, string | number | boolean | readonly (string | number)[] | null | undefined>\n>;\n\n/**\n * Options passed to the internal HTTP layer.\n *\n * @internal\n */\nexport interface RequestOptions {\n readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n readonly path: string;\n readonly query?: QueryParams;\n readonly body?: unknown;\n}\n\n/**\n * Transport configuration.\n *\n * @internal\n */\nexport interface TransportConfig {\n readonly baseUrl: string;\n readonly apiKey: string;\n readonly timeoutMs: number;\n readonly fetch: typeof fetch;\n}\n\n/**\n * Internal HTTP client. Holds no state between requests — each call\n * builds a fresh `Request`, runs it, and returns the parsed body.\n *\n * @internal\n */\nexport class HttpTransport {\n readonly #config: TransportConfig;\n\n constructor(config: TransportConfig) {\n this.#config = config;\n }\n\n async request<T>(options: RequestOptions): Promise<T> {\n const url = buildUrl(this.#config.baseUrl, options.path, options.query);\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new Error(`Request timed out after ${this.#config.timeoutMs}ms`)),\n this.#config.timeoutMs,\n );\n\n const headers: Record<string, string> = {\n 'X-API-Key': this.#config.apiKey,\n Accept: 'application/json',\n };\n\n const init: RequestInit = {\n method: options.method,\n headers,\n signal: controller.signal,\n };\n\n if (options.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(options.body);\n }\n\n let response: Response;\n try {\n response = await this.#config.fetch(url, init);\n } finally {\n clearTimeout(timeoutId);\n }\n\n if (!response.ok) {\n await throwFromResponse(response);\n }\n\n if (response.status === 204 || response.headers.get('content-length') === '0') {\n return undefined as T;\n }\n\n const text = await response.text();\n if (text.length === 0) {\n return undefined as T;\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new VairifiedError(`Unable to parse response as JSON: ${text}`, response.status);\n }\n }\n}\n\n/**\n * Build a full URL from a base and relative path, appending query params.\n *\n * @internal\n */\nexport function buildUrl(baseUrl: string, path: string, query?: QueryParams): string {\n const cleanBase = baseUrl.replace(/\\/+$/, '');\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(cleanBase + cleanPath);\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === null || value === undefined) continue;\n if (Array.isArray(value)) {\n if (value.length === 0) continue;\n url.searchParams.set(key, value.join(','));\n } else {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n}\n\n/**\n * Parse an error response and throw the right typed exception.\n *\n * @internal\n */\nasync function throwFromResponse(response: Response): Promise<never> {\n const status = response.status;\n const text = await response.text().catch(() => '');\n\n let body: ApiErrorResponse | unknown = null;\n if (text.length > 0) {\n try {\n body = JSON.parse(text);\n } catch {\n body = null;\n }\n }\n\n let message: string;\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n const apiBody = body as ApiErrorResponse;\n message = apiBody.message || apiBody.error || text || `HTTP ${status}`;\n } else {\n message = text || `HTTP ${status}`;\n }\n\n switch (status) {\n case 400:\n throw new ValidationError(message, body);\n case 401:\n throw new AuthenticationError(message, body);\n case 404:\n throw new NotFoundError(message, body);\n case 429: {\n const retryAfterHeader = response.headers.get('Retry-After');\n const retryAfter = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : undefined;\n throw new RateLimitError(message, Number.isFinite(retryAfter) ? retryAfter : undefined, body);\n }\n default:\n throw new VairifiedError(message, status, body);\n }\n}\n","/**\n * {@link LeaderboardResource} — read-only leaderboard queries.\n *\n * @module\n */\n\nimport type { HttpTransport, QueryParams } from '../http.js';\nimport type { LeaderboardOptions, PlayerRankOptions } from '../types.js';\n\n/**\n * Read-only leaderboard queries.\n *\n * @category Resources\n */\nexport class LeaderboardResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /** Fetch a leaderboard page with optional filters. */\n async list(options: LeaderboardOptions = {}): Promise<Record<string, unknown>> {\n const query: QueryParams = {\n limit: options.limit ?? 50,\n offset: options.offset ?? 0,\n category: options.category,\n ageBracket: options.ageBracket,\n scope: options.scope,\n state: options.state,\n city: options.city,\n clubId: options.clubId,\n gender: options.gender?.toUpperCase(),\n minGames: options.minGames,\n search: options.search,\n verifiedOnly: options.verifiedOnly === true ? true : undefined,\n };\n\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'GET',\n path: '/leaderboard',\n query,\n });\n return data ?? {};\n }\n\n /** Fetch a specific player's rank plus nearby players. */\n async rank(playerId: string, options: PlayerRankOptions = {}): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = {\n playerId,\n category: options.category ?? 'doubles',\n ageBracket: options.ageBracket ?? 'open',\n scope: options.scope ?? 'global',\n contextSize: options.contextSize ?? 5,\n };\n if (options.state !== undefined) body.state = options.state;\n if (options.city !== undefined) body.city = options.city;\n if (options.clubId !== undefined) body.clubId = options.clubId;\n\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'POST',\n path: '/leaderboard/rank',\n body,\n });\n return data ?? {};\n }\n\n /** List available leaderboard categories, brackets, and scopes. */\n async categories(): Promise<Record<string, unknown>> {\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'GET',\n path: '/leaderboard/categories',\n });\n return data ?? {};\n }\n}\n","/**\n * {@link MatchBatchResult} — result of a batch match submission.\n *\n * @module\n */\n\nimport type { MatchBatchResultWire } from '../types.js';\n\n/**\n * Result of a {@link MatchesResource.submit} call.\n *\n * {@link success} is `true` only when every match in the batch was\n * accepted. Check {@link errors} for per-match validation failures.\n *\n * @category Matches\n */\nexport class MatchBatchResult {\n readonly success: boolean;\n readonly numMatches: number;\n readonly numGames: number;\n readonly dryRun: boolean | null;\n readonly message: string | null;\n readonly errors: readonly string[] | null;\n\n constructor(wire: MatchBatchResultWire) {\n this.success = wire.success;\n this.numMatches = wire.numMatches;\n this.numGames = wire.numGames;\n this.dryRun = wire.dryRun ?? null;\n this.message = wire.message ?? null;\n this.errors = wire.errors ? Object.freeze([...wire.errors]) : null;\n Object.freeze(this);\n }\n\n /** Shorthand: successful submission with zero errors. */\n get ok(): boolean {\n return this.success && (this.errors === null || this.errors.length === 0);\n }\n\n /** Whether this was a dry-run (validation only, nothing persisted). */\n get isDryRun(): boolean {\n return this.dryRun === true;\n }\n\n toString(): string {\n const mode = this.isDryRun ? ' [dry-run]' : '';\n const errs = this.errors && this.errors.length > 0 ? ` errors=${this.errors.length}` : '';\n const status = this.ok ? 'ok' : 'FAILED';\n return `MatchBatchResult ${status}${mode} matches=${this.numMatches} games=${this.numGames}${errs}`;\n }\n}\n","/**\n * {@link TournamentImportResult} — result of a tournament import submission.\n *\n * @module\n */\n\nimport type { TournamentImportResultWire } from '../types.js';\n\n/**\n * Result of a tournament import submission.\n *\n * @category Matches\n */\nexport class TournamentImportResult {\n readonly success: boolean;\n readonly matchesImported: number;\n readonly gamesRecorded: number;\n readonly ghostPlayersCreated: number;\n readonly existingPlayersMatched: number;\n readonly dryRun: boolean;\n readonly message: string | undefined;\n readonly errors: readonly string[];\n\n /** @internal */\n constructor(wire: TournamentImportResultWire) {\n this.success = wire.success;\n this.matchesImported = wire.matchesImported;\n this.gamesRecorded = wire.gamesRecorded;\n this.ghostPlayersCreated = wire.ghostPlayersCreated;\n this.existingPlayersMatched = wire.existingPlayersMatched;\n this.dryRun = wire.dryRun ?? false;\n this.message = wire.message;\n this.errors = Object.freeze(wire.errors ?? []);\n Object.freeze(this);\n }\n\n /** True when the import succeeded without errors. */\n get ok(): boolean {\n return this.success && this.errors.length === 0;\n }\n}\n","/**\n * {@link MatchesResource} — bulk match submission.\n *\n * @module\n */\n\nimport type { HttpTransport } from '../http.js';\nimport { MatchBatchResult } from '../models/match-batch-result.js';\nimport { TournamentImportResult } from '../models/tournament-import-result.js';\nimport type { MatchBatch, MatchBatchResultWire, TournamentImportResultWire } from '../types.js';\n\n/**\n * Match submission — one call submits a full batch.\n *\n * @category Resources\n */\nexport class MatchesResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * Submit a {@link MatchBatch} for rating calculation.\n *\n * All players in every match must have granted the `user:match:submit`\n * scope via OAuth (unless your API key has the\n * `user:match:submit:trusted` scope, which skips per-player consent).\n *\n * Set `batch.dryRun = true` to validate without persisting.\n *\n * ```ts\n * const result = await client.matches.submit({\n * sport: 'pickleball',\n * winScore: 11,\n * winBy: 2,\n * bracket: '4.0 Doubles',\n * event: 'Weekly League',\n * matchDate: '2026-04-11T14:00:00Z',\n * matches: [\n * {\n * identifier: 'm1',\n * teams: [['vair_mem_aaa', 'vair_mem_bbb'],\n * ['vair_mem_ccc', 'vair_mem_ddd']],\n * games: [{ scores: [11, 8] }, { scores: [11, 5] }],\n * },\n * ],\n * });\n * if (result.ok) {\n * console.log(`Submitted ${result.numGames} games`);\n * }\n * ```\n */\n async submit(batch: MatchBatch): Promise<MatchBatchResult> {\n const wire = await this.#http.request<MatchBatchResultWire>({\n method: 'POST',\n path: '/partner/matches',\n body: batch,\n });\n return new MatchBatchResult(wire);\n }\n\n /**\n * Import tournament results.\n *\n * The request body is a free-form JSON object whose structure is\n * defined by the Vairified tournament import schema. Set\n * `body.dryRun = true` to validate without persisting.\n *\n * @param body - Tournament import payload.\n * @returns {@link TournamentImportResult} with match/game counts.\n * @category Matches\n *\n * @example\n * ```ts\n * const result = await client.matches.tournamentImport({\n * sport: 'pickleball',\n * tournamentName: 'Spring Classic',\n * matches: [...],\n * });\n * if (result.ok) {\n * console.log(`Imported ${result.matchesImported} matches`);\n * }\n * ```\n */\n async tournamentImport(body: Record<string, unknown>): Promise<TournamentImportResult> {\n const wire = await this.#http.request<TournamentImportResultWire>({\n method: 'POST',\n path: '/partner/tournament-import',\n body,\n });\n return new TournamentImportResult(wire);\n }\n\n /** Send a test payload to a webhook URL. */\n async testWebhook(webhookUrl: string): Promise<Record<string, unknown>> {\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'POST',\n path: '/partner/webhook-test',\n body: { webhookUrl },\n });\n return data ?? {};\n }\n}\n","/**\n * {@link SportRating} — a player's ratings for one sport.\n *\n * @module\n */\n\nimport type { RatingSplitWire, SportRatingWire } from '../types.js';\n\n/**\n * A player's ratings for a single sport.\n *\n * The top-level `rating` / `abbr` is the primary rating for that sport\n * (conventionally the overall-open bracket). Every category × age\n * bracket the player has played is also available via {@link get},\n * {@link has}, subscript-style access, and iteration.\n *\n * ```ts\n * const pb = member.sport.get('pickleball');\n * if (pb) {\n * console.log(pb.rating, pb.abbr); // 3.915 VO\n * console.log(pb.get('overall-open')?.rating); // 3.915\n * console.log(pb.has('singles-40+')); // false\n * console.log(pb.size); // 3\n * for (const [key, split] of pb) {\n * console.log(key, split.rating);\n * }\n * }\n * ```\n *\n * @category Members\n */\nexport class SportRating {\n /** Primary rating for this sport. */\n readonly rating: number;\n /** Category abbreviation for the primary rating (e.g. `'VO'`). */\n readonly abbr: string;\n\n readonly #splits: ReadonlyMap<string, RatingSplitWire>;\n\n constructor(wire: SportRatingWire) {\n this.rating = wire.rating;\n this.abbr = wire.abbr;\n this.#splits = new Map(Object.entries(wire.ratingSplits ?? {}));\n Object.freeze(this);\n }\n\n /**\n * Look up a rating split by key (e.g. `'overall-open'`,\n * `'singles-12-13'`, `'gender-40+'`). Returns `undefined` if the\n * player has no rating for that bracket.\n */\n get(key: string): RatingSplitWire | undefined {\n return this.#splits.get(key);\n }\n\n /** Whether the player has a rating for the given split key. */\n has(key: string): boolean {\n return this.#splits.has(key);\n }\n\n /** Number of rating splits. */\n get size(): number {\n return this.#splits.size;\n }\n\n /** All split keys the player has ratings for. */\n keys(): IterableIterator<string> {\n return this.#splits.keys();\n }\n\n /** All rating splits the player has. */\n values(): IterableIterator<RatingSplitWire> {\n return this.#splits.values();\n }\n\n /** `[key, split]` pairs for every rating split. */\n entries(): IterableIterator<[string, RatingSplitWire]> {\n return this.#splits.entries();\n }\n\n /**\n * `for (const [key, split] of sportRating) { ... }` — iterate every\n * rating split the player has in this sport.\n */\n [Symbol.iterator](): IterableIterator<[string, RatingSplitWire]> {\n return this.#splits.entries();\n }\n}\n","/**\n * {@link Member} — partner-facing player record.\n *\n * @module\n */\n\nimport type {\n Gender,\n MemberStatusWire,\n PartnerMemberWire,\n RatingSplitWire,\n SportRatingWire,\n} from '../types.js';\nimport { SportRating } from './sport-rating.js';\n\n/**\n * Map-like wrapper around a player's sport → {@link SportRating}.\n *\n * Supports `.get(code)`, `.has(code)`, `.size`, and iteration so the\n * shape feels native:\n *\n * ```ts\n * member.sport.get('pickleball')?.rating\n * for (const [code, rating] of member.sport) { ... }\n * ```\n *\n * @category Members\n */\nexport class MemberSportMap {\n readonly #sports: ReadonlyMap<string, SportRating>;\n\n constructor(wire: Readonly<Record<string, SportRatingWire>> | undefined) {\n const entries = Object.entries(wire ?? {}).map(\n ([code, w]) => [code, new SportRating(w)] as const,\n );\n this.#sports = new Map(entries);\n Object.freeze(this);\n }\n\n get(sport: string): SportRating | undefined {\n return this.#sports.get(sport);\n }\n\n has(sport: string): boolean {\n return this.#sports.has(sport);\n }\n\n get size(): number {\n return this.#sports.size;\n }\n\n keys(): IterableIterator<string> {\n return this.#sports.keys();\n }\n\n values(): IterableIterator<SportRating> {\n return this.#sports.values();\n }\n\n entries(): IterableIterator<[string, SportRating]> {\n return this.#sports.entries();\n }\n\n [Symbol.iterator](): IterableIterator<[string, SportRating]> {\n return this.#sports.entries();\n }\n}\n\n/**\n * A partner-facing player record.\n *\n * Returned by {@link MembersResource.get} (full detail, requires an\n * active OAuth connection) and {@link MembersResource.search} (limited\n * detail for public search).\n *\n * Rating data lives under {@link sport} — keyed by sport code. The\n * backend returns only the sports the player has ratings in, or only\n * the sports requested via the `sport=` query filter. Use\n * {@link ratingFor} to fetch the primary rating for a specific sport\n * with a sensible default.\n *\n * @category Members\n */\nexport class Member {\n readonly memberId: number;\n readonly id: string | null;\n readonly firstName: string;\n readonly lastName: string;\n readonly fullName: string;\n readonly displayName: string;\n readonly age: number | null;\n readonly city: string | null;\n readonly state: string | null;\n readonly zip: string | null;\n readonly country: string | null;\n readonly gender: Gender | null;\n readonly status: MemberStatusWire;\n readonly sport: MemberSportMap;\n readonly activeLeagues: readonly string[] | null;\n readonly email: string | null;\n readonly grantedScopes: readonly string[] | null;\n\n constructor(wire: PartnerMemberWire) {\n this.memberId = wire.memberId;\n this.id = wire.id ?? null;\n this.firstName = wire.firstName;\n this.lastName = wire.lastName;\n this.fullName = wire.fullName;\n this.displayName = wire.displayName;\n this.age = wire.age ?? null;\n this.city = wire.city ?? null;\n this.state = wire.state ?? null;\n this.zip = wire.zip ?? null;\n this.country = wire.country ?? null;\n this.gender = wire.gender ?? null;\n this.status = Object.freeze({ ...wire.status });\n this.sport = new MemberSportMap(wire.sport);\n this.activeLeagues = wire.activeLeagues ? Object.freeze([...wire.activeLeagues]) : null;\n this.email = wire.email ?? null;\n this.grantedScopes = wire.grantedScopes ? Object.freeze([...wire.grantedScopes]) : null;\n Object.freeze(this);\n }\n\n /** Full name — alias for {@link fullName}, matching common usage. */\n get name(): string {\n return this.fullName;\n }\n\n /** The list of sport codes this player has ratings in. */\n get sports(): readonly string[] {\n return [...this.sport.keys()];\n }\n\n /**\n * Primary rating for a given sport.\n *\n * @param sport Sport code — defaults to `'pickleball'`.\n * @returns The primary rating value, or `null` if the player has no\n * ratings for that sport.\n */\n ratingFor(sport = 'pickleball'): number | null {\n return this.sport.get(sport)?.rating ?? null;\n }\n\n /**\n * Get a specific rating split for a sport.\n *\n * @param key Split key (e.g. `'overall-open'`).\n * @param sport Sport code — defaults to `'pickleball'`.\n */\n split(key: string, sport = 'pickleball'): RatingSplitWire | null {\n return this.sport.get(sport)?.get(key) ?? null;\n }\n\n /** Compact summary for console output. */\n toString(): string {\n const primary = this.sport.values().next().value;\n if (primary) {\n return `Member #${this.memberId} '${this.displayName}' rating=${primary.rating.toFixed(\n 3,\n )} ${primary.abbr}`;\n }\n return `Member #${this.memberId} '${this.displayName}'`;\n }\n}\n","/**\n * {@link RatingUpdate} — a single rating change notification.\n *\n * @module\n */\n\nimport type { PartnerRatingUpdateWire, RatingSplitWire } from '../types.js';\n\n/**\n * A single rating change notification.\n *\n * Returned by {@link MembersResource.ratingUpdates} (polling) and\n * delivered via webhook callbacks to partners that have registered a\n * webhook URL and have subscribers.\n *\n * @category Members\n */\nexport class RatingUpdate {\n readonly memberId: number;\n readonly id: string | null;\n readonly displayName: string | null;\n readonly sport: string | null;\n readonly previousRating: number | null;\n readonly newRating: number | null;\n readonly changedAt: string | null;\n readonly ratingSplits: Readonly<Record<string, RatingSplitWire>> | null;\n\n constructor(wire: PartnerRatingUpdateWire) {\n this.memberId = wire.memberId;\n this.id = wire.id ?? null;\n this.displayName = wire.displayName ?? null;\n this.sport = wire.sport ?? null;\n this.previousRating = wire.previousRating ?? null;\n this.newRating = wire.newRating ?? null;\n this.changedAt = wire.changedAt ?? null;\n this.ratingSplits = wire.ratingSplits ? Object.freeze({ ...wire.ratingSplits }) : null;\n Object.freeze(this);\n }\n\n /**\n * Rating change amount — `newRating - previousRating`. Returns `null`\n * if either rating is missing from the update payload.\n */\n get delta(): number | null {\n if (this.previousRating === null || this.newRating === null) {\n return null;\n }\n return this.newRating - this.previousRating;\n }\n\n /** `true` when the new rating is strictly higher than the previous. */\n get improved(): boolean {\n const delta = this.delta;\n return delta !== null && delta > 0;\n }\n\n toString(): string {\n const arrow = this.improved ? '↑' : '↓';\n const prev = this.previousRating !== null ? this.previousRating.toFixed(3) : '?';\n const next = this.newRating !== null ? this.newRating.toFixed(3) : '?';\n const name = this.displayName ? ` '${this.displayName}'` : '';\n return `RatingUpdate #${this.memberId}${name} ${prev} ${arrow} ${next}`;\n }\n}\n","/**\n * {@link MembersResource} — member lookups, search, and rating updates.\n *\n * @module\n */\n\nimport { ValidationError } from '../errors.js';\nimport type { HttpTransport, QueryParams } from '../http.js';\nimport { Member } from '../models/member.js';\nimport { RatingUpdate } from '../models/rating-update.js';\nimport type { PartnerMemberWire, PartnerRatingUpdateWire, SearchFilters } from '../types.js';\n\nconst DEFAULT_PAGE_SIZE = 20;\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Member operations — get a single member, auto-paginating search,\n * find by name, and polling for rating change notifications.\n *\n * @category Resources\n */\nexport class MembersResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * Get a connected member by external ID.\n *\n * **Requires an active OAuth connection** between your partner app\n * and the player. Use the OAuth flow on `client.oauth` first.\n *\n * @param playerId External player ID in `vair_mem_xxx` format.\n * @param options.sport Optional sport filter — single code or list.\n * When omitted, the response contains every sport the player has\n * ratings in.\n * @throws {@link NotFoundError} if the external ID is unknown.\n * @throws {@link VairifiedError} if the player has not connected to\n * your app (403) or the request otherwise fails.\n *\n * @example\n * ```ts\n * const member = await client.members.get('vair_mem_xxx');\n * console.log(member.name, member.ratingFor('pickleball'));\n *\n * // Just pickleball\n * const member2 = await client.members.get('vair_mem_xxx', { sport: 'pickleball' });\n *\n * // Multiple sports\n * const member3 = await client.members.get('vair_mem_xxx', {\n * sport: ['pickleball', 'padel'],\n * });\n * ```\n */\n async get(\n playerId: string,\n options: { sport?: string | readonly string[] } = {},\n ): Promise<Member> {\n const query: Record<string, string> = { memberId: playerId };\n if (options.sport !== undefined) {\n query.sport = Array.isArray(options.sport)\n ? (options.sport as readonly string[]).join(',')\n : (options.sport as string);\n }\n const wire = await this.#http.request<PartnerMemberWire>({\n method: 'GET',\n path: '/partner/member',\n query,\n });\n return new Member(wire);\n }\n\n /**\n * Search for members, yielding each match as a {@link Member}.\n *\n * This is an **auto-paginating async iterator** — it fetches pages\n * from the server lazily as you iterate, so you can stream through\n * thousands of results without holding them all in memory:\n *\n * ```ts\n * for await (const m of client.members.search({ city: 'Austin' })) {\n * console.log(m.name, m.ratingFor('pickleball'));\n * }\n * ```\n *\n * Stop early by `break`-ing out of the loop, or cap the total with\n * `maxResults`.\n */\n async *search(filters: SearchFilters = {}): AsyncGenerator<Member, void, void> {\n const pageSize = Math.min(filters.pageSize ?? DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);\n const maxResults = filters.maxResults;\n\n const baseQuery = buildSearchQuery(filters, pageSize);\n\n let offset = 0;\n let yielded = 0;\n\n while (true) {\n const query: QueryParams = { ...baseQuery, offset };\n const data = await this.#http.request<\n PartnerMemberWire[] | { players?: PartnerMemberWire[] }\n >({ method: 'GET', path: '/partner/search', query });\n\n const batch: PartnerMemberWire[] = Array.isArray(data) ? data : (data?.players ?? []);\n\n if (batch.length === 0) {\n return;\n }\n\n for (const wire of batch) {\n yield new Member(wire);\n yielded += 1;\n if (maxResults !== undefined && yielded >= maxResults) {\n return;\n }\n }\n\n if (batch.length < pageSize) {\n return;\n }\n offset += pageSize;\n }\n }\n\n /**\n * Return the first search hit for a name, or `null`.\n *\n * Convenience for the common \"look up by name\" case:\n *\n * ```ts\n * const mike = await client.members.find('Mike Barker');\n * if (mike) {\n * console.log(mike.ratingFor('pickleball'));\n * }\n * ```\n */\n async find(name: string): Promise<Member | null> {\n for await (const member of this.search({ name, pageSize: 1, maxResults: 1 })) {\n return member;\n }\n return null;\n }\n\n /**\n * Fetch up to 100 members by their member IDs in one call.\n *\n * Unknown IDs are silently omitted — the returned array may be\n * shorter than the input. Results are returned in the same order\n * as the input IDs.\n *\n * @param ids - Array of integer member IDs (max 100).\n * @param options - Optional filters.\n * @param options.sport - Sport code to scope ratings (e.g. `'pickleball'`).\n * @returns Array of {@link Member} instances.\n * @throws {@link ValidationError} If more than 100 IDs are provided.\n * @category Members\n *\n * @example\n * ```ts\n * const members = await client.members.getBulk([4873327, 4873328]);\n * for (const m of members) {\n * console.log(m.name, m.ratingFor('pickleball'));\n * }\n * ```\n */\n async getBulk(ids: number[], options?: { sport?: string }): Promise<Member[]> {\n if (ids.length > 100) {\n throw new ValidationError('Maximum 100 member IDs per request');\n }\n const query: Record<string, string> = { ids: ids.join(',') };\n if (options?.sport) query.sport = options.sport;\n const rows = await this.#http.request<PartnerMemberWire[]>({\n method: 'GET',\n path: '/partner/members',\n query,\n });\n return rows.map((row) => new Member(row));\n }\n\n /**\n * Poll for rating change notifications.\n *\n * Returns a list of {@link RatingUpdate} objects for every player\n * whose rating has changed since the last poll. Members are\n * considered subscribed when they have an active OAuth connection\n * with the `user:webhook:subscribe` scope.\n */\n async ratingUpdates(): Promise<readonly RatingUpdate[]> {\n const data = await this.#http.request<{ updates?: PartnerRatingUpdateWire[] } | unknown>({\n method: 'GET',\n path: '/partner/rating-updates',\n });\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n return [];\n }\n const updates = (data as { updates?: PartnerRatingUpdateWire[] }).updates ?? [];\n return updates.map((wire) => new RatingUpdate(wire));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction buildSearchQuery(filters: SearchFilters, pageSize: number): QueryParams {\n const query: Record<string, string | number | boolean> = {};\n\n if (filters.sport !== undefined) {\n query.sport = Array.isArray(filters.sport)\n ? (filters.sport as readonly string[]).join(',')\n : (filters.sport as string);\n }\n\n if (filters.memberId !== undefined) {\n query.member = String(filters.memberId);\n } else if (filters.name !== undefined) {\n query.member = filters.name;\n }\n\n if (filters.city !== undefined) query.city = filters.city;\n if (filters.state !== undefined) query.state = filters.state;\n if (filters.country !== undefined) query.country = filters.country;\n if (filters.zip !== undefined) query.zip = filters.zip;\n if (filters.location !== undefined) query.location = filters.location;\n\n if (filters.gender !== undefined) {\n query.gender = filters.gender.toUpperCase();\n }\n if (filters.vairifiedOnly !== undefined) query.vairified = filters.vairifiedOnly;\n if (filters.wheelchair !== undefined) query.wheelchair = filters.wheelchair;\n\n if (filters.ratingMin !== undefined) query.rating1 = filters.ratingMin;\n if (filters.ratingMax !== undefined) query.rating2 = filters.ratingMax;\n\n const { ageFilterType, age1, age2 } = resolveAgeFilter(filters);\n if (ageFilterType !== undefined) query.ageFilterType = ageFilterType;\n if (age1 !== undefined) query.age1 = age1;\n if (age2 !== undefined) query.age2 = age2;\n\n if (filters.sortBy !== undefined) query.sortField = filters.sortBy;\n if (filters.sortOrder !== undefined) query.sortDirection = filters.sortOrder;\n\n query.limit = pageSize;\n\n return query;\n}\n\nfunction resolveAgeFilter(filters: SearchFilters): {\n ageFilterType?: string;\n age1?: number;\n age2?: number;\n} {\n if (filters.age !== undefined) {\n return { ageFilterType: 'exact', age1: filters.age };\n }\n if (filters.ageMin !== undefined && filters.ageMax !== undefined) {\n return { ageFilterType: 'range', age1: filters.ageMin, age2: filters.ageMax };\n }\n if (filters.ageMin !== undefined) {\n return { ageFilterType: 'above', age1: filters.ageMin };\n }\n if (filters.ageMax !== undefined) {\n return { ageFilterType: 'below', age1: filters.ageMax };\n }\n return {};\n}\n","/**\n * Vairified OAuth helpers and type definitions.\n *\n * Use the {@link OAuthResource} on `client.oauth` for the full flow —\n * these helpers exist for partners who need to build authorization URLs\n * or validate scopes outside the client (e.g. in a frontend that only\n * handles the redirect step).\n *\n * @module\n */\n\n// ---------------------------------------------------------------------------\n// Scope definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Every OAuth scope the Vairified authorization server accepts.\n *\n * Declaring this as a string union (rather than a free-form `string`)\n * lets TypeScript catch typos at authoring time:\n *\n * ```ts\n * const scopes: OAuthScope[] = ['user:profile:read', 'user:rating:read']; // ok\n * const bad: OAuthScope[] = ['user:profile:read', 'rating']; // type error\n * ```\n *\n * @category OAuth\n */\nexport type OAuthScope =\n | 'user:profile:read'\n | 'user:profile:email'\n | 'user:rating:read'\n | 'user:rating:history'\n | 'user:match:submit'\n | 'user:webhook:subscribe';\n\n/**\n * Human-readable description for every OAuth scope.\n *\n * @category OAuth\n */\nexport const SCOPES: Readonly<Record<OAuthScope, string>> = Object.freeze({\n 'user:profile:read': 'Access your name, location, and verification status',\n 'user:profile:email': 'Access your email address',\n 'user:rating:read': 'View your current rating and rating splits',\n 'user:rating:history': 'View your complete rating history',\n 'user:match:submit': 'Submit match results on your behalf',\n 'user:webhook:subscribe': 'Receive notifications when your rating changes',\n});\n\n/**\n * The scopes automatically requested when none are specified.\n *\n * @category OAuth\n */\nexport const DEFAULT_SCOPES: readonly OAuthScope[] = Object.freeze([\n 'user:profile:read',\n 'user:rating:read',\n]);\n\n// ---------------------------------------------------------------------------\n// OAuth data types\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration for building an authorization URL manually.\n *\n * @category OAuth\n */\nexport interface OAuthConfig {\n readonly apiKey: string;\n readonly redirectUri: string;\n readonly baseUrl?: string;\n /**\n * Your app's `client_id` — the `PartnerApp.slug` Vairified assigned you\n * (e.g. `dinkr`). Required by the browser `GET /partner/oauth/authorize`\n * endpoint to identify your app; without it the authorization page rejects\n * the request with `invalid_request: client_id is required`.\n *\n * Only needed for this pure-frontend URL helper. The recommended flow —\n * {@link OAuthResource.authorize} on a client — identifies your app by the\n * API key instead, so it needs no `client_id`.\n */\n readonly clientId?: string;\n}\n\n/**\n * Response from starting an OAuth authorization flow.\n *\n * @category OAuth\n */\nexport interface AuthorizationResponse {\n readonly authorizationUrl: string;\n readonly code: string;\n readonly state?: string;\n}\n\n/**\n * Response from exchanging an authorization code for tokens.\n *\n * @category OAuth\n */\nexport interface TokenResponse {\n readonly accessToken: string;\n readonly refreshToken: string | null;\n readonly expiresIn: number;\n readonly scope: readonly string[];\n readonly playerId: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helper functions\n// ---------------------------------------------------------------------------\n\n/**\n * Build the URL to redirect users to for OAuth authorization.\n *\n * Prefer {@link OAuthResource.authorize} on a Vairified client — this\n * helper is only useful when you need to construct the URL without\n * making an HTTP call first (for example, in a pure-frontend handoff).\n *\n * @category OAuth\n */\nexport function getAuthorizationUrl(\n config: OAuthConfig,\n options: { scopes?: readonly OAuthScope[]; state?: string } = {},\n): string {\n const baseUrl = (config.baseUrl ?? 'https://api-next.vairified.com/api/v1').replace(/\\/+$/, '');\n const scopeList = ensureProfileRead(options.scopes ?? DEFAULT_SCOPES);\n\n // Scope is space-delimited per RFC 6749 §3.3 — the deployed authorization\n // server splits on whitespace, not commas.\n const params = new URLSearchParams({\n redirect_uri: config.redirectUri,\n scope: scopeList.join(' '),\n response_type: 'code',\n });\n // `client_id` (the PartnerApp slug) identifies the app to the browser\n // authorize endpoint; the URL is rejected without it.\n if (config.clientId) {\n params.set('client_id', config.clientId);\n }\n if (options.state) {\n params.set('state', options.state);\n }\n\n return `${baseUrl}/partner/oauth/authorize?${params.toString()}`;\n}\n\n/**\n * Check whether a scope string is one the Vairified server accepts.\n *\n * @category OAuth\n */\nexport function validateScope(scope: string): scope is OAuthScope {\n return scope in SCOPES;\n}\n\n/**\n * Get a human-readable description of an OAuth scope.\n *\n * Returns `\"Unknown scope: {scope}\"` for unrecognized scopes so this\n * function is safe to call on user-supplied input.\n *\n * @category OAuth\n */\nexport function describeScope(scope: string): string {\n if (validateScope(scope)) {\n return SCOPES[scope];\n }\n return `Unknown scope: ${scope}`;\n}\n\n/**\n * Describe multiple scopes at once.\n *\n * @category OAuth\n */\nexport function describeScopes(\n scopes: readonly string[],\n): readonly { scope: string; description: string }[] {\n return scopes.map((scope) => ({\n scope,\n description: describeScope(scope),\n }));\n}\n\n/**\n * Generate a cryptographically-random CSRF state token suitable for\n * use with {@link OAuthResource.authorize}.\n *\n * Uses the Web Crypto API (available in Node 19+ and all modern\n * browsers). The returned string is URL-safe base64 of 32 random bytes.\n *\n * @category OAuth\n */\nexport function generateState(): string {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers (used by resources/oauth.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure `user:profile:read` is in the scope list, prepending if necessary.\n *\n * @internal\n */\nexport function ensureProfileRead(scopes: readonly OAuthScope[]): readonly OAuthScope[] {\n if (scopes.includes('user:profile:read')) {\n return scopes;\n }\n return ['user:profile:read', ...scopes];\n}\n","/**\n * {@link OAuthResource} — OAuth 2.0 flow for player consent.\n *\n * @module\n */\n\nimport { OAuthError } from '../errors.js';\nimport type { HttpTransport } from '../http.js';\nimport {\n type AuthorizationResponse,\n DEFAULT_SCOPES,\n ensureProfileRead,\n type OAuthScope,\n SCOPES,\n type TokenResponse,\n} from '../oauth.js';\n\n/**\n * OAuth 2.0 flow for obtaining player consent.\n *\n * Typical flow:\n *\n * 1. {@link authorize} — start an authorization, get a URL to redirect\n * the player to.\n * 2. Player approves on the Vairified site and is redirected back to\n * your `redirectUri` with a `code` query parameter.\n * 3. {@link exchangeToken} — swap the code for access and refresh\n * tokens plus the player's external ID.\n * 4. Store the refresh token and call {@link refresh} when the access\n * token expires.\n * 5. {@link revoke} — disconnect a player from your app.\n *\n * @category Resources\n */\nexport class OAuthResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * Start an OAuth authorization flow.\n *\n * @throws {@link OAuthError} with `errorCode: 'invalid_scope'` if a\n * requested scope is not in the accepted list.\n */\n async authorize(options: {\n redirectUri: string;\n scopes?: readonly OAuthScope[];\n state?: string;\n }): Promise<AuthorizationResponse> {\n const scopeList = ensureProfileRead(options.scopes ?? DEFAULT_SCOPES);\n\n for (const scope of scopeList) {\n if (!(scope in SCOPES)) {\n throw new OAuthError(`Invalid scope: ${scope}`, 'invalid_scope');\n }\n }\n\n const data = await this.#http.request<{\n authorization_url?: string;\n code?: string;\n }>({\n method: 'POST',\n path: '/partner/oauth/authorize',\n body: {\n redirect_uri: options.redirectUri,\n scope: scopeList.join(' '),\n state: options.state,\n },\n });\n\n return {\n authorizationUrl: data?.authorization_url ?? '',\n code: data?.code ?? '',\n state: options.state,\n };\n }\n\n /** Exchange an authorization code for access and refresh tokens. */\n async exchangeToken(options: { code: string; redirectUri: string }): Promise<TokenResponse> {\n const data = await this.#http.request<Record<string, unknown>>({\n method: 'POST',\n path: '/partner/oauth/token',\n // RFC 6749 §4.1.3 — the endpoint requires `grant_type` and the\n // snake_case `redirect_uri` (which must match the authorize request).\n body: {\n grant_type: 'authorization_code',\n code: options.code,\n redirect_uri: options.redirectUri,\n },\n });\n return tokenResponseFromWire(data);\n }\n\n /** Refresh an expired access token using a refresh token. */\n async refresh(refreshToken: string): Promise<TokenResponse> {\n const data = await this.#http.request<Record<string, unknown>>({\n method: 'POST',\n path: '/partner/oauth/refresh',\n // RFC 6749 §6 — refresh grant, snake_case body.\n body: { grant_type: 'refresh_token', refresh_token: refreshToken },\n });\n return tokenResponseFromWire(data);\n }\n\n /** Revoke a player's OAuth connection to your app. */\n async revoke(playerId: string): Promise<Record<string, unknown>> {\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'POST',\n path: '/partner/oauth/revoke',\n body: { player_id: playerId },\n });\n return data ?? {};\n }\n\n /** Return the list of OAuth scopes the server currently supports. */\n async availableScopes(): Promise<readonly { name: string; description: string }[]> {\n const data = await this.#http.request<\n { scopes?: { name: string; description: string }[] } | unknown\n >({\n method: 'GET',\n path: '/partner/oauth/scopes',\n });\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n return [];\n }\n return (data as { scopes?: { name: string; description: string }[] }).scopes ?? [];\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction tokenResponseFromWire(data: Record<string, unknown> | undefined): TokenResponse {\n // The API returns `scope` as a space-delimited string (RFC 6749 §3.3).\n // Fall back to the deprecated `scopes` array for older API builds.\n const scopeRaw = (data?.scope ?? '') as string;\n const scopeList =\n scopeRaw.length > 0\n ? scopeRaw.split(/\\s+/).filter(Boolean)\n : Array.isArray(data?.scopes)\n ? (data.scopes as string[])\n : [];\n return {\n accessToken: (data?.access_token ?? '') as string,\n refreshToken: (data?.refresh_token ?? null) as string | null,\n expiresIn: (data?.expires_in ?? 3600) as number,\n scope: Object.freeze(scopeList),\n playerId: (data?.player_id ?? '') as string,\n };\n}\n","/**\n * {@link WebhookDelivery} and {@link WebhookDeliveriesResult} — webhook\n * delivery inspection models.\n *\n * @module\n */\n\nimport type { WebhookDeliveriesResultWire, WebhookDeliveryWire } from '../types.js';\n\n/**\n * A single webhook delivery attempt.\n *\n * @category Webhooks\n */\nexport class WebhookDelivery {\n readonly id: string;\n readonly event: string;\n readonly url: string;\n readonly statusCode: number | null;\n readonly responseBody: string | null;\n readonly errorMessage: string | null;\n readonly attempts: number;\n readonly maxAttempts: number;\n readonly lastAttemptAt: string;\n readonly nextRetryAt: string | null;\n readonly completedAt: string | null;\n readonly createdAt: string;\n readonly payload: Readonly<Record<string, unknown>>;\n\n /** @internal */\n constructor(wire: WebhookDeliveryWire) {\n this.id = wire.id;\n this.event = wire.event;\n this.url = wire.url;\n this.statusCode = wire.statusCode;\n this.responseBody = wire.responseBody;\n this.errorMessage = wire.errorMessage;\n this.attempts = wire.attempts;\n this.maxAttempts = wire.maxAttempts;\n this.lastAttemptAt = wire.lastAttemptAt;\n this.nextRetryAt = wire.nextRetryAt;\n this.completedAt = wire.completedAt;\n this.createdAt = wire.createdAt;\n this.payload = Object.freeze({ ...wire.payload });\n Object.freeze(this);\n }\n\n /** Whether delivery completed successfully (2xx status). */\n get succeeded(): boolean {\n return (\n this.completedAt != null &&\n this.statusCode != null &&\n this.statusCode >= 200 &&\n this.statusCode < 300\n );\n }\n\n /** Whether delivery failed definitively (completed with non-2xx). */\n get failed(): boolean {\n return this.completedAt != null && !this.succeeded;\n }\n}\n\n/**\n * Paginated list of webhook delivery attempts.\n *\n * @category Webhooks\n */\nexport class WebhookDeliveriesResult {\n readonly deliveries: readonly WebhookDelivery[];\n readonly total: number;\n\n /** @internal */\n constructor(wire: WebhookDeliveriesResultWire) {\n this.deliveries = Object.freeze(wire.deliveries.map((d) => new WebhookDelivery(d)));\n this.total = wire.total;\n Object.freeze(this);\n }\n}\n","/**\n * {@link WebhooksResource} — webhook delivery inspection.\n *\n * @module\n */\n\nimport type { HttpTransport } from '../http.js';\nimport { WebhookDeliveriesResult } from '../models/webhook-delivery.js';\nimport type { WebhookDeliveriesResultWire } from '../types.js';\n\n/**\n * Webhook delivery inspection.\n *\n * @category Resources\n */\nexport class WebhooksResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * List recent webhook delivery attempts.\n *\n * @param options - Optional filters and pagination.\n * @param options.event - Filter by event type (e.g. `'rating.updated'`).\n * @param options.status - Filter: `'all'`, `'pending'`, `'success'`, or `'failed'`.\n * @param options.limit - Results per page (1-100, default 20).\n * @param options.offset - Pagination offset.\n * @returns {@link WebhookDeliveriesResult} with entries and total.\n * @category Webhooks\n *\n * @example\n * ```ts\n * const result = await client.webhooks.deliveries({ status: 'failed' });\n * for (const d of result.deliveries) {\n * console.log(d.event, d.statusCode, d.errorMessage);\n * }\n * ```\n */\n async deliveries(options?: {\n event?: string;\n status?: 'all' | 'pending' | 'success' | 'failed';\n limit?: number;\n offset?: number;\n }): Promise<WebhookDeliveriesResult> {\n const query: Record<string, string | number> = {};\n if (options?.event) query.event = options.event;\n if (options?.status) query.status = options.status;\n if (options?.limit != null) query.limit = options.limit;\n if (options?.offset != null) query.offset = options.offset;\n const data = await this.#http.request<WebhookDeliveriesResultWire>({\n method: 'GET',\n path: '/partner/webhook-deliveries',\n query,\n });\n return new WebhookDeliveriesResult(data);\n }\n}\n","/**\n * {@link Vairified} — the main entry point of the SDK.\n *\n * @module\n */\n\nimport { HttpTransport } from './http.js';\nimport {\n LeaderboardResource,\n MatchesResource,\n MembersResource,\n OAuthResource,\n WebhooksResource,\n} from './resources/index.js';\nimport type { VairifiedEnvironment, VairifiedOptions } from './types.js';\n\n/**\n * Environment preset → base URL mapping.\n *\n * Partners can switch between production, staging, and local development\n * without memorizing hostnames.\n *\n * @category Client\n */\nexport const ENVIRONMENTS: Readonly<Record<VairifiedEnvironment, string>> = Object.freeze({\n production: 'https://api-next.vairified.com/api/v1',\n staging: 'https://api-staging.vairified.com/api/v1',\n local: 'http://localhost:3001/api/v1',\n});\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Async client for the Vairified Partner API.\n *\n * The client is organized around sub-resources that mirror the REST\n * structure — {@link members}, {@link matches}, {@link oauth},\n * {@link leaderboard}. Each sub-resource is a thin wrapper around the\n * HTTP transport on this object.\n *\n * ## Lifecycle\n *\n * The client holds no persistent connections itself — it's safe to\n * create one per request if you want. But for typical usage, wrap it\n * in `await using` so resources are cleaned up deterministically:\n *\n * ```ts\n * await using client = new Vairified({ apiKey: 'vair_pk_xxx' });\n *\n * const member = await client.members.get('vair_mem_xxx');\n * console.log(member.name, member.ratingFor('pickleball'));\n *\n * for await (const m of client.members.search({ city: 'Austin' })) {\n * console.log(m.name);\n * }\n * ```\n *\n * `await using` requires TypeScript 5.2+ and Node 20+. If you can't\n * use it, just call `await client.close()` manually when you're done.\n *\n * @category Client\n */\nexport class Vairified {\n /** The resolved API key this client is using. */\n readonly apiKey: string;\n /** The resolved base URL (production, staging, local, or custom). */\n readonly baseUrl: string;\n /** The resolved environment name. */\n readonly env: VairifiedEnvironment;\n /** Request timeout in milliseconds. */\n readonly timeoutMs: number;\n\n /** Member operations — get, search, find, ratingUpdates. */\n readonly members: MembersResource;\n /** Match submission — submit, testWebhook. */\n readonly matches: MatchesResource;\n /** OAuth flow — authorize, exchangeToken, refresh, revoke. */\n readonly oauth: OAuthResource;\n /** Leaderboard queries — list, rank, categories. */\n readonly leaderboard: LeaderboardResource;\n /** Webhook delivery inspection — deliveries. */\n readonly webhooks: WebhooksResource;\n\n readonly #transport: HttpTransport;\n\n constructor(options: VairifiedOptions = {}) {\n const apiKey = options.apiKey ?? process.env.VAIRIFIED_API_KEY ?? '';\n if (apiKey.length === 0) {\n throw new Error('API key required. Pass { apiKey } or set VAIRIFIED_API_KEY.');\n }\n this.apiKey = apiKey;\n\n if (options.baseUrl) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n this.env = options.env ?? 'production';\n } else {\n const envName = (options.env ??\n (process.env.VAIRIFIED_ENV as VairifiedEnvironment | undefined) ??\n 'production') as VairifiedEnvironment;\n if (options.env && !(envName in ENVIRONMENTS)) {\n throw new Error(\n `Unknown environment: ${envName}. Use one of: ${Object.keys(ENVIRONMENTS).join(', ')}`,\n );\n }\n this.env = envName;\n this.baseUrl = ENVIRONMENTS[envName] ?? ENVIRONMENTS.production;\n }\n\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n this.#transport = new HttpTransport({\n baseUrl: this.baseUrl,\n apiKey: this.apiKey,\n timeoutMs: this.timeoutMs,\n fetch: options.fetch ?? fetch,\n });\n\n this.members = new MembersResource(this.#transport);\n this.matches = new MatchesResource(this.#transport);\n this.oauth = new OAuthResource(this.#transport);\n this.leaderboard = new LeaderboardResource(this.#transport);\n this.webhooks = new WebhooksResource(this.#transport);\n }\n\n /**\n * API usage statistics for the current API key.\n *\n * Returns rate-limit status, request counts, and quota usage.\n */\n async usage(): Promise<Record<string, unknown>> {\n const data = await this.#transport.request<Record<string, unknown> | undefined>({\n method: 'GET',\n path: '/partner/usage',\n });\n return data ?? {};\n }\n\n /**\n * Release any resources held by the client.\n *\n * The current transport is stateless, so this is a no-op today, but\n * partners should still call it (or use `await using`) so the SDK\n * can add connection pooling later without breaking them.\n */\n async close(): Promise<void> {\n // Nothing to release today. Kept as an explicit hook so future\n // transports (keep-alive, HTTP/2) can release their pools.\n }\n\n /**\n * Explicit resource management hook — enables\n * `await using client = new Vairified({ ... })` (TypeScript 5.2+).\n */\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close();\n }\n\n /** Compact summary for console output. */\n toString(): string {\n return `Vairified { env: '${this.env}', baseUrl: '${this.baseUrl}' }`;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/leaderboard.ts","../src/models/match-batch-result.ts","../src/models/tournament-import-result.ts","../src/resources/matches.ts","../src/models/sport-rating.ts","../src/models/member.ts","../src/models/rating-update.ts","../src/resources/members.ts","../src/oauth.ts","../src/resources/oauth.ts","../src/models/webhook-delivery.ts","../src/resources/webhooks.ts","../src/client.ts"],"sourcesContent":["/**\n * Vairified SDK — Partner API v1.\n *\n * The Vairified Partner API lets you read player ratings, submit match\n * results, and subscribe to rating change notifications for\n * integrations in leagues, tournaments, and club-management software.\n *\n * ```ts\n * import { Vairified } from 'vairified';\n *\n * await using client = new Vairified({ apiKey: 'vair_pk_xxx' });\n *\n * // Look up a connected player\n * const member = await client.members.get('vair_mem_xxx');\n * console.log(member.name, member.ratingFor('pickleball'));\n *\n * // Auto-paginating search\n * for await (const player of client.members.search({ city: 'Austin' })) {\n * console.log(player.displayName);\n * }\n *\n * // Submit a bulk match batch\n * const result = await client.matches.submit({\n * sport: 'pickleball',\n * winScore: 11,\n * winBy: 2,\n * bracket: '4.0 Doubles',\n * event: 'Weekly League',\n * matchDate: '2026-04-11T14:00:00Z',\n * matches: [\n * {\n * identifier: 'm1',\n * teams: [['vair_mem_aaa', 'vair_mem_bbb'],\n * ['vair_mem_ccc', 'vair_mem_ddd']],\n * games: [{ scores: [11, 8] }, { scores: [11, 5] }],\n * },\n * ],\n * });\n * console.log(`Submitted ${result.numGames} games`);\n * ```\n *\n * See https://vairified.github.io/vairified.js for full documentation.\n *\n * @packageDocumentation\n * @module vairified\n */\n\n// ---- Client ----\nexport { ENVIRONMENTS, Vairified } from './client.js';\n// ---- Error classes ----\nexport {\n AuthenticationError,\n NotFoundError,\n OAuthError,\n RateLimitError,\n VairifiedError,\n ValidationError,\n} from './errors.js';\n\n// ---- Response models ----\nexport {\n MatchBatchResult,\n Member,\n MemberSportMap,\n RatingUpdate,\n SportRating,\n TournamentImportResult,\n WebhookDeliveriesResult,\n WebhookDelivery,\n} from './models/index.js';\nexport type {\n AuthorizationResponse,\n OAuthConfig,\n OAuthScope,\n TokenResponse,\n} from './oauth.js';\n// ---- OAuth helpers ----\nexport {\n DEFAULT_SCOPES,\n describeScope,\n describeScopes,\n generateState,\n getAuthorizationUrl,\n SCOPES,\n validateScope,\n} from './oauth.js';\n// ---- Resource classes (typically accessed via client.*) ----\nexport {\n LeaderboardResource,\n MatchesResource,\n MembersResource,\n OAuthResource,\n WebhooksResource,\n} from './resources/index.js';\n// ---- Types (request shapes + wire types) ----\nexport type {\n ApiErrorResponse,\n GameInput,\n Gender,\n LeaderboardOptions,\n MatchBatch,\n MatchBatchResultWire,\n MatchInput,\n MemberStatusWire,\n PartnerMemberWire,\n PartnerRatingUpdateWire,\n PlayerRankOptions,\n RatingSplitWire,\n SearchFilters,\n SportRatingWire,\n TournamentImportResultWire,\n VairifiedEnvironment,\n VairifiedOptions,\n WebhookDeliveriesResultWire,\n WebhookDeliveryWire,\n} from './types.js';\n","/**\n * Vairified SDK — error hierarchy.\n *\n * All SDK errors inherit from {@link VairifiedError}, so a single\n * `catch (err: unknown) { if (err instanceof VairifiedError) ... }`\n * covers everything. HTTP-status-specific subclasses (auth, not found,\n * rate limit, validation) are thrown automatically by the HTTP layer.\n *\n * @module\n */\n\n/**\n * Base class for every error thrown by the Vairified SDK.\n *\n * @category Errors\n */\nexport class VairifiedError extends Error {\n /** HTTP status code (if the error came from an API response). */\n readonly statusCode?: number;\n /** Raw response body parsed as JSON when available. */\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = 'VairifiedError';\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/**\n * Thrown on HTTP 429 responses. Carries the `Retry-After` header value\n * when the server provides one.\n *\n * @category Errors\n */\nexport class RateLimitError extends VairifiedError {\n /** Seconds to wait before retrying, or `undefined` if the server didn't say. */\n readonly retryAfter?: number;\n\n constructor(message = 'Rate limit exceeded', retryAfter?: number, response?: unknown) {\n super(message, 429, response);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Thrown on HTTP 401 — invalid or missing API key.\n *\n * @category Errors\n */\nexport class AuthenticationError extends VairifiedError {\n constructor(message = 'Invalid API key', response?: unknown) {\n super(message, 401, response);\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown on HTTP 404 — the resource doesn't exist.\n *\n * @category Errors\n */\nexport class NotFoundError extends VairifiedError {\n constructor(message = 'Resource not found', response?: unknown) {\n super(message, 404, response);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Thrown on HTTP 400 — the server rejected the request payload.\n *\n * Inspect {@link VairifiedError.response} for field-level details.\n *\n * @category Errors\n */\nexport class ValidationError extends VairifiedError {\n constructor(message = 'Validation error', response?: unknown) {\n super(message, 400, response);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Thrown by {@link OAuthResource} methods when authorization, token\n * exchange, refresh, or revocation fails.\n *\n * @category Errors\n */\nexport class OAuthError extends VairifiedError {\n /**\n * OAuth error code such as `'invalid_grant'`, `'invalid_scope'`,\n * or `'expired_token'`. Check this to branch on the specific failure.\n */\n readonly errorCode?: string;\n\n constructor(message = 'OAuth error', errorCode?: string, response?: unknown) {\n super(message, undefined, response);\n this.name = 'OAuthError';\n this.errorCode = errorCode;\n }\n}\n","/**\n * HTTP transport — internal. Not part of the public API.\n *\n * The transport is a thin wrapper around native `fetch` that:\n *\n * - Injects the API key header on every request.\n * - Serializes query params (dropping `undefined`) and JSON bodies.\n * - Applies a request timeout via `AbortController`.\n * - Maps non-2xx responses to the right typed exception.\n *\n * @internal\n * @module\n */\n\nimport {\n AuthenticationError,\n NotFoundError,\n RateLimitError,\n VairifiedError,\n ValidationError,\n} from './errors.js';\nimport type { ApiErrorResponse } from './types.js';\n\n/**\n * Values accepted as query parameters.\n *\n * `null` and `undefined` are silently dropped. Arrays are joined with\n * `','`. Everything else is stringified.\n *\n * @internal\n */\nexport type QueryParams = Readonly<\n Record<string, string | number | boolean | readonly (string | number)[] | null | undefined>\n>;\n\n/**\n * Options passed to the internal HTTP layer.\n *\n * @internal\n */\nexport interface RequestOptions {\n readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n readonly path: string;\n readonly query?: QueryParams;\n readonly body?: unknown;\n}\n\n/**\n * Transport configuration.\n *\n * @internal\n */\nexport interface TransportConfig {\n readonly baseUrl: string;\n readonly apiKey: string;\n readonly timeoutMs: number;\n readonly fetch: typeof fetch;\n}\n\n/**\n * Internal HTTP client. Holds no state between requests — each call\n * builds a fresh `Request`, runs it, and returns the parsed body.\n *\n * @internal\n */\nexport class HttpTransport {\n readonly #config: TransportConfig;\n\n constructor(config: TransportConfig) {\n this.#config = config;\n }\n\n async request<T>(options: RequestOptions): Promise<T> {\n const url = buildUrl(this.#config.baseUrl, options.path, options.query);\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new Error(`Request timed out after ${this.#config.timeoutMs}ms`)),\n this.#config.timeoutMs,\n );\n\n const headers: Record<string, string> = {\n 'X-API-Key': this.#config.apiKey,\n Accept: 'application/json',\n };\n\n const init: RequestInit = {\n method: options.method,\n headers,\n signal: controller.signal,\n };\n\n if (options.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(options.body);\n }\n\n let response: Response;\n try {\n response = await this.#config.fetch(url, init);\n } finally {\n clearTimeout(timeoutId);\n }\n\n if (!response.ok) {\n await throwFromResponse(response);\n }\n\n if (response.status === 204 || response.headers.get('content-length') === '0') {\n return undefined as T;\n }\n\n const text = await response.text();\n if (text.length === 0) {\n return undefined as T;\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new VairifiedError(`Unable to parse response as JSON: ${text}`, response.status);\n }\n }\n}\n\n/**\n * Build a full URL from a base and relative path, appending query params.\n *\n * @internal\n */\nexport function buildUrl(baseUrl: string, path: string, query?: QueryParams): string {\n const cleanBase = baseUrl.replace(/\\/+$/, '');\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(cleanBase + cleanPath);\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === null || value === undefined) continue;\n if (Array.isArray(value)) {\n if (value.length === 0) continue;\n url.searchParams.set(key, value.join(','));\n } else {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n}\n\n/**\n * Parse an error response and throw the right typed exception.\n *\n * @internal\n */\nasync function throwFromResponse(response: Response): Promise<never> {\n const status = response.status;\n const text = await response.text().catch(() => '');\n\n let body: ApiErrorResponse | unknown = null;\n if (text.length > 0) {\n try {\n body = JSON.parse(text);\n } catch {\n body = null;\n }\n }\n\n let message: string;\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n const apiBody = body as ApiErrorResponse;\n message = apiBody.message || apiBody.error || text || `HTTP ${status}`;\n } else {\n message = text || `HTTP ${status}`;\n }\n\n switch (status) {\n case 400:\n throw new ValidationError(message, body);\n case 401:\n throw new AuthenticationError(message, body);\n case 404:\n throw new NotFoundError(message, body);\n case 429: {\n const retryAfterHeader = response.headers.get('Retry-After');\n const retryAfter = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : undefined;\n throw new RateLimitError(message, Number.isFinite(retryAfter) ? retryAfter : undefined, body);\n }\n default:\n throw new VairifiedError(message, status, body);\n }\n}\n","/**\n * {@link LeaderboardResource} — read-only leaderboard queries.\n *\n * @module\n */\n\nimport type { HttpTransport, QueryParams } from '../http.js';\nimport type { LeaderboardOptions, PlayerRankOptions } from '../types.js';\n\n/**\n * Read-only leaderboard queries.\n *\n * @category Resources\n */\nexport class LeaderboardResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /** Fetch a leaderboard page with optional filters. */\n async list(options: LeaderboardOptions = {}): Promise<Record<string, unknown>> {\n const query: QueryParams = {\n limit: options.limit ?? 50,\n offset: options.offset ?? 0,\n category: options.category,\n ageBracket: options.ageBracket,\n scope: options.scope,\n state: options.state,\n city: options.city,\n clubId: options.clubId,\n gender: options.gender?.toUpperCase(),\n minGames: options.minGames,\n search: options.search,\n verifiedOnly: options.verifiedOnly === true ? true : undefined,\n };\n\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'GET',\n path: '/leaderboard',\n query,\n });\n return data ?? {};\n }\n\n /** Fetch a specific player's rank plus nearby players. */\n async rank(playerId: string, options: PlayerRankOptions = {}): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = {\n playerId,\n category: options.category ?? 'doubles',\n ageBracket: options.ageBracket ?? 'open',\n scope: options.scope ?? 'global',\n contextSize: options.contextSize ?? 5,\n };\n if (options.state !== undefined) body.state = options.state;\n if (options.city !== undefined) body.city = options.city;\n if (options.clubId !== undefined) body.clubId = options.clubId;\n\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'POST',\n path: '/leaderboard/rank',\n body,\n });\n return data ?? {};\n }\n\n /** List available leaderboard categories, brackets, and scopes. */\n async categories(): Promise<Record<string, unknown>> {\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'GET',\n path: '/leaderboard/categories',\n });\n return data ?? {};\n }\n}\n","/**\n * {@link MatchBatchResult} — result of a batch match submission.\n *\n * @module\n */\n\nimport type { MatchBatchResultWire } from '../types.js';\n\n/**\n * Result of a {@link MatchesResource.submit} call.\n *\n * {@link success} is `true` only when every match in the batch was\n * accepted. Check {@link errors} for per-match validation failures.\n *\n * @category Matches\n */\nexport class MatchBatchResult {\n readonly success: boolean;\n readonly numMatches: number;\n readonly numGames: number;\n readonly dryRun: boolean | null;\n readonly message: string | null;\n readonly errors: readonly string[] | null;\n\n constructor(wire: MatchBatchResultWire) {\n this.success = wire.success;\n this.numMatches = wire.numMatches;\n this.numGames = wire.numGames;\n this.dryRun = wire.dryRun ?? null;\n this.message = wire.message ?? null;\n this.errors = wire.errors ? Object.freeze([...wire.errors]) : null;\n Object.freeze(this);\n }\n\n /** Shorthand: successful submission with zero errors. */\n get ok(): boolean {\n return this.success && (this.errors === null || this.errors.length === 0);\n }\n\n /** Whether this was a dry-run (validation only, nothing persisted). */\n get isDryRun(): boolean {\n return this.dryRun === true;\n }\n\n toString(): string {\n const mode = this.isDryRun ? ' [dry-run]' : '';\n const errs = this.errors && this.errors.length > 0 ? ` errors=${this.errors.length}` : '';\n const status = this.ok ? 'ok' : 'FAILED';\n return `MatchBatchResult ${status}${mode} matches=${this.numMatches} games=${this.numGames}${errs}`;\n }\n}\n","/**\n * {@link TournamentImportResult} — result of a tournament import submission.\n *\n * @module\n */\n\nimport type { TournamentImportResultWire } from '../types.js';\n\n/**\n * Result of a tournament import submission.\n *\n * @category Matches\n */\nexport class TournamentImportResult {\n readonly success: boolean;\n readonly matchesImported: number;\n readonly gamesRecorded: number;\n readonly ghostPlayersCreated: number;\n readonly existingPlayersMatched: number;\n readonly dryRun: boolean;\n readonly message: string | undefined;\n readonly errors: readonly string[];\n\n /** @internal */\n constructor(wire: TournamentImportResultWire) {\n this.success = wire.success;\n this.matchesImported = wire.matchesImported;\n this.gamesRecorded = wire.gamesRecorded;\n this.ghostPlayersCreated = wire.ghostPlayersCreated;\n this.existingPlayersMatched = wire.existingPlayersMatched;\n this.dryRun = wire.dryRun ?? false;\n this.message = wire.message;\n this.errors = Object.freeze(wire.errors ?? []);\n Object.freeze(this);\n }\n\n /** True when the import succeeded without errors. */\n get ok(): boolean {\n return this.success && this.errors.length === 0;\n }\n}\n","/**\n * {@link MatchesResource} — bulk match submission.\n *\n * @module\n */\n\nimport type { HttpTransport } from '../http.js';\nimport { MatchBatchResult } from '../models/match-batch-result.js';\nimport { TournamentImportResult } from '../models/tournament-import-result.js';\nimport type { MatchBatch, MatchBatchResultWire, TournamentImportResultWire } from '../types.js';\n\n/**\n * Match submission — one call submits a full batch.\n *\n * @category Resources\n */\nexport class MatchesResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * Submit a {@link MatchBatch} for rating calculation.\n *\n * All players in every match must have granted the `user:match:submit`\n * scope via OAuth (unless your API key has the\n * `user:match:submit:trusted` scope, which skips per-player consent).\n *\n * Set `batch.dryRun = true` to validate without persisting.\n *\n * ```ts\n * const result = await client.matches.submit({\n * sport: 'pickleball',\n * winScore: 11,\n * winBy: 2,\n * bracket: '4.0 Doubles',\n * event: 'Weekly League',\n * matchDate: '2026-04-11T14:00:00Z',\n * matches: [\n * {\n * identifier: 'm1',\n * teams: [['vair_mem_aaa', 'vair_mem_bbb'],\n * ['vair_mem_ccc', 'vair_mem_ddd']],\n * games: [{ scores: [11, 8] }, { scores: [11, 5] }],\n * },\n * ],\n * });\n * if (result.ok) {\n * console.log(`Submitted ${result.numGames} games`);\n * }\n * ```\n */\n async submit(batch: MatchBatch): Promise<MatchBatchResult> {\n const wire = await this.#http.request<MatchBatchResultWire>({\n method: 'POST',\n path: '/partner/matches',\n body: batch,\n });\n return new MatchBatchResult(wire);\n }\n\n /**\n * Import tournament results.\n *\n * The request body is a free-form JSON object whose structure is\n * defined by the Vairified tournament import schema. Set\n * `body.dryRun = true` to validate without persisting.\n *\n * @param body - Tournament import payload.\n * @returns {@link TournamentImportResult} with match/game counts.\n * @category Matches\n *\n * @example\n * ```ts\n * const result = await client.matches.tournamentImport({\n * sport: 'pickleball',\n * tournamentName: 'Spring Classic',\n * matches: [...],\n * });\n * if (result.ok) {\n * console.log(`Imported ${result.matchesImported} matches`);\n * }\n * ```\n */\n async tournamentImport(body: Record<string, unknown>): Promise<TournamentImportResult> {\n const wire = await this.#http.request<TournamentImportResultWire>({\n method: 'POST',\n path: '/partner/tournament-import',\n body,\n });\n return new TournamentImportResult(wire);\n }\n\n /** Send a test payload to a webhook URL. */\n async testWebhook(webhookUrl: string): Promise<Record<string, unknown>> {\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'POST',\n path: '/partner/webhook-test',\n body: { webhookUrl },\n });\n return data ?? {};\n }\n}\n","/**\n * {@link SportRating} — a player's ratings for one sport.\n *\n * @module\n */\n\nimport type { RatingSplitWire, SportRatingWire, VairProStatus } from '../types.js';\n\n/**\n * A player's ratings for a single sport.\n *\n * The top-level `rating` / `abbr` is the primary rating for that sport\n * (conventionally the overall-open bracket). Every category × age\n * bracket the player has played is also available via {@link get},\n * {@link has}, subscript-style access, and iteration.\n *\n * ```ts\n * const pb = member.sport.get('pickleball');\n * if (pb) {\n * console.log(pb.rating, pb.abbr); // 3.915 VO\n * console.log(pb.get('overall-open')?.rating); // 3.915\n * console.log(pb.has('singles-40+')); // false\n * console.log(pb.size); // 3\n * for (const [key, split] of pb) {\n * console.log(key, split.rating);\n * }\n * }\n * ```\n *\n * @category Members\n */\nexport class SportRating {\n /** Primary rating for this sport. */\n readonly rating: number;\n /** Category abbreviation for the primary rating (e.g. `'VO'`). */\n readonly abbr: string;\n\n /** Player is VAIRified in this sport (has a verified, non-recreational rating). */\n readonly isVairified: boolean;\n /** Player is an active VAIR Pro (can rate) in this sport. Alias of {@link isVairPro}. */\n readonly isRater: boolean;\n /** Player is an active VAIR Pro (can rate) in this sport. */\n readonly isVairPro: boolean;\n /** VAIR-Pro lifecycle status in this sport (`'ACTIVE'` / `'PENDING'` / `null`). */\n readonly isVairProStatus: VairProStatus;\n\n readonly #splits: ReadonlyMap<string, RatingSplitWire>;\n\n constructor(wire: SportRatingWire) {\n this.rating = wire.rating;\n this.abbr = wire.abbr;\n this.isVairified = wire.isVairified ?? false;\n this.isRater = wire.isRater ?? false;\n this.isVairPro = wire.isVairPro ?? false;\n this.isVairProStatus = wire.isVairProStatus ?? null;\n this.#splits = new Map(Object.entries(wire.ratingSplits ?? {}));\n Object.freeze(this);\n }\n\n /**\n * Look up a rating split by key (e.g. `'overall-open'`,\n * `'singles-12-13'`, `'gender-40+'`). Returns `undefined` if the\n * player has no rating for that bracket.\n */\n get(key: string): RatingSplitWire | undefined {\n return this.#splits.get(key);\n }\n\n /** Whether the player has a rating for the given split key. */\n has(key: string): boolean {\n return this.#splits.has(key);\n }\n\n /** Number of rating splits. */\n get size(): number {\n return this.#splits.size;\n }\n\n /** All split keys the player has ratings for. */\n keys(): IterableIterator<string> {\n return this.#splits.keys();\n }\n\n /** All rating splits the player has. */\n values(): IterableIterator<RatingSplitWire> {\n return this.#splits.values();\n }\n\n /** `[key, split]` pairs for every rating split. */\n entries(): IterableIterator<[string, RatingSplitWire]> {\n return this.#splits.entries();\n }\n\n /**\n * `for (const [key, split] of sportRating) { ... }` — iterate every\n * rating split the player has in this sport.\n */\n [Symbol.iterator](): IterableIterator<[string, RatingSplitWire]> {\n return this.#splits.entries();\n }\n}\n","/**\n * {@link Member} — partner-facing player record.\n *\n * @module\n */\n\nimport type {\n Gender,\n MemberStatusWire,\n PartnerMemberWire,\n RatingSplitWire,\n SportRatingWire,\n} from '../types.js';\nimport { SportRating } from './sport-rating.js';\n\n/**\n * Map-like wrapper around a player's sport → {@link SportRating}.\n *\n * Supports `.get(code)`, `.has(code)`, `.size`, and iteration so the\n * shape feels native:\n *\n * ```ts\n * member.sport.get('pickleball')?.rating\n * for (const [code, rating] of member.sport) { ... }\n * ```\n *\n * @category Members\n */\nexport class MemberSportMap {\n readonly #sports: ReadonlyMap<string, SportRating>;\n\n constructor(wire: Readonly<Record<string, SportRatingWire>> | undefined) {\n const entries = Object.entries(wire ?? {}).map(\n ([code, w]) => [code, new SportRating(w)] as const,\n );\n this.#sports = new Map(entries);\n Object.freeze(this);\n }\n\n get(sport: string): SportRating | undefined {\n return this.#sports.get(sport);\n }\n\n has(sport: string): boolean {\n return this.#sports.has(sport);\n }\n\n get size(): number {\n return this.#sports.size;\n }\n\n keys(): IterableIterator<string> {\n return this.#sports.keys();\n }\n\n values(): IterableIterator<SportRating> {\n return this.#sports.values();\n }\n\n entries(): IterableIterator<[string, SportRating]> {\n return this.#sports.entries();\n }\n\n [Symbol.iterator](): IterableIterator<[string, SportRating]> {\n return this.#sports.entries();\n }\n}\n\n/**\n * A partner-facing player record.\n *\n * Returned by {@link MembersResource.get} (full detail, requires an\n * active OAuth connection) and {@link MembersResource.search} (limited\n * detail for public search).\n *\n * Rating data lives under {@link sport} — keyed by sport code. The\n * backend returns only the sports the player has ratings in, or only\n * the sports requested via the `sport=` query filter. Use\n * {@link ratingFor} to fetch the primary rating for a specific sport\n * with a sensible default.\n *\n * @category Members\n */\nexport class Member {\n readonly memberId: number;\n readonly id: string | null;\n readonly firstName: string;\n readonly lastName: string;\n readonly fullName: string;\n readonly displayName: string;\n readonly age: number | null;\n readonly city: string | null;\n readonly state: string | null;\n readonly zip: string | null;\n readonly country: string | null;\n readonly gender: Gender | null;\n readonly status: MemberStatusWire;\n readonly sport: MemberSportMap;\n readonly activeLeagues: readonly string[] | null;\n readonly email: string | null;\n readonly grantedScopes: readonly string[] | null;\n\n constructor(wire: PartnerMemberWire) {\n this.memberId = wire.memberId;\n this.id = wire.id ?? null;\n this.firstName = wire.firstName;\n this.lastName = wire.lastName;\n this.fullName = wire.fullName;\n this.displayName = wire.displayName;\n this.age = wire.age ?? null;\n this.city = wire.city ?? null;\n this.state = wire.state ?? null;\n this.zip = wire.zip ?? null;\n this.country = wire.country ?? null;\n this.gender = wire.gender ?? null;\n this.status = Object.freeze({ ...wire.status });\n this.sport = new MemberSportMap(wire.sport);\n this.activeLeagues = wire.activeLeagues ? Object.freeze([...wire.activeLeagues]) : null;\n this.email = wire.email ?? null;\n this.grantedScopes = wire.grantedScopes ? Object.freeze([...wire.grantedScopes]) : null;\n Object.freeze(this);\n }\n\n /** Full name — alias for {@link fullName}, matching common usage. */\n get name(): string {\n return this.fullName;\n }\n\n /** The list of sport codes this player has ratings in. */\n get sports(): readonly string[] {\n return [...this.sport.keys()];\n }\n\n /**\n * Primary rating for a given sport.\n *\n * @param sport Sport code — defaults to `'pickleball'`.\n * @returns The primary rating value, or `null` if the player has no\n * ratings for that sport.\n */\n ratingFor(sport = 'pickleball'): number | null {\n return this.sport.get(sport)?.rating ?? null;\n }\n\n /**\n * Get a specific rating split for a sport.\n *\n * @param key Split key (e.g. `'overall-open'`).\n * @param sport Sport code — defaults to `'pickleball'`.\n */\n split(key: string, sport = 'pickleball'): RatingSplitWire | null {\n return this.sport.get(sport)?.get(key) ?? null;\n }\n\n /** Compact summary for console output. */\n toString(): string {\n const primary = this.sport.values().next().value;\n if (primary) {\n return `Member #${this.memberId} '${this.displayName}' rating=${primary.rating.toFixed(\n 3,\n )} ${primary.abbr}`;\n }\n return `Member #${this.memberId} '${this.displayName}'`;\n }\n}\n","/**\n * {@link RatingUpdate} — a single rating change notification.\n *\n * @module\n */\n\nimport type { PartnerRatingUpdateWire, RatingSplitWire } from '../types.js';\n\n/**\n * A single rating change notification.\n *\n * Returned by {@link MembersResource.ratingUpdates} (polling) and\n * delivered via webhook callbacks to partners that have registered a\n * webhook URL and have subscribers.\n *\n * @category Members\n */\nexport class RatingUpdate {\n readonly memberId: number;\n readonly id: string | null;\n readonly displayName: string | null;\n readonly sport: string | null;\n readonly previousRating: number | null;\n readonly newRating: number | null;\n readonly changedAt: string | null;\n readonly ratingSplits: Readonly<Record<string, RatingSplitWire>> | null;\n\n constructor(wire: PartnerRatingUpdateWire) {\n this.memberId = wire.memberId;\n this.id = wire.id ?? null;\n this.displayName = wire.displayName ?? null;\n this.sport = wire.sport ?? null;\n this.previousRating = wire.previousRating ?? null;\n this.newRating = wire.newRating ?? null;\n this.changedAt = wire.changedAt ?? null;\n this.ratingSplits = wire.ratingSplits ? Object.freeze({ ...wire.ratingSplits }) : null;\n Object.freeze(this);\n }\n\n /**\n * Rating change amount — `newRating - previousRating`. Returns `null`\n * if either rating is missing from the update payload.\n */\n get delta(): number | null {\n if (this.previousRating === null || this.newRating === null) {\n return null;\n }\n return this.newRating - this.previousRating;\n }\n\n /** `true` when the new rating is strictly higher than the previous. */\n get improved(): boolean {\n const delta = this.delta;\n return delta !== null && delta > 0;\n }\n\n toString(): string {\n const arrow = this.improved ? '↑' : '↓';\n const prev = this.previousRating !== null ? this.previousRating.toFixed(3) : '?';\n const next = this.newRating !== null ? this.newRating.toFixed(3) : '?';\n const name = this.displayName ? ` '${this.displayName}'` : '';\n return `RatingUpdate #${this.memberId}${name} ${prev} ${arrow} ${next}`;\n }\n}\n","/**\n * {@link MembersResource} — member lookups, search, and rating updates.\n *\n * @module\n */\n\nimport { ValidationError } from '../errors.js';\nimport type { HttpTransport, QueryParams } from '../http.js';\nimport { Member } from '../models/member.js';\nimport { RatingUpdate } from '../models/rating-update.js';\nimport type { PartnerMemberWire, PartnerRatingUpdateWire, SearchFilters } from '../types.js';\n\nconst DEFAULT_PAGE_SIZE = 20;\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Member operations — get a single member, auto-paginating search,\n * find by name, and polling for rating change notifications.\n *\n * @category Resources\n */\nexport class MembersResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * Get a connected member by external ID.\n *\n * **Requires an active OAuth connection** between your partner app\n * and the player. Use the OAuth flow on `client.oauth` first.\n *\n * @param playerId External player ID in `vair_mem_xxx` format.\n * @param options.sport Optional sport filter — single code or list.\n * When omitted, the response contains every sport the player has\n * ratings in.\n * @throws {@link NotFoundError} if the external ID is unknown.\n * @throws {@link VairifiedError} if the player has not connected to\n * your app (403) or the request otherwise fails.\n *\n * @example\n * ```ts\n * const member = await client.members.get('vair_mem_xxx');\n * console.log(member.name, member.ratingFor('pickleball'));\n *\n * // Just pickleball\n * const member2 = await client.members.get('vair_mem_xxx', { sport: 'pickleball' });\n *\n * // Multiple sports\n * const member3 = await client.members.get('vair_mem_xxx', {\n * sport: ['pickleball', 'padel'],\n * });\n * ```\n */\n async get(\n playerId: string,\n options: { sport?: string | readonly string[] } = {},\n ): Promise<Member> {\n const query: Record<string, string> = { memberId: playerId };\n if (options.sport !== undefined) {\n query.sport = Array.isArray(options.sport)\n ? (options.sport as readonly string[]).join(',')\n : (options.sport as string);\n }\n const wire = await this.#http.request<PartnerMemberWire>({\n method: 'GET',\n path: '/partner/member',\n query,\n });\n return new Member(wire);\n }\n\n /**\n * Search for members, yielding each match as a {@link Member}.\n *\n * This is an **auto-paginating async iterator** — it fetches pages\n * from the server lazily as you iterate, so you can stream through\n * thousands of results without holding them all in memory:\n *\n * ```ts\n * for await (const m of client.members.search({ city: 'Austin' })) {\n * console.log(m.name, m.ratingFor('pickleball'));\n * }\n * ```\n *\n * Stop early by `break`-ing out of the loop, or cap the total with\n * `maxResults`.\n */\n async *search(filters: SearchFilters = {}): AsyncGenerator<Member, void, void> {\n const pageSize = Math.min(filters.pageSize ?? DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);\n const maxResults = filters.maxResults;\n\n const baseQuery = buildSearchQuery(filters, pageSize);\n\n let offset = 0;\n let yielded = 0;\n\n while (true) {\n const query: QueryParams = { ...baseQuery, offset };\n const data = await this.#http.request<\n PartnerMemberWire[] | { players?: PartnerMemberWire[] }\n >({ method: 'GET', path: '/partner/search', query });\n\n const batch: PartnerMemberWire[] = Array.isArray(data) ? data : (data?.players ?? []);\n\n if (batch.length === 0) {\n return;\n }\n\n for (const wire of batch) {\n yield new Member(wire);\n yielded += 1;\n if (maxResults !== undefined && yielded >= maxResults) {\n return;\n }\n }\n\n if (batch.length < pageSize) {\n return;\n }\n offset += pageSize;\n }\n }\n\n /**\n * Return the first search hit for a name, or `null`.\n *\n * Convenience for the common \"look up by name\" case:\n *\n * ```ts\n * const mike = await client.members.find('Mike Barker');\n * if (mike) {\n * console.log(mike.ratingFor('pickleball'));\n * }\n * ```\n */\n async find(name: string): Promise<Member | null> {\n for await (const member of this.search({ name, pageSize: 1, maxResults: 1 })) {\n return member;\n }\n return null;\n }\n\n /**\n * Fetch up to 100 members by their member IDs in one call.\n *\n * Unknown IDs are silently omitted — the returned array may be\n * shorter than the input. Results are returned in the same order\n * as the input IDs.\n *\n * @param ids - Array of integer member IDs (max 100).\n * @param options - Optional filters.\n * @param options.sport - Sport code to scope ratings (e.g. `'pickleball'`).\n * @returns Array of {@link Member} instances.\n * @throws {@link ValidationError} If more than 100 IDs are provided.\n * @category Members\n *\n * @example\n * ```ts\n * const members = await client.members.getBulk([4873327, 4873328]);\n * for (const m of members) {\n * console.log(m.name, m.ratingFor('pickleball'));\n * }\n * ```\n */\n async getBulk(ids: number[], options?: { sport?: string }): Promise<Member[]> {\n if (ids.length > 100) {\n throw new ValidationError('Maximum 100 member IDs per request');\n }\n const query: Record<string, string> = { ids: ids.join(',') };\n if (options?.sport) query.sport = options.sport;\n const rows = await this.#http.request<PartnerMemberWire[]>({\n method: 'GET',\n path: '/partner/members',\n query,\n });\n return rows.map((row) => new Member(row));\n }\n\n /**\n * Poll for rating change notifications.\n *\n * Returns a list of {@link RatingUpdate} objects for every player\n * whose rating has changed since the last poll. Members are\n * considered subscribed when they have an active OAuth connection\n * with the `user:webhook:subscribe` scope.\n */\n async ratingUpdates(): Promise<readonly RatingUpdate[]> {\n const data = await this.#http.request<{ updates?: PartnerRatingUpdateWire[] } | unknown>({\n method: 'GET',\n path: '/partner/rating-updates',\n });\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n return [];\n }\n const updates = (data as { updates?: PartnerRatingUpdateWire[] }).updates ?? [];\n return updates.map((wire) => new RatingUpdate(wire));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction buildSearchQuery(filters: SearchFilters, pageSize: number): QueryParams {\n const query: Record<string, string | number | boolean> = {};\n\n if (filters.sport !== undefined) {\n query.sport = Array.isArray(filters.sport)\n ? (filters.sport as readonly string[]).join(',')\n : (filters.sport as string);\n }\n\n if (filters.memberId !== undefined) {\n query.member = String(filters.memberId);\n } else if (filters.name !== undefined) {\n query.member = filters.name;\n }\n\n if (filters.city !== undefined) query.city = filters.city;\n if (filters.state !== undefined) query.state = filters.state;\n if (filters.country !== undefined) query.country = filters.country;\n if (filters.zip !== undefined) query.zip = filters.zip;\n if (filters.location !== undefined) query.location = filters.location;\n\n if (filters.gender !== undefined) {\n query.gender = filters.gender.toUpperCase();\n }\n if (filters.vairifiedOnly !== undefined) query.vairified = filters.vairifiedOnly;\n if (filters.wheelchair !== undefined) query.wheelchair = filters.wheelchair;\n\n if (filters.ratingMin !== undefined) query.rating1 = filters.ratingMin;\n if (filters.ratingMax !== undefined) query.rating2 = filters.ratingMax;\n\n const { ageFilterType, age1, age2 } = resolveAgeFilter(filters);\n if (ageFilterType !== undefined) query.ageFilterType = ageFilterType;\n if (age1 !== undefined) query.age1 = age1;\n if (age2 !== undefined) query.age2 = age2;\n\n if (filters.sortBy !== undefined) query.sortField = filters.sortBy;\n if (filters.sortOrder !== undefined) query.sortDirection = filters.sortOrder;\n\n query.limit = pageSize;\n\n return query;\n}\n\nfunction resolveAgeFilter(filters: SearchFilters): {\n ageFilterType?: string;\n age1?: number;\n age2?: number;\n} {\n if (filters.age !== undefined) {\n return { ageFilterType: 'exact', age1: filters.age };\n }\n if (filters.ageMin !== undefined && filters.ageMax !== undefined) {\n return { ageFilterType: 'range', age1: filters.ageMin, age2: filters.ageMax };\n }\n if (filters.ageMin !== undefined) {\n return { ageFilterType: 'above', age1: filters.ageMin };\n }\n if (filters.ageMax !== undefined) {\n return { ageFilterType: 'below', age1: filters.ageMax };\n }\n return {};\n}\n","/**\n * Vairified OAuth helpers and type definitions.\n *\n * Use the {@link OAuthResource} on `client.oauth` for the full flow —\n * these helpers exist for partners who need to build authorization URLs\n * or validate scopes outside the client (e.g. in a frontend that only\n * handles the redirect step).\n *\n * @module\n */\n\n// ---------------------------------------------------------------------------\n// Scope definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Every OAuth scope the Vairified authorization server accepts.\n *\n * Declaring this as a string union (rather than a free-form `string`)\n * lets TypeScript catch typos at authoring time:\n *\n * ```ts\n * const scopes: OAuthScope[] = ['user:profile:read', 'user:rating:read']; // ok\n * const bad: OAuthScope[] = ['user:profile:read', 'rating']; // type error\n * ```\n *\n * @category OAuth\n */\nexport type OAuthScope =\n | 'user:profile:read'\n | 'user:profile:email'\n | 'user:rating:read'\n | 'user:rating:history'\n | 'user:match:submit'\n | 'user:webhook:subscribe';\n\n/**\n * Human-readable description for every OAuth scope.\n *\n * @category OAuth\n */\nexport const SCOPES: Readonly<Record<OAuthScope, string>> = Object.freeze({\n 'user:profile:read': 'Access your name, location, and verification status',\n 'user:profile:email': 'Access your email address',\n 'user:rating:read': 'View your current rating and rating splits',\n 'user:rating:history': 'View your complete rating history',\n 'user:match:submit': 'Submit match results on your behalf',\n 'user:webhook:subscribe': 'Receive notifications when your rating changes',\n});\n\n/**\n * The scopes automatically requested when none are specified.\n *\n * @category OAuth\n */\nexport const DEFAULT_SCOPES: readonly OAuthScope[] = Object.freeze([\n 'user:profile:read',\n 'user:rating:read',\n]);\n\n// ---------------------------------------------------------------------------\n// OAuth data types\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration for building an authorization URL manually.\n *\n * @category OAuth\n */\nexport interface OAuthConfig {\n readonly apiKey: string;\n readonly redirectUri: string;\n readonly baseUrl?: string;\n /**\n * Your app's `client_id` — the `PartnerApp.slug` Vairified assigned you\n * (e.g. `dinkr`). Required by the browser `GET /partner/oauth/authorize`\n * endpoint to identify your app; without it the authorization page rejects\n * the request with `invalid_request: client_id is required`.\n *\n * Only needed for this pure-frontend URL helper. The recommended flow —\n * {@link OAuthResource.authorize} on a client — identifies your app by the\n * API key instead, so it needs no `client_id`.\n */\n readonly clientId?: string;\n}\n\n/**\n * Response from starting an OAuth authorization flow.\n *\n * @category OAuth\n */\nexport interface AuthorizationResponse {\n readonly authorizationUrl: string;\n readonly code: string;\n readonly state?: string;\n}\n\n/**\n * Response from exchanging an authorization code for tokens.\n *\n * @category OAuth\n */\nexport interface TokenResponse {\n readonly accessToken: string;\n readonly refreshToken: string | null;\n readonly expiresIn: number;\n readonly scope: readonly string[];\n readonly playerId: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helper functions\n// ---------------------------------------------------------------------------\n\n/**\n * Build the URL to redirect users to for OAuth authorization.\n *\n * Prefer {@link OAuthResource.authorize} on a Vairified client — this\n * helper is only useful when you need to construct the URL without\n * making an HTTP call first (for example, in a pure-frontend handoff).\n *\n * @category OAuth\n */\nexport function getAuthorizationUrl(\n config: OAuthConfig,\n options: { scopes?: readonly OAuthScope[]; state?: string } = {},\n): string {\n const baseUrl = (config.baseUrl ?? 'https://api-next.vairified.com/api/v1').replace(/\\/+$/, '');\n const scopeList = ensureProfileRead(options.scopes ?? DEFAULT_SCOPES);\n\n // Scope is space-delimited per RFC 6749 §3.3 — the deployed authorization\n // server splits on whitespace, not commas.\n const params = new URLSearchParams({\n redirect_uri: config.redirectUri,\n scope: scopeList.join(' '),\n response_type: 'code',\n });\n // `client_id` (the PartnerApp slug) identifies the app to the browser\n // authorize endpoint; the URL is rejected without it.\n if (config.clientId) {\n params.set('client_id', config.clientId);\n }\n if (options.state) {\n params.set('state', options.state);\n }\n\n return `${baseUrl}/partner/oauth/authorize?${params.toString()}`;\n}\n\n/**\n * Check whether a scope string is one the Vairified server accepts.\n *\n * @category OAuth\n */\nexport function validateScope(scope: string): scope is OAuthScope {\n return scope in SCOPES;\n}\n\n/**\n * Get a human-readable description of an OAuth scope.\n *\n * Returns `\"Unknown scope: {scope}\"` for unrecognized scopes so this\n * function is safe to call on user-supplied input.\n *\n * @category OAuth\n */\nexport function describeScope(scope: string): string {\n if (validateScope(scope)) {\n return SCOPES[scope];\n }\n return `Unknown scope: ${scope}`;\n}\n\n/**\n * Describe multiple scopes at once.\n *\n * @category OAuth\n */\nexport function describeScopes(\n scopes: readonly string[],\n): readonly { scope: string; description: string }[] {\n return scopes.map((scope) => ({\n scope,\n description: describeScope(scope),\n }));\n}\n\n/**\n * Generate a cryptographically-random CSRF state token suitable for\n * use with {@link OAuthResource.authorize}.\n *\n * Uses the Web Crypto API `crypto.getRandomValues` (built into Node 19+\n * and all modern browsers). The returned string is URL-safe, unpadded\n * base64 of 32 random bytes.\n *\n * On runtimes without Web Crypto — notably **React Native / Hermes** —\n * this throws a descriptive `Error` (rather than a bare `ReferenceError`)\n * telling you to install and import `react-native-get-random-values` at\n * your app entry, or to pass your own high-entropy `state` string. Base64\n * encoding is done in pure JS, so no `btoa` polyfill is required.\n *\n * @throws {Error} when `crypto.getRandomValues` is unavailable.\n * @category OAuth\n */\nexport function generateState(): string {\n const webCrypto = globalThis.crypto;\n if (typeof webCrypto?.getRandomValues !== 'function') {\n throw new Error(\n 'generateState() needs Web Crypto (crypto.getRandomValues), which is unavailable in ' +\n 'this runtime. Node 19+ and browsers have it built in; on React Native / Hermes, ' +\n \"install 'react-native-get-random-values' and import it once at your app entry \" +\n 'before using the SDK — or pass your own high-entropy `state` string to ' +\n 'oauth.authorize().',\n );\n }\n const bytes = new Uint8Array(32);\n webCrypto.getRandomValues(bytes);\n return base64UrlNoPad(bytes);\n}\n\n/** URL-safe base64 alphabet (RFC 4648 §5), used by {@link base64UrlNoPad}. */\nconst B64URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\n/**\n * URL-safe, unpadded base64 of a byte array — implemented in pure JS so it\n * works on runtimes without `btoa` (e.g. React Native / Hermes).\n *\n * @internal\n */\nfunction base64UrlNoPad(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i += 3) {\n const b0 = bytes[i] ?? 0;\n const b1 = bytes[i + 1] ?? 0;\n const b2 = bytes[i + 2] ?? 0;\n const hasB1 = i + 1 < bytes.length;\n const hasB2 = i + 2 < bytes.length;\n out += B64URL_ALPHABET[b0 >> 2] ?? '';\n out += B64URL_ALPHABET[((b0 & 0x03) << 4) | (b1 >> 4)] ?? '';\n if (hasB1) out += B64URL_ALPHABET[((b1 & 0x0f) << 2) | (b2 >> 6)] ?? '';\n if (hasB2) out += B64URL_ALPHABET[b2 & 0x3f] ?? '';\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers (used by resources/oauth.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure `user:profile:read` is in the scope list, prepending if necessary.\n *\n * @internal\n */\nexport function ensureProfileRead(scopes: readonly OAuthScope[]): readonly OAuthScope[] {\n if (scopes.includes('user:profile:read')) {\n return scopes;\n }\n return ['user:profile:read', ...scopes];\n}\n","/**\n * {@link OAuthResource} — OAuth 2.0 flow for player consent.\n *\n * @module\n */\n\nimport { OAuthError } from '../errors.js';\nimport type { HttpTransport } from '../http.js';\nimport {\n type AuthorizationResponse,\n DEFAULT_SCOPES,\n ensureProfileRead,\n type OAuthScope,\n SCOPES,\n type TokenResponse,\n} from '../oauth.js';\n\n/**\n * OAuth 2.0 flow for obtaining player consent.\n *\n * Typical flow:\n *\n * 1. {@link authorize} — start an authorization, get a URL to redirect\n * the player to.\n * 2. Player approves on the Vairified site and is redirected back to\n * your `redirectUri` with a `code` query parameter.\n * 3. {@link exchangeToken} — swap the code for access and refresh\n * tokens plus the player's external ID.\n * 4. Store the refresh token and call {@link refresh} when the access\n * token expires.\n * 5. {@link revoke} — disconnect a player from your app.\n *\n * @category Resources\n */\nexport class OAuthResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * Start an OAuth authorization flow.\n *\n * @throws {@link OAuthError} with `errorCode: 'invalid_scope'` if a\n * requested scope is not in the accepted list.\n */\n async authorize(options: {\n redirectUri: string;\n scopes?: readonly OAuthScope[];\n state?: string;\n }): Promise<AuthorizationResponse> {\n const scopeList = ensureProfileRead(options.scopes ?? DEFAULT_SCOPES);\n\n for (const scope of scopeList) {\n if (!(scope in SCOPES)) {\n throw new OAuthError(`Invalid scope: ${scope}`, 'invalid_scope');\n }\n }\n\n const data = await this.#http.request<{\n authorization_url?: string;\n code?: string;\n }>({\n method: 'POST',\n path: '/partner/oauth/authorize',\n body: {\n redirect_uri: options.redirectUri,\n scope: scopeList.join(' '),\n state: options.state,\n },\n });\n\n return {\n authorizationUrl: data?.authorization_url ?? '',\n code: data?.code ?? '',\n state: options.state,\n };\n }\n\n /** Exchange an authorization code for access and refresh tokens. */\n async exchangeToken(options: { code: string; redirectUri: string }): Promise<TokenResponse> {\n const data = await this.#http.request<Record<string, unknown>>({\n method: 'POST',\n path: '/partner/oauth/token',\n // RFC 6749 §4.1.3 — the endpoint requires `grant_type` and the\n // snake_case `redirect_uri` (which must match the authorize request).\n body: {\n grant_type: 'authorization_code',\n code: options.code,\n redirect_uri: options.redirectUri,\n },\n });\n return tokenResponseFromWire(data);\n }\n\n /** Refresh an expired access token using a refresh token. */\n async refresh(refreshToken: string): Promise<TokenResponse> {\n const data = await this.#http.request<Record<string, unknown>>({\n method: 'POST',\n path: '/partner/oauth/refresh',\n // RFC 6749 §6 — refresh grant, snake_case body.\n body: { grant_type: 'refresh_token', refresh_token: refreshToken },\n });\n return tokenResponseFromWire(data);\n }\n\n /** Revoke a player's OAuth connection to your app. */\n async revoke(playerId: string): Promise<Record<string, unknown>> {\n const data = await this.#http.request<Record<string, unknown> | undefined>({\n method: 'POST',\n path: '/partner/oauth/revoke',\n body: { player_id: playerId },\n });\n return data ?? {};\n }\n\n /** Return the list of OAuth scopes the server currently supports. */\n async availableScopes(): Promise<readonly { name: string; description: string }[]> {\n const data = await this.#http.request<\n { scopes?: { name: string; description: string }[] } | unknown\n >({\n method: 'GET',\n path: '/partner/oauth/scopes',\n });\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n return [];\n }\n return (data as { scopes?: { name: string; description: string }[] }).scopes ?? [];\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction tokenResponseFromWire(data: Record<string, unknown> | undefined): TokenResponse {\n // The API returns `scope` as a space-delimited string (RFC 6749 §3.3).\n // Fall back to the deprecated `scopes` array for older API builds.\n const scopeRaw = (data?.scope ?? '') as string;\n const scopeList =\n scopeRaw.length > 0\n ? scopeRaw.split(/\\s+/).filter(Boolean)\n : Array.isArray(data?.scopes)\n ? (data.scopes as string[])\n : [];\n return {\n accessToken: (data?.access_token ?? '') as string,\n refreshToken: (data?.refresh_token ?? null) as string | null,\n expiresIn: (data?.expires_in ?? 3600) as number,\n scope: Object.freeze(scopeList),\n playerId: (data?.player_id ?? '') as string,\n };\n}\n","/**\n * {@link WebhookDelivery} and {@link WebhookDeliveriesResult} — webhook\n * delivery inspection models.\n *\n * @module\n */\n\nimport type { WebhookDeliveriesResultWire, WebhookDeliveryWire } from '../types.js';\n\n/**\n * A single webhook delivery attempt.\n *\n * @category Webhooks\n */\nexport class WebhookDelivery {\n readonly id: string;\n readonly event: string;\n readonly url: string;\n readonly statusCode: number | null;\n readonly responseBody: string | null;\n readonly errorMessage: string | null;\n readonly attempts: number;\n readonly maxAttempts: number;\n readonly lastAttemptAt: string;\n readonly nextRetryAt: string | null;\n readonly completedAt: string | null;\n readonly createdAt: string;\n readonly payload: Readonly<Record<string, unknown>>;\n\n /** @internal */\n constructor(wire: WebhookDeliveryWire) {\n this.id = wire.id;\n this.event = wire.event;\n this.url = wire.url;\n this.statusCode = wire.statusCode;\n this.responseBody = wire.responseBody;\n this.errorMessage = wire.errorMessage;\n this.attempts = wire.attempts;\n this.maxAttempts = wire.maxAttempts;\n this.lastAttemptAt = wire.lastAttemptAt;\n this.nextRetryAt = wire.nextRetryAt;\n this.completedAt = wire.completedAt;\n this.createdAt = wire.createdAt;\n this.payload = Object.freeze({ ...wire.payload });\n Object.freeze(this);\n }\n\n /** Whether delivery completed successfully (2xx status). */\n get succeeded(): boolean {\n return (\n this.completedAt != null &&\n this.statusCode != null &&\n this.statusCode >= 200 &&\n this.statusCode < 300\n );\n }\n\n /** Whether delivery failed definitively (completed with non-2xx). */\n get failed(): boolean {\n return this.completedAt != null && !this.succeeded;\n }\n}\n\n/**\n * Paginated list of webhook delivery attempts.\n *\n * @category Webhooks\n */\nexport class WebhookDeliveriesResult {\n readonly deliveries: readonly WebhookDelivery[];\n readonly total: number;\n\n /** @internal */\n constructor(wire: WebhookDeliveriesResultWire) {\n this.deliveries = Object.freeze(wire.deliveries.map((d) => new WebhookDelivery(d)));\n this.total = wire.total;\n Object.freeze(this);\n }\n}\n","/**\n * {@link WebhooksResource} — webhook delivery inspection.\n *\n * @module\n */\n\nimport type { HttpTransport } from '../http.js';\nimport { WebhookDeliveriesResult } from '../models/webhook-delivery.js';\nimport type { WebhookDeliveriesResultWire } from '../types.js';\n\n/**\n * Webhook delivery inspection.\n *\n * @category Resources\n */\nexport class WebhooksResource {\n readonly #http: HttpTransport;\n\n /** @internal */\n constructor(http: HttpTransport) {\n this.#http = http;\n }\n\n /**\n * List recent webhook delivery attempts.\n *\n * @param options - Optional filters and pagination.\n * @param options.event - Filter by event type (e.g. `'rating.updated'`).\n * @param options.status - Filter: `'all'`, `'pending'`, `'success'`, or `'failed'`.\n * @param options.limit - Results per page (1-100, default 20).\n * @param options.offset - Pagination offset.\n * @returns {@link WebhookDeliveriesResult} with entries and total.\n * @category Webhooks\n *\n * @example\n * ```ts\n * const result = await client.webhooks.deliveries({ status: 'failed' });\n * for (const d of result.deliveries) {\n * console.log(d.event, d.statusCode, d.errorMessage);\n * }\n * ```\n */\n async deliveries(options?: {\n event?: string;\n status?: 'all' | 'pending' | 'success' | 'failed';\n limit?: number;\n offset?: number;\n }): Promise<WebhookDeliveriesResult> {\n const query: Record<string, string | number> = {};\n if (options?.event) query.event = options.event;\n if (options?.status) query.status = options.status;\n if (options?.limit != null) query.limit = options.limit;\n if (options?.offset != null) query.offset = options.offset;\n const data = await this.#http.request<WebhookDeliveriesResultWire>({\n method: 'GET',\n path: '/partner/webhook-deliveries',\n query,\n });\n return new WebhookDeliveriesResult(data);\n }\n}\n","/**\n * {@link Vairified} — the main entry point of the SDK.\n *\n * @module\n */\n\nimport { HttpTransport } from './http.js';\nimport {\n LeaderboardResource,\n MatchesResource,\n MembersResource,\n OAuthResource,\n WebhooksResource,\n} from './resources/index.js';\nimport type { VairifiedEnvironment, VairifiedOptions } from './types.js';\n\n/**\n * Environment preset → base URL mapping.\n *\n * Partners can switch between production, staging, and local development\n * without memorizing hostnames.\n *\n * @category Client\n */\nexport const ENVIRONMENTS: Readonly<Record<VairifiedEnvironment, string>> = Object.freeze({\n production: 'https://api-next.vairified.com/api/v1',\n staging: 'https://api-staging.vairified.com/api/v1',\n local: 'http://localhost:3001/api/v1',\n});\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Read an environment variable without assuming `process` exists.\n *\n * Node and most bundlers expose `process.env`, but React Native / Hermes\n * (and some edge runtimes) do not — touching `process.env` there can throw\n * a `ReferenceError`. This resolves to `undefined` instead of crashing, so\n * those callers simply pass `apiKey`/`env` explicitly (see the README's\n * \"React Native\" section).\n *\n * @internal\n */\nfunction readEnv(name: string): string | undefined {\n try {\n if (typeof process === 'undefined') return undefined;\n return process.env?.[name];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Async client for the Vairified Partner API.\n *\n * The client is organized around sub-resources that mirror the REST\n * structure — {@link members}, {@link matches}, {@link oauth},\n * {@link leaderboard}. Each sub-resource is a thin wrapper around the\n * HTTP transport on this object.\n *\n * ## Lifecycle\n *\n * The client holds no persistent connections itself — it's safe to\n * create one per request if you want. But for typical usage, wrap it\n * in `await using` so resources are cleaned up deterministically:\n *\n * ```ts\n * await using client = new Vairified({ apiKey: 'vair_pk_xxx' });\n *\n * const member = await client.members.get('vair_mem_xxx');\n * console.log(member.name, member.ratingFor('pickleball'));\n *\n * for await (const m of client.members.search({ city: 'Austin' })) {\n * console.log(m.name);\n * }\n * ```\n *\n * `await using` requires TypeScript 5.2+ and Node 20+. If you can't\n * use it, just call `await client.close()` manually when you're done.\n *\n * @category Client\n */\nexport class Vairified {\n /** The resolved API key this client is using. */\n readonly apiKey: string;\n /** The resolved base URL (production, staging, local, or custom). */\n readonly baseUrl: string;\n /** The resolved environment name. */\n readonly env: VairifiedEnvironment;\n /** Request timeout in milliseconds. */\n readonly timeoutMs: number;\n\n /** Member operations — get, search, find, ratingUpdates. */\n readonly members: MembersResource;\n /** Match submission — submit, testWebhook. */\n readonly matches: MatchesResource;\n /** OAuth flow — authorize, exchangeToken, refresh, revoke. */\n readonly oauth: OAuthResource;\n /** Leaderboard queries — list, rank, categories. */\n readonly leaderboard: LeaderboardResource;\n /** Webhook delivery inspection — deliveries. */\n readonly webhooks: WebhooksResource;\n\n readonly #transport: HttpTransport;\n\n constructor(options: VairifiedOptions = {}) {\n const apiKey = options.apiKey ?? readEnv('VAIRIFIED_API_KEY') ?? '';\n if (apiKey.length === 0) {\n throw new Error('API key required. Pass { apiKey } or set VAIRIFIED_API_KEY.');\n }\n this.apiKey = apiKey;\n\n if (options.baseUrl) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n this.env = options.env ?? 'production';\n } else {\n const envName = (options.env ??\n (readEnv('VAIRIFIED_ENV') as VairifiedEnvironment | undefined) ??\n 'production') as VairifiedEnvironment;\n if (options.env && !(envName in ENVIRONMENTS)) {\n throw new Error(\n `Unknown environment: ${envName}. Use one of: ${Object.keys(ENVIRONMENTS).join(', ')}`,\n );\n }\n this.env = envName;\n this.baseUrl = ENVIRONMENTS[envName] ?? ENVIRONMENTS.production;\n }\n\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n this.#transport = new HttpTransport({\n baseUrl: this.baseUrl,\n apiKey: this.apiKey,\n timeoutMs: this.timeoutMs,\n fetch: options.fetch ?? fetch,\n });\n\n this.members = new MembersResource(this.#transport);\n this.matches = new MatchesResource(this.#transport);\n this.oauth = new OAuthResource(this.#transport);\n this.leaderboard = new LeaderboardResource(this.#transport);\n this.webhooks = new WebhooksResource(this.#transport);\n }\n\n /**\n * API usage statistics for the current API key.\n *\n * Returns rate-limit status, request counts, and quota usage.\n */\n async usage(): Promise<Record<string, unknown>> {\n const data = await this.#transport.request<Record<string, unknown> | undefined>({\n method: 'GET',\n path: '/partner/usage',\n });\n return data ?? {};\n }\n\n /**\n * Release any resources held by the client.\n *\n * The current transport is stateless, so this is a no-op today, but\n * partners should still call it (or use `await using`) so the SDK\n * can add connection pooling later without breaking them.\n */\n async close(): Promise<void> {\n // Nothing to release today. Kept as an explicit hook so future\n // transports (keep-alive, HTTP/2) can release their pools.\n }\n\n /**\n * Explicit resource management hook — enables\n * `await using client = new Vairified({ ... })` (TypeScript 5.2+).\n */\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close();\n }\n\n /** Compact summary for console output. */\n toString(): string {\n return `Vairified { env: '${this.env}', baseUrl: '${this.baseUrl}' }`;\n }\n}\n"],"mappings":"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","names":[]}