CommonJS wrapper for the Yunite API: 38 documented HTTP operations, the custom-state WebSocket, and makeRequest() for undocumented routes.
pnpm add yuniteVersion 2.3.0 adds complete documented API coverage while retaining legacy runtime call signatures and response shapes.
const { YuniteApi } = require('yunite');
const client = new YuniteApi(process.env.YUNITE_API_TOKEN);
async function main() {
try {
const response = await client.getUserLinks('guildId', {
type: 'DISCORD',
userIds: ['discordUserId']
});
console.log(response.data.users.length);
} catch (error) {
console.error('Yunite request failed', {
status: error.response?.status,
code: error.code
});
} finally {
client.dispose();
}
}
main();Use one long-lived client per token/environment so requests share rate-limit state. Independent clients/processes do not share a limiter. Never log API tokens, raw Axios responses/errors, WebSocket URLs, or custom matchmaking keys.
require('yunite').YuniteApi, thelib/Clientdefault export, and all existing method names remain available.new YuniteApi(token, beta, suppressLogs)still works. The last two arguments are optional. Beta continues to usehttps://beta.yunite.xyz/api/v3.- Existing HTTP methods return full Axios responses, except
addTeamandaddTeams, which still return raw bodies. getTournaments(guildId)retains the legacy array; the server may cap its size. Use explicit pagination for full history.getSingleLeaderboard(guildId, tournamentId, sessionId)still sendsincludeLive=true. It does not request location history unless asked.- Support-stat timestamps remain UNIX seconds; zero is not omitted.
- Legacy type names, including
BlocKUserResponseData, and extensionless/.tsdeep type imports remain supported. - The incorrect team-return declarations now describe the runtime body. Code that relied on nonexistent
.data/.statusfields needs correction. - No automatic 5xx, network-error, or 409 retries. A write may already have completed; reconcile custom-session state before retrying.
- Unsafe foreign-origin URLs, API-path traversal, malformed IDs/configuration and invalid numeric options are rejected. Caller options are no longer mutated.
- Most body/business validation remains on Yunite so existing server errors, future fields, explicit nulls, and partial updates retain their meaning.
The optional fourth constructor argument sets defaults:
const client = new YuniteApi(token, false, true, {
timeout: 15000,
requestTimeout: 30000,
maxRetries: 3
});
const controller = new AbortController();
await client.getApp(false, {
signal: controller.signal,
timeout: 5000,
requestTimeout: 10000,
maxRetries: 1
});timeout is Axios's per-attempt network timeout. requestTimeout covers queueing, cooldowns and all attempts. Both default to 0 (disabled) to preserve slow legacy calls. Values are integer milliseconds, at most 2,147,483,647. maxRetries counts additional attempts after an eligible 429 and defaults to 3; set 0 to return immediately. Daily lookup-quota exhaustion is returned immediately. Stream bodies are never automatically replayed.
Every HTTP convenience method accepts an optional final request-options argument. Methods with query/round parameters require an empty query or undefined placeholder when only passing transport options. dispose() cancels pending/active requests and terminates managed WebSockets; a disposed client cannot be reused.
Rate limits use bucket IDs and millisecond deadlines, serialize requests within each known bucket, and let unrelated buckets proceed independently. A bucket cannot be identified before the API first returns its header. Idle route mappings are bounded once their cooldown expires; API payloads are not cached.
const legacy = await client.getTournaments('guildId'); // data is an array
const page = await client.getTournaments('guildId', {
page: 1,
pageSize: 100,
after: '2026-01-01T00:00:00Z'
}); // data has tournaments and pagination
const result = await client.getSingleLeaderboard('guildId', 'tournamentId', 'sessionId', {
round: 0,
includeLive: false,
includeLocations: true
});
const logs = await client.getCustomMatchLogs('guildId', {
start: '2026-01-01T00:00:00Z',
end: '2026-01-02T00:00:00Z',
mode: ['SOLO', 'DUO'],
pageSize: 100
});
// Pass logs.data.nextCursor back unchanged with the same filters.Optional rounds are omitted from the URL, allowing the server's BR/Creative defaults. Repeated log filters are encoded as repeated query parameters. No helper silently merges pages or changes response envelopes.
await client.createOrUpdateTournament('guildId', {
id: 'tournamentId',
prizePool: null // clear only this field; leave other settings unchanged
});
const team = await client.addTeam('guildId', 'tournamentId', {
id: 'teamId',
players: null,
disqualified: true
});
const bulk = await client.addTeams('guildId', 'tournamentId', [
{players: [{epicId: 'epicId'}]}
]);
// Inspect bulk.successTeams and bulk.errorTeams, even after HTTP 200.The API accepts both matchTemplates and legacy matchTemplate for writes. Its response uses a matchTemplate array. Reuse template IDs when updating. Write-only apps may receive just {id}. Creation requirements and premium/permission rules are enforced by Yunite.
const socket = await client.connectCustomState('guildId', {
handshakeTimeout: 10000,
onMessage(data) {
try {
const message = JSON.parse(data.toString());
if (message.op === 0) return; // ping
if (message.op === 1) {
console.log('Received a custom-state update');
// Match the hosting session id to openCustomSession().data.createdId.
}
} catch {
console.error('Invalid custom-state frame');
}
},
onError() {
console.error('Custom-state connection failed');
}
});
// Connect first, then call openCustomSession when appropriate.
// socket.close() closes this stream; client.dispose() closes all managed streams.Each call gets a fresh five-second, single-use token and connects immediately. The API key is never included in the socket URL or handshake headers. onMessage is attached before the initial state probe. Raw op/data envelopes are preserved. Call connectCustomState again after a disconnect; there is no hidden reconnect loop or session mutation.
getCustomStateStreamUrl(guildId, requestOptions?) is available for external WebSocket clients. Do not cache or log the returned URL. For dependency injection, connectCustomState accepts a webSocketFactory(url, options) returning a ws-compatible socket.
import { YuniteApi, type Tournament, type CustomStateMessage } from 'yunite';
const client = new YuniteApi(process.env.YUNITE_API_TOKEN!);
const response = await client.makeRequest<{ enabled: boolean }>(
'PATCH',
'/future/route',
{ timeout: 5000 },
{ enabled: true }
);makeRequest(method, endpoint, options?, body?) accepts relative paths and same-origin absolute URLs under the configured API prefix. PUT/PATCH/DELETE bodies work; numeric bodies are encoded as JSON. Existing unparameterized TypeScript calls retain Axios's historical default data type; supply a generic for a checked response.
All public request/response types are exported from the package root. See API_ROUTES.md for all method signatures and routes. The package ships declaration files; old lib/Parameters.ts and lib/Responses.ts paths are type-only compatibility shims.
From the repository root:
pnpm --dir yuniteapi install --frozen-lockfile
pnpm --dir yuniteapi test
pnpm --dir yuniteapi run typecheck
pnpm --dir yuniteapi run check:packageTests use mocked responses, deterministic clocks and local HTTP/WebSocket servers. The package check creates a temporary tarball and installs it into an isolated consumer to verify CommonJS, ESM and strict TypeScript imports. It does not publish. CI checks Node 20, 22 and 24. Keep both dependency lockfiles synchronized when updating dependencies.