Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/lib/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const appName = 'Talo'
export const docsRoute = '/docs'
export const docsRoute = '/'

export const baseApiUrl = import.meta.env.DEV ? 'http://localhost:3000' : 'https://api.trytalo.com'
5 changes: 2 additions & 3 deletions app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { index, route, type RouteConfig } from '@react-router/dev/routes'

export default [
index('routes/home.tsx'),
route('docs/intro', 'routes/intro-redirect.tsx'),
route('docs/*', 'routes/docs.tsx'),
route('intro', 'routes/intro-redirect.tsx'),
route('api/search', 'routes/search.ts'),
route('*', 'routes/not-found.tsx'),
route(':version/*', 'routes/docs.tsx'),
] satisfies RouteConfig
26 changes: 4 additions & 22 deletions app/routes/docs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useFumadocsLoader } from 'fumadocs-core/source/client'
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page'
import { use } from 'react'
import { redirect } from 'react-router'
import { Breadcrumb } from '@/components/breadcrumb'
import { Feedback } from '@/components/feedback/client'
import { useMDXComponents } from '@/components/mdx'
Expand All @@ -12,32 +11,15 @@ import { baseOptions } from '@/lib/layout.shared'
import { docs, source } from '@/lib/source'
import type { Route } from './+types/docs'

// Pre-versioning paths (e.g. /docs/godot/install) redirect to the default version.
const DEFAULT_VERSION = '1.x'
const LEGACY_SECTIONS = ['godot', 'unity', 'http', 'sockets', 'selfhosting', 'integrations']
const VERSION_REDIRECTS: Record<string, string> = {
'1.0': '1.x',
'0.49': 'pre-1.0',
'0.60': 'pre-1.0',
}

// Pre-versioning paths are redirected to the default version by the Cloudflare
// Worker (see workers/app.ts).
export async function loader({ params }: Route.LoaderArgs) {
const slugs = params['*'].split('/').filter((v) => v.length > 0)
const version = params.version ?? ''
const slugs = [version, ...params['*'].split('/').filter((v) => v.length > 0)]
const page = source.getPage(slugs)
if (!page) {
const first = slugs[0] ?? ''
if (LEGACY_SECTIONS.includes(first)) {
throw redirect(`/docs/${DEFAULT_VERSION}/${slugs.join('/')}`)
}
if (VERSION_REDIRECTS[first]) {
throw redirect(`/docs/${VERSION_REDIRECTS[first]}/${slugs.slice(1).join('/')}`)
}
throw new Response('Not found', { status: 404 })
}
// Default the docs root to the default version.
if (slugs.length === 0) {
throw redirect(`/docs/${DEFAULT_VERSION}`)
}

return {
path: page.path,
Expand Down
11 changes: 9 additions & 2 deletions app/routes/home.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { Navigate } from 'react-router'
import { useEffect } from 'react'
import { useNavigate } from 'react-router'

export default function Home() {
return <Navigate to='/docs' replace />
const navigate = useNavigate()

useEffect(() => {
navigate('/1.x', { replace: true })
}, [navigate])

return null
}
8 changes: 6 additions & 2 deletions app/routes/intro-redirect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { Navigate } from 'react-router'
import { redirect } from 'react-router'

export async function loader() {
throw redirect('/')
}

export default function IntroRedirect() {
return <Navigate to='/' replace />
return null
}
7 changes: 1 addition & 6 deletions app/routes/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { HomeLayout } from 'fumadocs-ui/layouts/home'
import { Link } from 'react-router'
import { baseOptions } from '@/lib/layout.shared'
import type { Route } from './+types/not-found'

export function meta({}: Route.MetaArgs) {
return [{ title: 'Not Found' }]
}

export default function NotFound() {
return (
Expand All @@ -15,7 +10,7 @@ export default function NotFound() {
<p className='text-fd-muted-foreground mb-4'>This page could not be found.</p>
<Link
className='text-sm bg-fd-primary text-fd-primary-foreground rounded-full font-medium px-4 py-2.5'
to='/docs'
to='/1.x'
>
Back to Docs
</Link>
Expand Down
2 changes: 1 addition & 1 deletion content/docs/1.x/admin/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ title: Authentication

The Admin API is a way of programmatically managing your game data like stats and leaderboards.

Unlike the gameplay-orientated [HTTP API](/docs/1.x/http/authentication), which authenticates requests on behalf of players, the Admin API authenticates requests using admin API keys scoped to your game.
Unlike the gameplay-orientated [HTTP API](/1.x/http/authentication), which authenticates requests on behalf of players, the Admin API authenticates requests using admin API keys scoped to your game.

## Creating an admin API key

Expand Down
4 changes: 2 additions & 2 deletions content/docs/1.x/admin/common-errors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ title: Common errors

The `Authorization` header is required, with its value set to `Bearer your-admin-api-key`.

Admin API keys are prefixed with `ta_` and are created inside the [dashboard](https://dashboard.trytalo.com/api-keys). Unlike the gameplay [HTTP API](/docs/1.x/http/authentication), admin API keys are scoped to a single game rather than authenticating on behalf of a player.
Admin API keys are prefixed with `ta_` and are created inside the [dashboard](https://dashboard.trytalo.com/api-keys). Unlike the gameplay [HTTP API](/1.x/http/authentication), admin API keys are scoped to a single game rather than authenticating on behalf of a player.

## Missing scopes

Expand Down Expand Up @@ -66,4 +66,4 @@ The `Retry-After` header will return how many seconds to wait before retrying -

Admin endpoints that read entities (e.g. listing leaderboard entries or listing stats) respect the `X-Talo-Include-Dev-Data` header. Set it to `1` to include development data, or leave it unset to only return live data.

Learn more in the [dev data guide](/docs/1.x/admin/dev-data).
Learn more in the [dev data guide](/1.x/admin/dev-data).
2 changes: 1 addition & 1 deletion content/docs/1.x/admin/dev-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Separating development data
---
## Dev build headers

When creating players through the [HTTP API](/docs/1.x/http/dev-data), you can optionally specify if the player belongs to a development build and therefore if they should be excluded from live data.
When creating players through the [HTTP API](/1.x/http/dev-data), you can optionally specify if the player belongs to a development build and therefore if they should be excluded from live data.

By default, the Admin API only returns data associated with live players. To include development data in these reads, set the `X-Talo-Include-Dev-Data` header to `1`.

Expand Down
4 changes: 2 additions & 2 deletions content/docs/1.x/admin/game-stat-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const pageToc = [

## Overview

The game stat admin API lets you create, update, delete and reset [game stats](/docs/1.x/http/game-stat-api) programmatically, as well as read stats and their metrics. This is useful for automation like creating stats ahead of a new patch or resetting player stats between competitive seasons.
The game stat admin API lets you create, update, delete and reset [game stats](/1.x/http/game-stat-api) programmatically, as well as read stats and their metrics. This is useful for automation like creating stats ahead of a new patch or resetting player stats between competitive seasons.

## Endpoints

Expand Down Expand Up @@ -52,7 +52,7 @@ type Stat = {

### StatMetrics

Metrics are **optional** and only included when the `withMetrics` query parameter is set on [list](/docs/1.x/admin/game-stat-api#get-all-game-stats) and [find](/docs/1.x/admin/game-stat-api#get-an-individual-game-stat) requests. When `withMetrics` is set, the `metrics` property is included with the stat response.
Metrics are **optional** and only included when the `withMetrics` query parameter is set on [list](/1.x/admin/game-stat-api#get-all-game-stats) and [find](/1.x/admin/game-stat-api#get-an-individual-game-stat) requests. When `withMetrics` is set, the `metrics` property is included with the stat response.

```ts
type StatMetrics = {
Expand Down
2 changes: 1 addition & 1 deletion content/docs/1.x/admin/leaderboard-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const pageToc = [

## Overview

The leaderboard admin API lets you create, update, delete and reset [leaderboards](/docs/1.x/http/leaderboard-api) programmatically, as well as read leaderboards and their entries. This is useful for automation like creating a new leaderboard ahead of a patch, resetting entries between competitive seasons or hiding suspicious entries.
The leaderboard admin API lets you create, update, delete and reset [leaderboards](/1.x/http/leaderboard-api) programmatically, as well as read leaderboards and their entries. This is useful for automation like creating a new leaderboard ahead of a patch, resetting entries between competitive seasons or hiding suspicious entries.

## Endpoints

Expand Down
6 changes: 3 additions & 3 deletions content/docs/1.x/godot/channels.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ if not result.success:

For channel **storage** prop errors, use the `channel_storage_props_failed_to_set` signal instead.

See [Players and props - Prop rejection reasons](/docs/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.
See [Players and props - Prop rejection reasons](/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.

## Channel storage

Expand Down Expand Up @@ -345,7 +345,7 @@ func _ready() -> void:
)
```

`TaloRejectedProp` includes a `message` with a human-readable description of the error, alongside the `code`. See [Players and props - Prop rejection reasons](/docs/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.
`TaloRejectedProp` includes a `message` with a human-readable description of the error, alongside the `code`. See [Players and props - Prop rejection reasons](/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.

### Setting storage prop arrays

Expand Down Expand Up @@ -463,7 +463,7 @@ This function will return a `TaloChannelStorageProp` array, allowing you to iter

#### Prop arrays

If any of the keys you pass are [prop arrays](/docs/1.x/godot/channels#getting-storage-prop-arrays), append `[]` to the key to fetch every item stored under it. Scalar and array keys can be mixed in a single call:
If any of the keys you pass are [prop arrays](/1.x/godot/channels#getting-storage-prop-arrays), append `[]` to the key to fetch every item stored under it. Scalar and array keys can be mixed in a single call:

```gdscript
# storage_prop_1 is a scalar, world_items[] is a prop array
Expand Down
2 changes: 1 addition & 1 deletion content/docs/1.x/godot/feedback.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ if not result.success:
print("Rejected prop '%s': %s (%s)" % [prop.key, prop.message, prop.code])
```

See [Players and props - Prop rejection reasons](/docs/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.
See [Players and props - Prop rejection reasons](/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.
10 changes: 5 additions & 5 deletions content/docs/1.x/godot/identifying.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ You cannot use "Talo" for the `service` parameter as this is reserved for **Talo

If you are using Talo Player Authentication, `Talo.players.identify()` will be invoked automatically and the `Talo.players.identified` signal will also emit as normal.

Visit the [Player authentication docs](/docs/1.x/godot/player-authentication) to learn more about identifying players with authentication enabled.
Visit the [Player authentication docs](/1.x/godot/player-authentication) to learn more about identifying players with authentication enabled.

</Callout>

Expand Down Expand Up @@ -134,7 +134,7 @@ In the example above, the two players created with `Talo.players.identify()` are
page](https://dashboard.trytalo.com/integrations).
</Callout>

If you have the Steamworks integration enabled, Talo can sync a Steam player ([as described here](/docs/1.x/integrations/steamworks#authentication)). You can do this via the `Talo.players.identify_steam` function. Here's an example using [GodotSteam](https://godotsteam.com):
If you have the Steamworks integration enabled, Talo can sync a Steam player ([as described here](/1.x/integrations/steamworks#authentication)). You can do this via the `Talo.players.identify_steam` function. Here's an example using [GodotSteam](https://godotsteam.com):

```gdscript
extends Node
Expand All @@ -157,7 +157,7 @@ The `identity` parameter is optional but strongly recommended as it ensures prop

### Steamworks player props

After successfully authenticating the player, several [props](/docs/1.x/godot/player-props) will automatically be created for them:
After successfully authenticating the player, several [props](/1.x/godot/player-props) will automatically be created for them:

- `META_STEAMWORKS_VAC_BANNED` - "true" or "false"
- `META_STEAMWORKS_PUBLISHER_BANNED` - "true" or "false"
Expand Down Expand Up @@ -209,7 +209,7 @@ Replace "yourid.apps.googleusercontent.com" with the client ID you generated ear

### Google Play Games player props

After successfully authenticating the player, these [props](/docs/1.x/godot/player-props) will automatically be created for them:
After successfully authenticating the player, these [props](/1.x/godot/player-props) will automatically be created for them:

- `META_GOOGLE_PLAY_GAMES_DISPLAY_NAME` - The player's chosen display name
- `META_GOOGLE_PLAY_GAMES_AVATAR_URL` - A direct link to the player's avatar
Expand Down Expand Up @@ -296,7 +296,7 @@ This function will return the identifier (if one exists) or an empty string. If

## Display names

Every player alias has a `display_name` that provides a human-readable name for the player. You can read it from `Talo.current_alias.display_name` after a player has been identified. Display names are resolved from a [player's props](/docs/1.x/godot/player-props) - arbitrary properties persisted across all of a player's aliases.
Every player alias has a `display_name` that provides a human-readable name for the player. You can read it from `Talo.current_alias.display_name` after a player has been identified. Display names are resolved from a [player's props](/1.x/godot/player-props) - arbitrary properties persisted across all of a player's aliases.

```gdscript title="welcome_label.gd"
extends Label
Expand Down
4 changes: 2 additions & 2 deletions content/docs/1.x/godot/install.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ You can download the latest version of the Godot plugin from our [itch.io page](

<Callout type="idea">
Upgrading from an older version of the plugin? Read the [upgrading to 1.0
guide](/docs/1.x/godot/upgrading-to-1.0) for the breaking changes.
guide](/1.x/godot/upgrading-to-1.0) for the breaking changes.
</Callout>

## Enable the plugin
Expand Down Expand Up @@ -67,4 +67,4 @@ If you're self-hosting Talo, you can configure your custom endpoint here in the

### Settings reference

You can visit the [settings reference](/docs/1.x/godot/settings-reference) for a detailed overview of Talo's configuration options.
You can visit the [settings reference](/1.x/godot/settings-reference) for a detailed overview of Talo's configuration options.
2 changes: 1 addition & 1 deletion content/docs/1.x/godot/leaderboards.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ if not res.success:
print("Rejected prop '%s': %s (%s)" % [prop.key, prop.message, prop.code])
```

See [Players and props - Prop rejection reasons](/docs/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.
See [Players and props - Prop rejection reasons](/1.x/godot/player-props#prop-rejection-reasons) for the full list of rejection reason codes.

## Getting entries

Expand Down
2 changes: 1 addition & 1 deletion content/docs/1.x/godot/live-config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ func _on_live_config_updated(live_config: TaloLiveConfig) -> void:
label.text = live_config.get_prop("live_string", "Not set!")
```

The `live_config_updated` signal is emitted (via the [Talo Socket](/docs/1.x/socket)) whenever the live config is updated.
The `live_config_updated` signal is emitted (via the [Talo Socket](/1.x/socket)) whenever the live config is updated.
6 changes: 3 additions & 3 deletions content/docs/1.x/godot/player-authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ You can migrate a player's account to a different service and identifier using `

The original player auth account will be deleted and they will only be able to use their new identifier.

Here is an example of migrating to a [Steam alias](/docs/1.x/godot/identifying#steamworks-integration):
Here is an example of migrating to a [Steam alias](/1.x/godot/identifying#steamworks-integration):

```gdscript
@onready var current_password: TextEdit = %CurrentPassword
Expand All @@ -267,12 +267,12 @@ func _migrate_account(ticket: String) -> void:
validation_label.text = res.error.message
```

You can also migrate to the `google_play_games` service by providing an [auth code](/docs/1.x/godot/identifying#google-play-games-integration).
You can also migrate to the `google_play_games` service by providing an [auth code](/1.x/godot/identifying#google-play-games-integration).

When a migration is successful, the current session is cleared, the player's alias is updated to the new service and identifier, and the `Talo.players.identified` signal is emitted.

## Reading errors

As shown in the examples above, every auth method returns a result object. On failure, `res.success` is `false` and `res.error` holds a `TaloPlayerAuthError` with a machine-readable `code` enum value and a human-readable `message`.

You can view all the authentication errors and their descriptions [here](/docs/1.x/http/player-auth-api#error-codes).
You can view all the authentication errors and their descriptions [here](/1.x/http/player-auth-api#error-codes).
2 changes: 1 addition & 1 deletion content/docs/1.x/godot/player-props.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ print("Found %s results: %s" % [search_page.count, ", ".join(identifiers)])

Players can have a list of arbitrary properties that are persisted across all of their aliases. These props are identified by their unique key and can have any string value. Keys can be up to 128 characters long and values can be up to 512 characters long.

All functions that modify props accept an optional `update` parameter (default `true`) that controls whether the player is synced with Talo after the change. They return an awaitable `PlayerUpdateResult`, and setting `update` to `false` returns a valid result without triggering a sync - use it to batch multiple changes and avoid redundant [debounces](/docs/1.x/godot/settings-reference#debounce_timer_seconds).
All functions that modify props accept an optional `update` parameter (default `true`) that controls whether the player is synced with Talo after the change. They return an awaitable `PlayerUpdateResult`, and setting `update` to `false` returns a valid result without triggering a sync - use it to batch multiple changes and avoid redundant [debounces](/1.x/godot/settings-reference#debounce_timer_seconds).

The `Talo.players.player_updated(success: bool)` signal fires after every player update settles, and `Talo.players.flush_updates()` immediately flushes any pending or in-flight update (returning a `FlushResult`). Pending updates are also flushed automatically when the game quits.

Expand Down
2 changes: 1 addition & 1 deletion content/docs/1.x/godot/player-relationships.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ A complete sample is available in the Godot plugin at `addons/talo/samples/frien

To subscribe to a player, you need to first decide what type of relationship you want to create: unidirectional or bidirectional. Unidirectional relationships create a subscription to the target player and bidirectional relationships will create a reciprocal subscription between both players.

You also need to know the target player alias' ID. You can get this through [player presence updates](/docs/1.x/godot/player-presence), or by searching for players using [player search](/docs/1.x/godot/player-props#searching-for-players).
You also need to know the target player alias' ID. You can get this through [player presence updates](/1.x/godot/player-presence), or by searching for players using [player search](/1.x/godot/player-props#searching-for-players).

Once you have both of these pieces of information, you can create the relationship:

Expand Down
Loading
Loading