vairified 0.3.0 → 0.3.2

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
@@ -189,8 +189,8 @@ if (result.ok) {
189
189
  }
190
190
  ```
191
191
 
192
- Set `dryRun: true` on the batch to validate without persisting your API key must have
193
- the `key:dry-run` scope.
192
+ Set `dryRun: true` on the batch to validate without persisting. No special scope
193
+ needed — any key with `key:match:submit` can dry-run.
194
194
 
195
195
  ### Tournament import
196
196
 
package/dist/index.cjs CHANGED
@@ -655,7 +655,7 @@ var MembersResource = class {
655
655
  * ```
656
656
  */
657
657
  async get(playerId, options = {}) {
658
- const query = { id: playerId };
658
+ const query = { memberId: playerId };
659
659
  if (options.sport !== void 0) {
660
660
  query.sport = Array.isArray(options.sport) ? options.sport.join(",") : options.sport;
661
661
  }
@@ -846,9 +846,12 @@ function getAuthorizationUrl(config, options = {}) {
846
846
  const scopeList = ensureProfileRead(options.scopes ?? DEFAULT_SCOPES);
847
847
  const params = new URLSearchParams({
848
848
  redirect_uri: config.redirectUri,
849
- scope: scopeList.join(","),
849
+ scope: scopeList.join(" "),
850
850
  response_type: "code"
851
851
  });
852
+ if (config.clientId) {
853
+ params.set("client_id", config.clientId);
854
+ }
852
855
  if (options.state) {
853
856
  params.set("state", options.state);
854
857
  }
@@ -909,13 +912,13 @@ var OAuthResource = class {
909
912
  method: "POST",
910
913
  path: "/partner/oauth/authorize",
911
914
  body: {
912
- redirectUri: options.redirectUri,
913
- scope: scopeList.join(","),
915
+ redirect_uri: options.redirectUri,
916
+ scope: scopeList.join(" "),
914
917
  state: options.state
915
918
  }
916
919
  });
917
920
  return {
918
- authorizationUrl: data?.authorizationUrl ?? "",
921
+ authorizationUrl: data?.authorization_url ?? "",
919
922
  code: data?.code ?? "",
920
923
  state: options.state
921
924
  };
@@ -925,7 +928,13 @@ var OAuthResource = class {
925
928
  const data = await this.#http.request({
926
929
  method: "POST",
927
930
  path: "/partner/oauth/token",
928
- body: { code: options.code, redirectUri: options.redirectUri }
931
+ // RFC 6749 §4.1.3 the endpoint requires `grant_type` and the
932
+ // snake_case `redirect_uri` (which must match the authorize request).
933
+ body: {
934
+ grant_type: "authorization_code",
935
+ code: options.code,
936
+ redirect_uri: options.redirectUri
937
+ }
929
938
  });
930
939
  return tokenResponseFromWire(data);
931
940
  }
@@ -934,7 +943,8 @@ var OAuthResource = class {
934
943
  const data = await this.#http.request({
935
944
  method: "POST",
936
945
  path: "/partner/oauth/refresh",
937
- body: { refreshToken }
946
+ // RFC 6749 §6 — refresh grant, snake_case body.
947
+ body: { grant_type: "refresh_token", refresh_token: refreshToken }
938
948
  });
939
949
  return tokenResponseFromWire(data);
940
950
  }
@@ -943,7 +953,7 @@ var OAuthResource = class {
943
953
  const data = await this.#http.request({
944
954
  method: "POST",
945
955
  path: "/partner/oauth/revoke",
946
- body: { playerId }
956
+ body: { player_id: playerId }
947
957
  });
948
958
  return data ?? {};
949
959
  }
@@ -961,13 +971,13 @@ var OAuthResource = class {
961
971
  };
962
972
  function tokenResponseFromWire(data) {
963
973
  const scopeRaw = data?.scope ?? "";
964
- const scopeList = scopeRaw.length > 0 ? scopeRaw.split(",") : [];
974
+ const scopeList = scopeRaw.length > 0 ? scopeRaw.split(/\s+/).filter(Boolean) : Array.isArray(data?.scopes) ? data.scopes : [];
965
975
  return {
966
- accessToken: data?.accessToken ?? "",
967
- refreshToken: data?.refreshToken ?? null,
968
- expiresIn: data?.expiresIn ?? 3600,
976
+ accessToken: data?.access_token ?? "",
977
+ refreshToken: data?.refresh_token ?? null,
978
+ expiresIn: data?.expires_in ?? 3600,
969
979
  scope: Object.freeze(scopeList),
970
- playerId: data?.playerId ?? ""
980
+ playerId: data?.player_id ?? ""
971
981
  };
972
982
  }
973
983
 
@@ -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> = { id: 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\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 const params = new URLSearchParams({\n redirect_uri: config.redirectUri,\n scope: scopeList.join(','),\n response_type: 'code',\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 authorizationUrl?: string;\n code?: string;\n }>({\n method: 'POST',\n path: '/partner/oauth/authorize',\n body: {\n redirectUri: options.redirectUri,\n scope: scopeList.join(','),\n state: options.state,\n },\n });\n\n return {\n authorizationUrl: data?.authorizationUrl ?? '',\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 body: { code: options.code, redirectUri: options.redirectUri },\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 body: { 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: { 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 const scopeRaw = (data?.scope ?? '') as string;\n const scopeList = scopeRaw.length > 0 ? scopeRaw.split(',') : [];\n return {\n accessToken: (data?.accessToken ?? '') as string,\n refreshToken: (data?.refreshToken ?? null) as string | null,\n expiresIn: (data?.expiresIn ?? 3600) as number,\n scope: Object.freeze(scopeList),\n playerId: (data?.playerId ?? '') 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 } 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":[]}
package/dist/index.d.cts CHANGED
@@ -886,6 +886,17 @@ interface OAuthConfig {
886
886
  readonly apiKey: string;
887
887
  readonly redirectUri: string;
888
888
  readonly baseUrl?: string;
889
+ /**
890
+ * Your app's `client_id` — the `PartnerApp.slug` Vairified assigned you
891
+ * (e.g. `dinkr`). Required by the browser `GET /partner/oauth/authorize`
892
+ * endpoint to identify your app; without it the authorization page rejects
893
+ * the request with `invalid_request: client_id is required`.
894
+ *
895
+ * Only needed for this pure-frontend URL helper. The recommended flow —
896
+ * {@link OAuthResource.authorize} on a client — identifies your app by the
897
+ * API key instead, so it needs no `client_id`.
898
+ */
899
+ readonly clientId?: string;
889
900
  }
890
901
  /**
891
902
  * Response from starting an OAuth authorization flow.
package/dist/index.d.ts CHANGED
@@ -886,6 +886,17 @@ interface OAuthConfig {
886
886
  readonly apiKey: string;
887
887
  readonly redirectUri: string;
888
888
  readonly baseUrl?: string;
889
+ /**
890
+ * Your app's `client_id` — the `PartnerApp.slug` Vairified assigned you
891
+ * (e.g. `dinkr`). Required by the browser `GET /partner/oauth/authorize`
892
+ * endpoint to identify your app; without it the authorization page rejects
893
+ * the request with `invalid_request: client_id is required`.
894
+ *
895
+ * Only needed for this pure-frontend URL helper. The recommended flow —
896
+ * {@link OAuthResource.authorize} on a client — identifies your app by the
897
+ * API key instead, so it needs no `client_id`.
898
+ */
899
+ readonly clientId?: string;
889
900
  }
890
901
  /**
891
902
  * Response from starting an OAuth authorization flow.
package/dist/index.js CHANGED
@@ -602,7 +602,7 @@ var MembersResource = class {
602
602
  * ```
603
603
  */
604
604
  async get(playerId, options = {}) {
605
- const query = { id: playerId };
605
+ const query = { memberId: playerId };
606
606
  if (options.sport !== void 0) {
607
607
  query.sport = Array.isArray(options.sport) ? options.sport.join(",") : options.sport;
608
608
  }
@@ -793,9 +793,12 @@ function getAuthorizationUrl(config, options = {}) {
793
793
  const scopeList = ensureProfileRead(options.scopes ?? DEFAULT_SCOPES);
794
794
  const params = new URLSearchParams({
795
795
  redirect_uri: config.redirectUri,
796
- scope: scopeList.join(","),
796
+ scope: scopeList.join(" "),
797
797
  response_type: "code"
798
798
  });
799
+ if (config.clientId) {
800
+ params.set("client_id", config.clientId);
801
+ }
799
802
  if (options.state) {
800
803
  params.set("state", options.state);
801
804
  }
@@ -856,13 +859,13 @@ var OAuthResource = class {
856
859
  method: "POST",
857
860
  path: "/partner/oauth/authorize",
858
861
  body: {
859
- redirectUri: options.redirectUri,
860
- scope: scopeList.join(","),
862
+ redirect_uri: options.redirectUri,
863
+ scope: scopeList.join(" "),
861
864
  state: options.state
862
865
  }
863
866
  });
864
867
  return {
865
- authorizationUrl: data?.authorizationUrl ?? "",
868
+ authorizationUrl: data?.authorization_url ?? "",
866
869
  code: data?.code ?? "",
867
870
  state: options.state
868
871
  };
@@ -872,7 +875,13 @@ var OAuthResource = class {
872
875
  const data = await this.#http.request({
873
876
  method: "POST",
874
877
  path: "/partner/oauth/token",
875
- body: { code: options.code, redirectUri: options.redirectUri }
878
+ // RFC 6749 §4.1.3 the endpoint requires `grant_type` and the
879
+ // snake_case `redirect_uri` (which must match the authorize request).
880
+ body: {
881
+ grant_type: "authorization_code",
882
+ code: options.code,
883
+ redirect_uri: options.redirectUri
884
+ }
876
885
  });
877
886
  return tokenResponseFromWire(data);
878
887
  }
@@ -881,7 +890,8 @@ var OAuthResource = class {
881
890
  const data = await this.#http.request({
882
891
  method: "POST",
883
892
  path: "/partner/oauth/refresh",
884
- body: { refreshToken }
893
+ // RFC 6749 §6 — refresh grant, snake_case body.
894
+ body: { grant_type: "refresh_token", refresh_token: refreshToken }
885
895
  });
886
896
  return tokenResponseFromWire(data);
887
897
  }
@@ -890,7 +900,7 @@ var OAuthResource = class {
890
900
  const data = await this.#http.request({
891
901
  method: "POST",
892
902
  path: "/partner/oauth/revoke",
893
- body: { playerId }
903
+ body: { player_id: playerId }
894
904
  });
895
905
  return data ?? {};
896
906
  }
@@ -908,13 +918,13 @@ var OAuthResource = class {
908
918
  };
909
919
  function tokenResponseFromWire(data) {
910
920
  const scopeRaw = data?.scope ?? "";
911
- const scopeList = scopeRaw.length > 0 ? scopeRaw.split(",") : [];
921
+ const scopeList = scopeRaw.length > 0 ? scopeRaw.split(/\s+/).filter(Boolean) : Array.isArray(data?.scopes) ? data.scopes : [];
912
922
  return {
913
- accessToken: data?.accessToken ?? "",
914
- refreshToken: data?.refreshToken ?? null,
915
- expiresIn: data?.expiresIn ?? 3600,
923
+ accessToken: data?.access_token ?? "",
924
+ refreshToken: data?.refresh_token ?? null,
925
+ expiresIn: data?.expires_in ?? 3600,
916
926
  scope: Object.freeze(scopeList),
917
- playerId: data?.playerId ?? ""
927
+ playerId: data?.player_id ?? ""
918
928
  };
919
929
  }
920
930
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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 — 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> = { id: 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\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 const params = new URLSearchParams({\n redirect_uri: config.redirectUri,\n scope: scopeList.join(','),\n response_type: 'code',\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 authorizationUrl?: string;\n code?: string;\n }>({\n method: 'POST',\n path: '/partner/oauth/authorize',\n body: {\n redirectUri: options.redirectUri,\n scope: scopeList.join(','),\n state: options.state,\n },\n });\n\n return {\n authorizationUrl: data?.authorizationUrl ?? '',\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 body: { code: options.code, redirectUri: options.redirectUri },\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 body: { 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: { 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 const scopeRaw = (data?.scope ?? '') as string;\n const scopeList = scopeRaw.length > 0 ? scopeRaw.split(',') : [];\n return {\n accessToken: (data?.accessToken ?? '') as string,\n refreshToken: (data?.refreshToken ?? null) as string | null,\n expiresIn: (data?.expiresIn ?? 3600) as number,\n scope: Object.freeze(scopeList),\n playerId: (data?.playerId ?? '') 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/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 — 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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vairified",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Official TypeScript/JavaScript SDK for the Vairified Partner API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",