Vairified TypeScript SDK - v0.3.1
    Preparing search index...

    Migrating from 0.1.x

    Version 0.2.0 is a breaking rewrite of the SDK surface to match the multi-sport Partner API v1. This guide walks through the changes and shows how to port existing code.

    See CHANGELOG.md for the full release notes.

    0.1.x 0.2.0
    client.getMember(id) client.members.get(id)
    client.search({...}) returning SearchResults for await (const m of client.members.search({...}))
    client.findPlayer(name) client.members.find(name)
    client.submitMatch(match) client.matches.submit(batch)
    client.submitMatches([m1, m2]) client.matches.submit(batch) (put both in batch.matches)
    client.getRatingUpdates() client.members.ratingUpdates()
    client.startOAuth({...}) client.oauth.authorize({...})
    client.exchangeToken(...) client.oauth.exchangeToken({...})
    client.refreshAccessToken(rt) client.oauth.refresh(rt)
    client.revokeConnection(id) client.oauth.revoke(id)
    client.getLeaderboard({...}) client.leaderboard.list({...})
    client.getPlayerRank(...) client.leaderboard.rank(...)
    client.getUsage() client.usage()
    member.rating (single sport) member.ratingFor('pickleball')
    member.ratingSplits.gender member.sport.get('pickleball')?.get('gender-open')?.rating
    member.isVairified member.status.isVairified
    new Match({ team1, team2, scores }) MatchInput with teams: string[][] and games: GameInput[]

    All operations now live on sub-resources that mirror the REST path. The flat client.* methods are gone.

    // Before
    const member = await client.getMember('vair_mem_xxx');
    const results = await client.search({ city: 'Austin' });
    await client.submitMatch(match);

    // After
    const member = await client.members.get('vair_mem_xxx');
    for await (const m of client.members.search({ city: 'Austin' })) { /* ... */ }
    await client.matches.submit(batch);

    The biggest conceptual change. In 0.1.x, every Member had a single rating and a flat ratingSplits object. In 0.2.0, rating data lives under member.sport keyed by sport code, so the same SDK can represent a player's pickleball and padel ratings in one call.

    // Before
    member.rating; // 3.915
    member.ratingSplits.gender; // 3.880
    member.ratingSplits.singles; // 3.710
    member.isVairified; // true

    // After
    member.ratingFor('pickleball'); // 3.915
    member.sport.get('pickleball')?.get('gender-open')?.rating; // 3.880
    member.sport.get('pickleball')?.get('singles-open')?.rating; // 3.710
    member.status.isVairified; // true

    MemberSportMap and SportRating are both dict-like — subscript access, iteration, and membership checks all work:

    const pb = member.sport.get('pickleball');
    if (pb) {
    console.log(pb.size, 'splits');
    if (pb.has('singles-open')) {
    console.log(pb.get('singles-open')?.rating);
    }
    for (const [key, split] of pb) {
    console.log(key, split.rating, split.abbr);
    }
    }

    Fetch ratings for just the sports you care about with the sport filter:

    // All sports this player has ratings in
    const member = await client.members.get('vair_mem_xxx');

    // Just pickleball
    const member2 = await client.members.get('vair_mem_xxx', { sport: 'pickleball' });

    // Multiple sports
    const member3 = await client.members.get('vair_mem_xxx', {
    sport: ['pickleball', 'padel'],
    });

    In 0.1.x, client.search() returned a SearchResults object with nextPage(). In 0.2.0, client.members.search() is an async iterator that fetches pages lazily as you iterate:

    // Before
    let results = await client.search({ city: 'Austin', limit: 20 });
    while (results.hasMore) {
    for (const player of results.players) {
    console.log(player.name);
    }
    results = await results.nextPage();
    }

    // After
    for await (const member of client.members.search({ city: 'Austin' })) {
    console.log(member.name);
    }

    // Cap the total
    for await (const m of client.members.search({ name: 'Smith', maxResults: 50 })) {
    // ...
    }

    Match has been restructured to natively support any match shape — singles, doubles, 3-way round robin, best-of-N — through a single schema. Submit matches as a MatchBatch that carries shared defaults:

    // Before
    const match = new Match({
    event: 'Weekly League',
    bracket: '4.0 Doubles',
    date: new Date(),
    team1: ['p1', 'p2'],
    team2: ['p3', 'p4'],
    scores: [[11, 9], [11, 7]],
    });
    const result = await client.submitMatch(match);

    // After
    const result = await client.matches.submit({
    sport: 'pickleball', // NEW: sport code is required
    winScore: 11, // NEW: so the rater can interpret scores
    winBy: 2,
    bracket: '4.0 Doubles',
    event: 'Weekly League',
    matchDate: '2026-04-11T14:00:00Z',
    matches: [
    {
    identifier: 'm1',
    teams: [['p1', 'p2'], ['p3', 'p4']],
    games: [{ scores: [11, 9] }, { scores: [11, 7] }],
    },
    ],
    });

    Singles becomes teams: [['p1'], ['p2']]. A 3-way round robin becomes teams: [['p1'], ['p2'], ['p3']]. Each GameInput scores one entry per team in the same order.

    The OAuth methods moved to the client.oauth sub-resource. Signatures now take a single options object:

    // Before
    const auth = await client.startOAuth({
    redirectUri: '...',
    scopes: [...],
    state: '...',
    });
    const tokens = await client.exchangeToken(code, redirectUri);
    const newTokens = await client.refreshAccessToken(refreshToken);
    await client.revokeConnection(playerId);

    // After
    const auth = await client.oauth.authorize({
    redirectUri: '...',
    scopes: [...],
    state: '...',
    });
    const tokens = await client.oauth.exchangeToken({ code, redirectUri });
    const newTokens = await client.oauth.refresh(refreshToken);
    await client.oauth.revoke(playerId);

    OAuthScope is now a string literal union, so TypeScript catches typos:

    import type { OAuthScope } from 'vairified';

    const scopes: OAuthScope[] = ['profile:read', 'rating:read']; // ok
    const bad: OAuthScope[] = ['profile:read', 'rating']; // type error

    Response models (Member, SportRating, RatingUpdate, etc.) are now frozen class instances. Attempts to mutate a field throw in strict mode. Every model has a useful toString() and, where appropriate, Symbol.iterator.

    The top-level is* booleans on Member are now grouped under member.status:

    // Before
    member.isVairified;
    member.isWheelchair;
    member.isAmbassador;

    // After
    member.status.isVairified;
    member.status.isWheelchair;
    member.status.isAmbassador;
    member.status.isRater; // NEW
    member.status.isConnected; // NEW
    // Before
    const client = new Vairified({
    apiKey: 'vair_pk_xxx',
    baseUrl: 'https://api-staging.vairified.com/api/v1',
    });

    // After — preset
    const client = new Vairified({ apiKey: 'vair_pk_xxx', env: 'staging' });

    // After — explicit resource management (TS 5.2+, Node 20+)
    await using client = new Vairified({ apiKey: 'vair_pk_xxx' });
    // client.close() is called automatically at block exit

    Supported environments: "production" (default), "staging", "local". Reads VAIRIFIED_ENV from the environment when not supplied.