mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 22:51:30 -07:00
[auth][api] accept the 20250424.01 client
Version check now answers "current" for a set of builds rather than one: SUPPORTED_GAME_VERSIONS carries 20230414 and 20250424.01. GAME_VERSION is unchanged and still what the server reports for itself (presence, rn.ver). Adds GET /api/versioncheck/islandedversions, always [] — we never island a build off into its own matchmaking pool. The 2025 build POSTs /cachedlogin/forplatformid/:platform/:id with a deviceId/platformAuth/time form body where the 2023 build GETs it, so that route now takes both methods. The body is accepted and ignored for now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -145,7 +145,13 @@ export const ApiConfigV2 = JsonObject.describe(
|
||||
'The static client config, plus a ShareBaseUrl templated from the deploy domain'
|
||||
)
|
||||
|
||||
/** `GET /api/versioncheck/v4` — whether the client's `?v=` build matches GAME_VERSION. */
|
||||
/**
|
||||
* `GET /api/versioncheck/islandedversions` — builds islanded onto their own matchmaking
|
||||
* pool. Always empty here.
|
||||
*/
|
||||
export const IslandedVersions = z.array(z.string())
|
||||
|
||||
/** `GET /api/versioncheck/v4` — whether the client's `?v=` build is one we serve. */
|
||||
export const VersionCheck = z.object({
|
||||
VersionStatus: z.int().describe('0 = current, 1 = client on a different build'),
|
||||
UpdateNotificationStage: z.int(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from 'hono'
|
||||
import { describeRoute } from 'hono-openapi'
|
||||
|
||||
import { GAME_VERSION } from '@repo/domain'
|
||||
import { isSupportedGameVersion } from '@repo/domain'
|
||||
|
||||
import apiConfigV2 from '../../static/api-config-v2.json'
|
||||
import gameConfigsV1All from '../../static/gameconfigs-v1-all.json'
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ApiConfigV2,
|
||||
AzureSpeechConfig,
|
||||
BacktraceConfig,
|
||||
IslandedVersions,
|
||||
json,
|
||||
JsonObject,
|
||||
VersionCheck,
|
||||
@@ -100,18 +101,33 @@ export const configRoutes = new Hono<App>({ strict: false })
|
||||
summary: 'Client version check',
|
||||
description:
|
||||
'Whether the client build is current. Compares the client’s `?v=` build against ' +
|
||||
'our target `GAME_VERSION`: `VersionStatus` is 0 when they match, 1 when the ' +
|
||||
'client is on a different build.',
|
||||
'the builds we serve (`SUPPORTED_GAME_VERSIONS`): `VersionStatus` is 0 when the ' +
|
||||
'client is on one of them, 1 when it is on some other build.',
|
||||
responses: { 200: json(VersionCheck, 'Version status') },
|
||||
}),
|
||||
(c) =>
|
||||
c.json({
|
||||
VersionStatus: c.req.query('v') === GAME_VERSION ? 0 : 1,
|
||||
VersionStatus: isSupportedGameVersion(c.req.query('v')) ? 0 : 1,
|
||||
UpdateNotificationStage: 0,
|
||||
IsVersionIslanded: false,
|
||||
IsCrossPlayDisabled: false,
|
||||
})
|
||||
)
|
||||
// Islanding splits players onto version-specific matchmaking pools. We serve every
|
||||
// supported build from one pool, so the list is empty — the client reads it as
|
||||
// "nobody is islanded" and matchmakes normally.
|
||||
.get(
|
||||
'/api/versioncheck/islandedversions',
|
||||
describeRoute({
|
||||
tags: ['Config'],
|
||||
summary: 'Islanded client builds',
|
||||
description:
|
||||
'The builds that are islanded off into their own matchmaking pool. This server ' +
|
||||
'never islands a build, so the list is always empty.',
|
||||
responses: { 200: json(IslandedVersions, 'Always an empty list') },
|
||||
}),
|
||||
(c) => c.json([])
|
||||
)
|
||||
.get(
|
||||
'/api/gameconfigs/v1/all',
|
||||
describeRoute({
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
ROOM_SCHEMA_DDL,
|
||||
seedRoomWithSubRooms,
|
||||
SUBROOM_SCHEMA_DDL,
|
||||
SUPPORTED_GAME_VERSIONS,
|
||||
} from '@repo/domain'
|
||||
|
||||
import '../../api.app'
|
||||
@@ -197,11 +198,29 @@ describe('public endpoints', () => {
|
||||
expect(await res.json()).toMatchObject({ VersionStatus: 0 })
|
||||
})
|
||||
|
||||
test('GET /api/versioncheck/v4 reports current for every supported build', async () => {
|
||||
for (const version of SUPPORTED_GAME_VERSIONS) {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/versioncheck/v4?v=${version}`)
|
||||
expect(await res.json(), version).toMatchObject({ VersionStatus: 0 })
|
||||
}
|
||||
})
|
||||
|
||||
test('GET /api/versioncheck/v4 flags a mismatched build', async () => {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/versioncheck/v4?v=19990101`)
|
||||
expect(await res.json()).toMatchObject({ VersionStatus: 1 })
|
||||
})
|
||||
|
||||
test('GET /api/versioncheck/v4 flags a client that sends no build', async () => {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/versioncheck/v4`)
|
||||
expect(await res.json()).toMatchObject({ VersionStatus: 1 })
|
||||
})
|
||||
|
||||
test('GET /api/versioncheck/islandedversions is empty', async () => {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/versioncheck/islandedversions`)
|
||||
expect(res.status).toBe(200)
|
||||
expect(await res.json()).toEqual([])
|
||||
})
|
||||
|
||||
test('GET /api/relationships/v2/get returns empty array for a player with none', async () => {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/relationships/v2/get`, {
|
||||
headers: await bearer('99999'),
|
||||
@@ -3646,6 +3665,7 @@ describe('openapi', () => {
|
||||
'GET /api/roomkeys/v1/mine',
|
||||
'GET /api/roomkeys/v1/room',
|
||||
'GET /api/rooms/v1/filters',
|
||||
'GET /api/versioncheck/islandedversions',
|
||||
'GET /api/versioncheck/v4',
|
||||
'GET /voice/config',
|
||||
'POST /api/PlayerReporting/v1/deviceId',
|
||||
|
||||
Reference in New Issue
Block a user