goban
Version:
[](https://opensource.org/licenses/Apache-2.0) [](https://deepwiki.com/online-go/goban)
806 lines (805 loc) • 28.2 kB
TypeScript
import type { JGOFMove, JGOFPlayerClock, JGOFSealingIntersection } from "../formats/JGOF";
import type { ReviewMessage } from "../GobanEngine";
import type { ConditionalMoveResponse } from "../ConditionalMoveTree";
/** Messages that clients send, regardless of target server */
export interface ClientToServerBase {
/** Authenticate with the server.
*
* Prior to authentication, you should perform a GET request to
* `/api/v1/ui/config`
* to get the current configuration. Within the returned JSON
* you will find all of the necessary fields to authenticate.
*/
"authenticate": (data: {
/** The JSON Web Token (`user_jwt` field) from `/api/v1/ui/config`. If
* connecting as a guest, send "" */
jwt: string;
/** Client generated unique id for the device. */
device_id?: string;
/** Browser user agent (or websocket library) */
user_agent?: string;
/** ISO 639-1 language code used on this device. */
language?: string;
/** The version of the translation dictionary. */
language_version?: string;
/** Client name (your application name) */
client?: string;
/** Client version string. */
client_version?: string;
/** Bot username connecting, if applicable */
bot_username?: string;
/** Bot API key, if applicable */
bot_apikey?: string;
}) => {
id: number;
username: string;
} | undefined;
/** Sends a ping to the server. This message should be
* sent regularly. The default interval is 10 seconds.
* This keeps the connection alive and allows a client
* to measure clock drift and latency, both of which
* are vital to adjusting the client's game clock displays.
*/
"net/ping": (data: {
/** Client timestamp - milliseconds since epoch */
client: number;
/** Last clock drift measurement, or `0` */
drift: number;
/** Last latency measurement, or `0` */
latency: number;
}) => void;
}
/** This is an exhaustive list of the messages that the client can send
* to the server.
*
* This documentation is generated from the official typescript interface.
* To interpret it, you will every message organized as the name of the
* message followed by a function taking the message data parameters and
* returning what you can expect tor receive back.
*
* For example, the authentication message documentation looks like this:
*
* ```typescript
* authenticate: ((data: {
* bot_apikey?: string;
* bot_username?: string;
* client?: string;
* client_version?: string;
* device_id?: string;
* jwt: string;
* language?: string;
* language_version?: string;
* user_agent?: string;
* }) => undefined | {
* id: number;
* username: string;
* })
* ```
*
* The command you will send is `authenticate`, the data you send will be an object with the following format:
* ```typescript
* {
* bot_apikey?: string;
* bot_username?: string;
* client?: string;
* client_version?: string;
* device_id?: string;
* jwt: string;
* language?: string;
* language_version?: string;
* user_agent?: string;
* }
* ```
*
* and you can expect to receive back either `undefined` or `{id: number, username: string}`
*
*/
export interface ClientToServer extends ClientToServerBase {
/** Get active automatch entries for the current user */
"automatch/list": (data: {}) => void;
/** Message to let the server know the client is still interested
* in the specified blitz or live challenge. These should be sent
* about once a second to prevent the server from canceling the challenge.
*/
"challenge/keepalive": (data: {
challenge_id: number;
game_id: number;
}) => void;
/** Connect to a game. Once connected, the client will receive game
* updates relevant to the game. */
"game/connect": (data: {
/** The game id to connect to */
game_id: number;
/** If true, the client will receive the game chat log and new chat events */
chat?: boolean;
}) => void;
/** Disconnect from a game. This will stop game updates for a particular game. */
"game/disconnect": (data: {
game_id: number;
}) => void;
/** Sets removed stones in the stone removal phase. */
"game/removed_stones/set": (data: {
/** The game id */
game_id: number;
/** True if the stones should be marked as removed (or intersections marked
* as dame if there is no stone there), false if they should be marked as
* not removed / open area. */
removed: boolean;
/** List of intersections that are to be removed. */
stones: JGOFMove[] | string;
/** List of intersections that need to be sealed before the game can be
* correctly scored. Note, if this is undefined, the value will not
* be changed on the server side. To specify there are no more intersections
* that need to be cleared, set it to `[]` specifically.
*/
needs_sealing?: JGOFSealingIntersection[];
/** Japanese rules technically have some special scoring rules about
* whether territory in seki should be counted or not. This is supported
* by the backend but the official client no longer displays this as an
* option to the user as it was very largely unused and was a large
* source of confusion. This field is deprecated and will likely be
* removed in the future.*/
strict_seki_mode?: boolean;
}) => void;
/** Rejects the removed stones and resumes the game from the stone removal phase */
"game/removed_stones/reject": (data: {
/** The game id */
game_id: number;
}) => void;
/** Accepts the stones as removed. Once both players have accepted the same
* stones, the stone removal phase will conclude and the game will finish. */
"game/removed_stones/accept": (data: {
/** The game id */
game_id: number;
/** All of the stones that are accepted as removed, and all
* intersections marked as dame */
stones: string;
/** Japanese rules technically have some special scoring rules about
* whether territory in seki should be counted or not. This is supported
* by the backend but clients should always set this to false in this
* era of the game, the official client no longer displays this as an
* option to the user as it was very largely unused and was a large
* source of confusion. */
strict_seki_mode: boolean;
}) => void;
/** Submit a move for a game */
"game/move": (data: {
/** The game id */
game_id: number;
/** The move number to play at */
move: string;
/** Maximum number of milliseconds the client was out of focus between
* the last move and this move */
blur?: number;
/** Clock according to the client. If this is within the margin of
* error of the server's clock, the server will accept the new
* clock value. If not provided, the server clock will be used. */
clock?: JGOFPlayerClock;
}) => void;
/** Requests an undo */
"game/undo/request": (data: {
/** The game id */
game_id: number;
/** The current move number */
move_number: number;
}) => void;
/** Accepts an undo */
"game/undo/accept": (data: {
/** The game id */
game_id: number;
/** The current move number */
move_number: number;
}) => void;
/** Cancels an undo request */
"game/undo/cancel": (data: {
/** The game id */
game_id: number;
/** The current move number */
move_number: number;
}) => void;
/** Pauses the game clocks */
"game/pause": (data: {
/** The game id */
game_id: number;
}) => void;
/** Resumes the game clocks */
"game/resume": (data: {
/** The game id */
game_id: number;
}) => void;
/** Resigns from the game */
"game/resign": (data: {
/** The game id */
game_id: number;
}) => void;
"game/delayed_resign": (data: {
/** The game id */
game_id: number;
}) => void;
"game/clear_delayed_resign": (data: {
/** The game id */
game_id: number;
}) => void;
/** Cancels a game. This is effectively the same as resign, except the
* game will not be ranked. This is only allowed within the first few
* moves of the game. (See GobanEngine.gameCanBeCancelled for cancellation ) */
"game/cancel": (data: {
/** The game id */
game_id: number;
}) => void;
/** In Japanese rules, if the game is found to be repeating, the players
* may opt to annul the entire game and start over.
*
* This is largely undesired in an online setting and support for this
* will probably be removed in the future, dont' bother implementing
* this.
*/
"game/annul": (data: {
/** The game id */
game_id: number;
}) => void;
/** Request the server end a game that is being stalled by one of the
* players. This will only work if the server agrees in the outcome. */
"game/prevent_stalling": (data: {
/** The game id */
game_id: number;
/** The proposed winner */
winner: "black" | "white";
}) => void;
/** Request the server end a game that someone has left without resigning
* from */
"game/prevent_escaping": (data: {
/** The game id */
game_id: number;
/** The proposed winner */
winner: "black" | "white";
/** Request that the game be annulled or not */
annul: boolean;
}) => void;
/** Inform the server that the client believes it's clock has timed out
* and the game should be ended in a timeout. This is not strictly necessary
* to implement as the server will also timeout games, however there is
* a grace period to account for network latency, so well behaved clients
* can (and should) send this message to be very exact with timeouts. */
"game/timed_out": (data: {
/** The game id */
game_id: number;
}) => void;
/** Sets conditional moves to be made on behalf of the player in response
* to a move by the opponent. */
"game/conditional_moves/set": (data: {
/** The game id */
game_id: number;
/** The move number from which the conditional moves are rooted in */
move_number: number;
/** The conditional moves. The top level should be an array that looks
* like `[null, { ... }]` where the second element contains the responses
* to the opponent's move. */
conditional_moves: ConditionalMoveResponse;
}) => void;
/** Sends a chat message to a game */
"game/chat": (data: {
/** The game id */
game_id: number;
/** The type of chat message being sent */
type: "main" | "malkovich" | "moderator" | "hidden" | "personal";
/** The move number currently being viewed */
move_number: number;
/** The chat message */
body: string | GameChatTranslatedMessage | GameChatAnalysisMessage | GameChatReviewMessage;
}) => void;
/** Update your latency information for a particular game. This is used
* for clock synchronization. It is not strictly required, however strongly
* suggested for live games. */
"game/latency": (data: {
/** The game id */
game_id: number;
/** Network latency, measured in milliseconds. See net/ping to measure this. */
latency: number;
}) => void;
/** Connects to a review */
"review/connect": (data: {
/** The review id */
review_id: number;
}) => void;
/** Disconnects from a review */
"review/disconnect": (data: {
/** The review id */
review_id: number;
}) => void;
/** Append a review action to the review log. */
"review/append": (data: ReviewMessage) => void;
/** Sends a chat message to a review */
"review/chat": (data: {
/** The review id */
review_id: number;
/** The root of the branch the user is viewing */
from: number;
/** The analysis branch the user is viewing */
moves: string;
/** The chat message */
body: string;
}) => void;
/** Request the number of unique authenticated players
* online within the given interval */
"stats/online": (data: {
/** Interval in seconds */
interval: number;
}) => number;
/** Deletes a notification */
"notification/delete": (data: {
notification_id: string;
}) => void;
/** Connects to the game list count.
* Once connected you'll start receiving `gamelist-count` or
* `gamelist-count-${channel}` messages.
*/
"gamelist/count/subscribe": (data: {
/** The group or tournament channel to subscribe to. If no
* channel is provided, the global server counts will be
* sent */
channel?: string;
}) => void;
/** Disconnects from the game list count */
"gamelist/count/unsubscribe": (data: {
/** The group or tournament channel to unsubscribe from. If no
* channel is provided, the global server counts will be
* unsubscribed from */
channel?: string;
}) => void;
/** Queries the server for a list of games */
"gamelist/query": (data: {
list: "live" | "corr" | "kidsgo";
sort_by: "rank";
/** Filtering options */
where: GameListWhere;
/** The number of games to skip before returning results */
from: number;
/** Number of games to return, between 1 and 300 */
limit: number;
/** The group or tournament channel to query */
channel?: string;
}) => undefined | {
list: string;
by: string;
size: number;
where: GameListWhere;
from: number;
limit: number;
results: GameListEntry[];
};
/** Returns an event log for the given game. This is primarily
* for moderation purposes, although the endpoint is generally
* available to all users. */
"game/log": (data: {
game_id: number;
}) => {
timestamp: string;
event: string;
data: any;
}[];
/** Subscribes to online status updates for the given player ids */
"user/monitor": (data: {
user_ids: number[];
}) => void;
/** Sends an "Inter Tab Communication" message to all other connected
* clients for the current user. This includes other devices, so the
* "Tab" part is a bit of a misnomer. */
"itc": (data: {
/** User defined event string */
event: string;
/** User defined data */
data: any;
}) => void;
/** Set the given key in the remote storage system for this user
*
* For more details on the remote storage replication system see:
* https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts
*/
"remote_storage/set": (data: {
key: string;
value: any;
replication: RemoteStorageReplication;
}) => {
error?: string;
retry?: boolean;
} | {
success: true;
};
/** Remove the given key from remote storage system for this user
*
* For more details on the remote storage replication system see:
* https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts
*/
"remote_storage/remove": (data: {
key: string;
replication: RemoteStorageReplication;
}) => {
error?: string;
retry?: boolean;
} | {
success: true;
};
/** Requests all updated key/value pairs for this user since the
* provided timestamp (as as ISO 8601 string).
*
* For more details on the remote storage replication system see:
* https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts
*/
"remote_storage/sync": (data: {
/** ISO 8601 timestamp. Updates made after this timestamp will be sent to the client. */
since: string;
}) => {
error?: string;
retry?: boolean;
} | {
success: true;
};
/** Sets a channel topic */
"chat/topic": (data: {
channel: string;
topic: string;
}) => void;
/** Sends a chat message to the given channel */
"chat/send": (data: {
/** Channel to send the message to */
channel: string;
/** ID for the message */
uuid: string;
/** Message text */
message: string;
}) => void;
/** Join a chat channel */
"chat/join": (data: {
/** Channel to join */
channel: string;
}) => void;
/** Leave a channel */
"chat/part": (data: {
/** Channel to leave */
channel: string;
}) => void;
/** Subscribes to UI related push event messages sent to a particular channel */
"ui-pushes/subscribe": (data: {
channel: string;
}) => void;
/** Un-Subscribes to UI related push event messages sent to a particular channel */
"ui-pushes/unsubscribe": (data: {
channel: string;
}) => void;
/** Subscribes to the seek graph events. The channel is required to be "global"
* for now and the foreseeable future. */
"seek_graph/connect": (data: {
channel: "global";
}) => void;
/** Un-Subscribes to the seek graph events. The channel is required to be "global"
* for now and the foreseeable future. */
"seek_graph/disconnect": (data: {
channel: "global";
}) => void;
/** Send a private message to another user */
"chat/pm": (data: {
/** Player ID of the recipient */
player_id: number;
/** Username of the recipient */
username: string;
/** UUID for the message */
uid: string;
/** Message text */
message: string;
/** Moderator option to send the chat from the system not from their personal PM */
as_system?: true;
}) => undefined | {
from: User;
to: {
id: number;
username: string;
};
message: {
i: string;
t: number;
m: string;
};
};
/** Loads the current user's private message session history with the given player id */
"chat/pm/load": (data: {
player_id: number;
}) => void;
/** Closes the current user's private message session with the given player id */
"chat/pm/close": (data: {
player_id: number;
}) => void;
/** Begins a "super chat" session with the given player id, which creates an
* unclosable dialog if enable is true, and makes the dialog closable again
* if enable is false. This is only available to moderators. */
"chat/pm/superchat": (data: {
player_id: number;
/** Username of the recipient */
username: string;
/** Set to true if you want the modal to be unclosable, false if you want
* the modal to be closable again */
enable: boolean;
}) => void;
/** Moderator only command to remove all chat messages for a given player */
"chat/remove_all": (data: {
/** Player id to remove all messages for */
player_id: number;
}) => void;
/** Moderator only command to remove a single chat message */
"chat/remove": (data: {
uuid: string;
}) => void;
/** Moderator only command to remove a single chat message from a game */
"game/chat/remove": (data: {
game_id: number;
channel: string;
chat_id: string;
}) => void;
/** Moderator only command to remove a single chat message from a game */
"review/chat/remove": (data: {
review_id: number;
channel: string;
chat_id: string;
}) => void;
/** Retrieve host information for the termination server you are connected to */
"hostinfo": (data: {}) => {
"hostname": string;
"clients": number;
"uptime": number;
"ggs-version": string;
};
/** Request a match via the automatch system */
"automatch/find_match": (data: AutomatchPreferences) => void;
/** Cancel a match request */
"automatch/cancel": (data: {
uuid: string;
}) => void;
/** Subscribe to automatch offers */
"automatch/available/subscribe": () => void;
/** Unsubscribe from automatch offers */
"automatch/available/unsubscribe": () => void;
/** Updates the config for the bot */
"bot/config": (config: BotConfig) => void;
/** Update the number of games that the bot is currently playing */
"bot/status": (data: {
ongoing_blitz_count: number;
ongoing_live_count: number;
ongoing_correspondence_count: number;
}) => void;
}
export interface BotAllowedClockSettingsV1 {
simple?: {
per_move_time_range: [number, number];
};
byoyomi?: {
main_time_range: [number, number];
period_time_range: [number, number];
periods_range: [number, number];
};
fischer?: {
max_time_range: [number, number];
time_increment_range: [number, number];
};
concurrent_games?: number;
}
export interface BotAllowedClockSettingsV2 {
simple?: {
per_move_time_range: [number, number];
};
byoyomi?: {
main_time_range: [number, number];
period_time_range: [number, number];
periods_range: [number, number];
};
fischer?: {
initial_time_range: [number, number];
max_time_range: [number, number];
time_increment_range: [number, number];
};
concurrent_games?: number;
}
export interface BotConfigV0 {
_config_version: 0;
}
export interface BotConfigV1 {
_config_version: 1;
hidden: boolean;
bot_id: number;
username: string;
allowed_time_control_systems: ("simple" | "byoyomi" | "fischer")[];
allowed_board_sizes: number[] | "all" | "square" | number;
allowed_blitz_settings?: BotAllowedClockSettingsV1;
allowed_rapid_settings?: BotAllowedClockSettingsV1;
allowed_live_settings?: BotAllowedClockSettingsV1;
allowed_correspondence_settings?: BotAllowedClockSettingsV1;
allow_ranked: boolean;
allow_unranked: boolean;
allowed_rank_range: [string, string];
allow_ranked_handicap: boolean;
allow_unranked_handicap: boolean;
allowed_komi_range: [number, number];
decline_new_challenges: boolean;
min_move_time: number;
max_games_per_player: number;
}
export interface BotConfigV2 {
_config_version: 2;
hidden: boolean;
bot_id: number;
username: string;
allowed_time_control_systems: ("simple" | "byoyomi" | "fischer")[];
allowed_board_sizes: number[] | "all" | "square" | number;
allowed_blitz_settings?: BotAllowedClockSettingsV2;
allowed_rapid_settings?: BotAllowedClockSettingsV2;
allowed_live_settings?: BotAllowedClockSettingsV2;
allowed_correspondence_settings?: BotAllowedClockSettingsV2;
allow_ranked: boolean;
allow_unranked: boolean;
allowed_rank_range: [string, string];
allow_ranked_handicap: boolean;
allow_unranked_handicap: boolean;
allowed_komi_range: [number, number];
decline_new_challenges: boolean;
min_move_time: number;
max_games_per_player: number;
}
export type BotConfig = BotConfigV0 | BotConfigV1 | BotConfigV2;
export type Speed = "blitz" | "rapid" | "live" | "correspondence";
export type Size = "9x9" | "13x13" | "19x19";
export type AutomatchCondition = "required" | "preferred" | "no-preference";
export type RuleSet = "japanese" | "chinese" | "aga" | "korean" | "nz" | "ing";
export interface AutomatchPreferences {
uuid: string;
size_speed_options: Array<{
size: Size;
speed: Speed;
system: "fischer" | "byoyomi";
}>;
timestamp?: number;
lower_rank_diff: number;
upper_rank_diff: number;
rules: {
condition: AutomatchCondition;
value: "japanese" | "chinese" | "aga" | "korean" | "nz" | "ing";
};
handicap: {
condition: AutomatchCondition;
value: "enabled" | "disabled";
};
}
/** This enum defines the various replication strategies for the remote storage
* system. For more details on the remote storage replication system see:
* https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts
*/
export declare enum RemoteStorageReplication {
/** No replication of this change */
NONE = 0,
/** Locally set data will overwrite remotely set data, but if not
* set will default to remotely set data */
LOCAL_OVERWRITES_REMOTE = 1,
/** Remotely set data will overwrite locally set data */
REMOTE_OVERWRITES_LOCAL = 2,
/** Remotely set data, but do not update our local value */
REMOTE_ONLY = 4
}
/** Parameters for the `gamelist/query` message */
export interface GameListWhere {
hide_ranked?: boolean;
hide_unranked?: boolean;
rengo_only?: boolean;
hide_19x19?: boolean;
hide_9x9?: boolean;
hide_13x13?: boolean;
hide_other?: boolean;
hide_tournament?: boolean;
hide_ladder?: boolean;
hide_open?: boolean;
hide_handicap?: boolean;
hide_even?: boolean;
hide_bot_games?: boolean;
hide_beginning?: boolean;
hide_middle?: boolean;
hide_end?: boolean;
players?: Array<number>;
tournament_id?: number;
ladder_id?: number;
malk_only?: boolean;
}
interface GameListPlayer {
username: string;
id: number;
rank: number;
professional: boolean;
accepted: boolean;
ratings: {
version: number;
overall: {
rating: number;
deviation: number;
volatility: number;
};
};
}
export interface GameListEntry {
id: number;
group_ids?: Array<number>;
group_ids_map?: {
[]: boolean;
};
kidsgo_game?: boolean;
phase: string;
name: string;
player_to_move: number;
width: number;
height: number;
move_number: number;
paused: boolean;
private: boolean;
black: GameListPlayer;
white: GameListPlayer;
rengo: boolean;
rengo_teams: {
black: Array<User>;
white: Array<User>;
};
dropped_player: number;
rengo_casual_mode: boolean;
_participants?: Array<number>;
time_per_move: number;
clock_expiration: number;
bot_game?: boolean;
ranked?: boolean;
handicap?: number;
tournament_id?: number;
ladder_id?: number;
komi?: number;
socket_id?: any;
in_beginning?: boolean;
in_middle?: boolean;
in_end?: boolean;
malkovich_present?: boolean;
}
export interface User {
id: number;
username: string;
ratings?: {
[]: Glicko2;
};
ranking?: number;
professional?: boolean;
country?: string;
ui_class?: string;
}
export interface Glicko2 {
rating: number;
deviation: number;
volatility: number;
games_played?: number;
}
export interface GameChatTranslatedMessage {
type: "translated";
en: string;
[]: string;
}
export interface GameChatAnalysisMessage {
type: "analysis";
name?: string;
branch_move?: number;
from?: number;
moves?: string;
marks?: {
[]: string;
};
pen_marks?: unknown[];
engine_analysis?: {
win_rate: number;
score?: number;
visits?: number;
[]: number | undefined;
};
}
export interface GameChatReviewMessage {
type: "review";
review_id: number;
}
export {};