# Types reference

TypeScript type definitions for the Wavedash SDK

Source: https://docs.wavedash.com/sdk/types

This page documents the shared TypeScript types used throughout the Wavedash SDK. For method signatures and usage examples, see the [Functions reference](/sdk/functions) or the individual feature pages under the [SDK](/sdk) and [Multiplayer](/multiplayer) sections.

## Response types

### WavedashResponse

Most async service calls return a `WavedashResponse` wrapper. Synchronous getters such as `getUser()` do not.

```typescript
interface WavedashResponse<T> {
  success: boolean;     // Whether the operation succeeded
  data: T | null;       // Result data (null on failure)
  message?: string;     // Error message if success is false
}
```

**Example usage:**

```typescript
const user = Wavedash.getUser(); // sync getter

const response = await Wavedash.getLeaderboard("high-scores");

if (response.success) {
  const leaderboard: Leaderboard = response.data;
  // Use leaderboard...
} else {
  console.error(response.message);
}
```

## Configuration types

### WavedashConfig

SDK configuration options:

```typescript
interface WavedashConfig {
  debug?: boolean;                       // Useful for logging and testing — enables verbose output in the browser console
  deferEvents?: boolean;                 // Lets your game finish setup before handling lobby/multiplayer events
  p2p?: Partial<P2PConfig>;             // P2P networking configuration (see P2PConfig below)
}
```

All config options are optional.

### P2PConfig

Peer-to-peer networking configuration:

```typescript
interface P2PConfig {
  enableReliableChannel: boolean;  // TCP-like channel
  enableUnreliableChannel: boolean; // UDP-like channel
  messageSize?: number;            // Max bytes per message slot (default: 2048, max: 65536)
  maxIncomingMessages?: number;    // Incoming message queue depth (default: 1024)
}
```

## Launch param types

### GameLaunchParams

Key-value mapping of URL query parameters that were present when the game launched. See [SDK setup](/sdk/setup#launch-params) for details.

```typescript
interface GameLaunchParams {
  lobby?: string;              // Lobby ID if the player followed an invite link
  [key: string]: string | undefined; // Any other wvdsh_-prefixed params
}
```

## Leaderboard types

### Leaderboard

```typescript
interface Leaderboard {
  id: Id<"leaderboards">;              // Leaderboard ID
  name: string;                        // Display name
  sortOrder: LeaderboardSortOrder;     // 0 = ASC, 1 = DESC
  displayType: LeaderboardDisplayType; // See LeaderboardDisplayType below
  totalEntries: number;                // Total number of entries
}
```

### LeaderboardSortOrder

```typescript
// 0 = ascending  — Lower scores rank higher (time trials, golf)
// 1 = descending — Higher scores rank higher (points, high scores)
type LeaderboardSortOrder = 0 | 1;
```

### LeaderboardDisplayType

```typescript
// 0 = numeric           — Display as a number (e.g., "1,000")
// 1 = time_seconds      — Display as time in seconds (e.g., "1:23")
// 2 = time_milliseconds — Display as time with milliseconds (e.g., "1:23.456")
// 3 = time_game_ticks   — Display as game ticks (assumes 60fps)
type LeaderboardDisplayType = 0 | 1 | 2 | 3;
```

### LeaderboardEntry

```typescript
interface LeaderboardEntry {
  userId: Id<"users">;                  // Player's user ID
  username?: string;                    // Player's display name
  score: number;                        // Score value
  globalRank: number;                   // Current rank
  ugcId?: Id<"userGeneratedContent">;   // Attached UGC (optional)
  timestamp: number;                    // Submission timestamp
  metadata?: Uint8Array;                // Optional binary metadata
}
```

### UpsertedLeaderboardEntry

Returned from `uploadLeaderboardScore`. A **different** shape from `LeaderboardEntry` — it reports what changed on upload. It carries your saved standing (`score` / `globalRank`) alongside the submitted attempt (`submittedScore` / `submittedRank`), which differ when `keepBest` kept a better existing score. See [Leaderboards](/sdk/leaderboards#upsertedleaderboardentry) for details.

```typescript
interface UpsertedLeaderboardEntry {
  entryId: Id<"leaderboardEntries">;
  score: number;                        // Your saved standing's score
  scoreChanged: boolean;                // false if keepBest kept a better score
  globalRank: number;                   // Your saved standing's rank
  submittedScore: number;               // The score you just submitted
  submittedRank: number;                // Where that submitted run would rank
  userId: Id<"users">;
  username: string;
  userAvatarUrl?: string;
}
```

## Lobby types

### Lobby

```typescript
interface Lobby {
  lobbyId: Id<"lobbies">;            // Lobby ID
  visibility: LobbyVisibility;       // Access level
  maxPlayers: number;                // Player limit
  playerCount: number;               // Current count
  metadata: Record<string, unknown>; // Custom data
}
```

### LobbyVisibility

```typescript
// 0 = public       — Anyone can find and join
// 1 = friends_only — Only friends can see and join
// 2 = private      — Only joinable with the lobby ID
type LobbyVisibility = 0 | 1 | 2;
```

### LobbyUser

```typescript
interface LobbyUser {
  lobbyId: Id<"lobbies">;       // Lobby ID
  userId: Id<"users">;          // User ID
  username: string;             // Display name
  userAvatarUrl?: string;       // Avatar URL
  isHost: boolean;              // Whether this user is the host
}
```

### LobbyMessage

```typescript
interface LobbyMessage {
  messageId: string;            // Message ID
  lobbyId: Id<"lobbies">;       // Lobby ID
  userId: Id<"users">;          // Sender's ID
  username: string;             // Sender's name
  message: string;              // Message text
  timestamp: number;            // Timestamp
}
```

### LobbyInvite

```typescript
interface LobbyInvite {
  notificationId: string;       // Notification ID
  lobbyId: Id<"lobbies">;       // ID of the lobby you're invited to
  sender: {
    _id: Id<"users">;           // User ID of who sent the invite
    username: string;           // Username of who sent the invite
    avatarUrl?: string;         // Avatar URL of the sender
  };
  _creationTime: number;        // When the invite was sent
}
```

## Friend types

### Friend

```typescript
interface Friend {
  userId: Id<"users">;   // Friend's user ID
  username: string;      // Friend's display name
  avatarUrl?: string;    // Avatar URL (if set)
  isOnline: boolean;     // Whether the friend is currently online
}
```

## P2P types

### P2PConnection

```typescript
interface P2PConnection {
  lobbyId: Id<"lobbies">;
  peers: Record<Id<"users">, P2PPeer>;
  state: P2PConnectionState;
}
```

### P2PConnectionState

```typescript
type P2PConnectionState =
  | "connecting"
  | "connected"
  | "disconnected"
  | "failed";
```

### P2PPeer

```typescript
interface P2PPeer {
  userId: Id<"users">;   // Peer's user ID
  username: string;      // Peer's display name
}
```

### P2PMessage

```typescript
interface P2PMessage {
  fromUserId: Id<"users">;   // Sender's user ID
  channel: number;           // Channel number (0-7)
  payload: Uint8Array;  // Binary data
}
```

## UGC types

### UGCType

```typescript
// UGC types are integer values:
// 0 = SCREENSHOT    - Player-captured screenshot
// 1 = VIDEO         - Player-captured video
// 2 = COMMUNITY     - Community-created content (levels, mods, etc.)
// 3 = GAME_MANAGED  - Game-managed content (replays, saves)
// 4 = OTHER         - Other UGC types
type UGCType = 0 | 1 | 2 | 3 | 4;
```

In JavaScript use `Wavedash.UGCType.SCREENSHOT` / `VIDEO` / `COMMUNITY` / `GAME_MANAGED` / `OTHER` instead of the raw integer. In Godot, use constants like `WavedashConstants.UGC_TYPE_SCREENSHOT`; in Unity, use `WavedashConstants.UGCItemType.SCREENSHOT`.

### UGCVisibility

```typescript
// UGC visibility is an integer value:
// 0 = PUBLIC  - Anyone can view
// 2 = PRIVATE - Only the creator can view
type UGCVisibility = 0 | 2;
```

## Storage types

### RemoteFileMetadata

```typescript
interface RemoteFileMetadata {
  exists: boolean;     // Whether file exists
  key: string;         // Full storage key
  name: string;        // Filename
  lastModified: number; // Unix timestamp
  size: number;        // Size in bytes
  etag: string;        // Version identifier
}
```

## Engine types

### EngineInstance

Interface for game engine instances:

```typescript
interface EngineInstance {
  type: "GODOT" | "UNITY" | "UNREAL";

  // Send message to engine
  SendMessage(
    objectName: string,
    methodName: string,
    value?: string | number | boolean
  ): void;

  // Emscripten filesystem API
  FS: {
    readFile(path: string, opts?: Record<string, unknown>): string | Uint8Array;
    writeFile(path: string, data: string | ArrayBufferView, opts?: Record<string, unknown>): void;
    mkdirTree(path: string, mode?: number): void;
    syncfs(populate: boolean, callback?: (err: unknown) => void): void;
    analyzePath(path: string): { exists: boolean };
  };
}
```

## ID types

The SDK uses Convex-style branded `Id<"tableName">` types — opaque strings tagged with the table they belong to so the type system catches accidental cross-mixing (e.g. passing a `Id<"users">` where an `Id<"lobbies">` is expected).

```typescript
import type { Id } from "@wvdsh/sdk-js";

type UserId = Id<"users">;
type LobbyId = Id<"lobbies">;
type LeaderboardId = Id<"leaderboards">;
type UGCId = Id<"userGeneratedContent">;
```

The aliases above are illustrative — in your own code, prefer writing `Id<"users">` directly so the table name is visible at the callsite.

<Note>
IDs are opaque branded strings. Don't parse or construct them manually — always use the IDs returned from SDK methods.
</Note>
