CEEJAYDocs

ceejay.connect

Link a player of your game to their Discord account in the community, from your own server.

This page is for a studio whose server signs its players in. Your server knows who the player is, so CEEJAY trusts your server's identification: a connection made this way is at the verified level. A game that has no server of its own uses the public key that ships inside it, with the client on Connect, inside a game.

Every function takes the same last argument, options: signal, timeoutMs and maxRetries, for that one call. Every function can also raise the errors any request can raise, such as a bad key or the rate limit. Both are on Errors and retries.

Before you start

  • The game is set up for the community first, and gets a slug: a short name in lower case, with underscores where a name has spaces. Every function here takes that slug as its first argument, game.
  • The key needs the permission players:connect. A key with every permission (*) does not include it: tick Act for a player when you create the key. A server with this permission can sign in any player who is already connected, and can end a session, so keep that key on your server and nowhere else.
  • The rate limit is 600 requests per minute for one game, across the five functions. They do not count against the key's own rate limit.
  • No idempotency key. None of the five takes one, so the SDK never retries any of the three writes automatically. Retrying one yourself is safe: a retried request creates another pass, a new session for a player ends the previous one, and a confirmation or decline that was already given does not change.

The two ways to use it

The game stores the tokens. Your server creates a pass with ceejay.connect.createPass and passes it to the game. The game starts the session itself, with the pass as its proof, and stores the player's tokens. Your server does nothing more.

Your server does everything. Your server starts the session with ceejay.connect.createSession and passes the link, the code or the QR image to the game. The player opens the link and approves with their Discord account. Your server polls the session with ceejay.connect.getSession until its status is needs_game_confirmation, shows the player the Discord name, and sends the player's choice with ceejay.connect.confirmSession.

Nothing is saved until both parties have approved: the Discord member, on CEEJAY's connect page or in Discord, and the game.

The two ways to use it
async function connectPlayer(playerId: string, askPlayer: (discordName: string | null) => Promise<boolean>) {
  const started = await ceejay.connect.createSession('rugby_manager', { playerId, playerName: 'Nova' })
  if (started.status === 'approved') return started.sessionId

  // Hand started.url, started.code or started.qrUrl to the game, then read the session
  // every few seconds until it ends. It lasts 10 minutes.
  for (;;) {
    await new Promise((resolve) => setTimeout(resolve, 3000))
    const session = await ceejay.connect.getSession('rugby_manager', started.sessionId)

    if (session.status === 'needs_game_confirmation') {
      const accept = await askPlayer(session.member?.displayName ?? null)
      const after = await ceejay.connect.confirmSession('rugby_manager', started.sessionId, { accept })
      if (after.status === 'approved') return after.sessionId
    } else if (session.status !== 'pending' && session.status !== 'needs_confirmation') {
      // approved, or an end: declined, cancelled, expired, locked or refused.
      return session.status === 'approved' ? session.sessionId : null
    }
  }
}

Rewards and roles the community has set for connecting are granted by CEEJAY's bot within seconds of approval. Once the player is connected, send data about them and read it with Players, and agree the field names with the community in The field map.

ceejay.connect.createPass

Creates a connect pass for one player your server has signed in. Pass it to your game. The game sends it as its proof when it starts a connect session, and the session is then at the verified level.

POST /v1/games/{game}/connect/passes · requires players:connect · API reference: Create a connect pass

Retried by the SDK: No. Retrying it yourself creates a second pass, which is harmless

Takes the game, one object, then options.

Prop

Type

Returns the pass, typed as Schemas['ConnectPass'].

Prop

Type

Errors

StatuscodeWhen
400bad_player_idplayerId contains a character that is not allowed, or is too long
400bad_requestThe body cannot be parsed, or playerName is not a string of at most 80 characters
403community_not_activeThe community removed CEEJAY
403game_not_allowedThe key is limited to other games
403audience_not_allowedThe game is directed at children, and such a game cannot connect players
404game_not_foundThe community has no game with this slug
404not_availableThis instance does not support Connect yet
409game_pausedThe game is paused

A game or a playerId that is not a string never leaves your server: the SDK throws a TypeError.

Example

ceejay.connect.createPass
const pass = await ceejay.connect.createPass('rugby_manager', { playerId: 'p_19', playerName: 'Nova' })

// Send pass.pass to the game, over your own connection to it.
console.log(pass.pass, pass.expiresAt)

ceejay.connect.createSession

Starts a connect session for a player your server has signed in. With code, it attaches that player to the session of a member who generated a code in Discord and typed it into the game.

POST /v1/games/{game}/connect/sessions · requires players:connect · API reference: Create a connect session

Retried by the SDK: No. Retrying it yourself starts a new session, which ends the previous one

Takes the game, one object, then options.

Prop

Type

Returns the session, typed as Schemas['StartedConnectSession'].

Prop

Type

Errors

StatuscodeWhen
400bad_player_idplayerId contains a character that is not allowed, or is too long
400unknown_returnreturnTo is not the key of a return URL saved for the game
400age_answer_requiredThe game is set up for a mixed audience, and underAge was not sent
400bad_requestThe body cannot be parsed, or a field has the wrong type
403under_ageYou sent underAge: true. Nothing is stored, and a connection this player has is ended
403community_not_activeThe community removed CEEJAY
403game_not_allowedThe key is limited to other games
403audience_not_allowedThe game is directed at children
404code_not_foundNo open session has the code you sent
404game_not_foundThe community has no game with this slug
404not_availableThis instance does not support Connect yet
409session_lockedThe code belongs to a session that was locked by this failed attempt, its fifth. The member starts again
409game_pausedThe game is paused

Example

ceejay.connect.createSession
const session = await ceejay.connect.createSession('rugby_manager', {
  playerId: 'p_19',
  playerName: 'Nova',
  returnTo: 'game',
})

if (session.alreadyConnected) {
  console.log('This player is connected already')
} else {
  console.log('Open', session.url, 'or type', session.code, 'before', session.expiresAt)
}

A player who typed a code a member generated in Discord:

ceejay.connect.createSession with a code
import { CeejayError } from '@communitystudios/ceejay'

try {
  const session = await ceejay.connect.createSession('rugby_manager', { playerId: 'p_19', code: 'K7M-2QX' })
  console.log(`Connect to ${session.member?.displayName ?? 'this Discord account'}`)
} catch (error) {
  if (error instanceof CeejayError && error.code === 'code_not_found') {
    console.log('That code is not open. Make a new one in Discord')
  } else {
    throw error
  }
}

ceejay.connect.getSession

Reads one connect session: its status, who approved on the Discord side once someone has, and the connection once it is approved.

GET /v1/games/{game}/connect/sessions/{sessionId} · requires players:connect · API reference: Get a connect session

Retried by the SDK: Yes. It is a read

Takes the game, the session, then options.

ArgumentTypeRequiredWhat it is
gamestringYesThe game's slug. It is the first argument
sessionIdstringYesThe sessionId that ceejay.connect.createSession returned. It is the second argument

Returns the session, typed as Schemas['ConnectSession'].

Prop

Type

A session of a paused game can still be read.

Errors

StatuscodeWhen
403community_not_activeThe community removed CEEJAY
403game_not_allowedThe key is limited to other games
403audience_not_allowedThe game is directed at children
404session_not_foundThe game has no session with this ID. A session of another game or community returns the same error
404game_not_foundThe community has no game with this slug
404not_availableThis instance does not support Connect yet

Example

ceejay.connect.getSession
const session = await ceejay.connect.getSession('rugby_manager', 'kT3v9QmZ1xY7bLw2RfA8cN')

if (session.status === 'approved' && session.connection) {
  console.log(session.connection.playerId, 'is connected to', session.connection.discordId)
}

ceejay.connect.listSessions

Reads up to 100 connect sessions of one game by their IDs, for a server that follows several at once.

GET /v1/games/{game}/connect/sessions · requires players:connect · API reference: List connect sessions

Retried by the SDK: Yes. It is a read

Takes the game, one object, then options.

Prop

Type

Returns the full response, typed as Schemas['ListConnectSessionsResponse']. The sessions are in data, and page is alongside it.

Prop

Type

Errors

StatuscodeWhen
400bad_requestids is missing, or is not 1 to 100 session IDs separated by commas
403community_not_activeThe community removed CEEJAY
403game_not_allowedThe key is limited to other games
403audience_not_allowedThe game is directed at children
404game_not_foundThe community has no game with this slug
404not_availableThis instance does not support Connect yet

Example

ceejay.connect.listSessions
const open = ['kT3v9QmZ1xY7bLw2RfA8cN', 'Zp4c81LmQe7YtR2vXw9KdA']
const sessions = await ceejay.connect.listSessions('rugby_manager', { ids: open.join(',') })

for (const session of sessions.data) {
  console.log(session.sessionId, session.status)
}

ceejay.connect.confirmSession

Confirms or declines the connection for the game, from your server, for a game that has no session secret. Read the session first, show your player the Discord name it returns, and send the player's choice. There is no default: the player decides.

POST /v1/games/{game}/connect/sessions/{sessionId}/confirm · requires players:connect · API reference: Confirm a connect session

Retried by the SDK: No. Retrying it yourself is safe: a confirmation that was already given does not change, and a decline for a session that has ended changes nothing

Takes the game, the session, one object, then options.

Prop

Type

A confirmation completes a session your server or the game started, and the connection is saved. For a session a member started in Discord it moves the session to needs_confirmation, and the member confirms there.

Returns the session after the confirmation or the decline, typed as Schemas['ConnectSession']: the same fields as ceejay.connect.getSession returns, which are sessionId, status, reason, expiresAt, member and connection.

Errors

StatuscodeWhen
400bad_requestThe body cannot be read, or accept is not true or false
403community_not_activeThe community removed CEEJAY
403game_not_allowedThe key is limited to other games
403audience_not_allowedThe game is directed at children
404session_not_foundThe game has no session with this ID
404game_not_foundThe community has no game with this slug
404not_availableThis instance does not support Connect yet
409nothing_to_confirmYou sent a confirmation, and the session is not awaiting one right now
409session_changedThe session changed since it was read. Read it again, and show the player its current state
409player_blockedThe community blocked this player
409player_takenThe player is connected to another Discord account
409game_pausedThe game is paused. A decline is still accepted

Example

ceejay.connect.confirmSession
import { CeejayError } from '@communitystudios/ceejay'

try {
  const session = await ceejay.connect.confirmSession('rugby_manager', 'kT3v9QmZ1xY7bLw2RfA8cN', { accept: true })
  console.log(session.status, session.connection?.discordId)
} catch (error) {
  if (error instanceof CeejayError && error.code === 'nothing_to_confirm') {
    console.log('The member has not approved yet')
  } else {
    throw error
  }
}

On this page

Community StudiosPrivacyTerms