From d822017510ec384eb66bb6070a2a5c05f17fb78e Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 12 Oct 2023 18:06:09 +0100 Subject: [PATCH] migrate to oapi v2 --- src/classes/OAPI.ts | 23 ++--- src/types.ts | 2 +- src/types/oapi_v1.ts | 17 +--- src/types/oapi_v2.ts | 200 ++++++++++++++++++++++++++++++++++++++++ src/types/util.ts | 6 ++ src/utils/endpoint.ts | 16 ++-- tests/gps.test.ts | 11 ++- tests/oapi.test.ts | 10 +- tests/residents.test.ts | 8 +- 9 files changed, 241 insertions(+), 52 deletions(-) create mode 100644 src/types/oapi_v2.ts create mode 100644 src/types/util.ts diff --git a/src/classes/OAPI.ts b/src/classes/OAPI.ts index 456ecee..d7326f5 100644 --- a/src/classes/OAPI.ts +++ b/src/classes/OAPI.ts @@ -14,7 +14,8 @@ import { FetchError } from '../utils/errors.js' const parseResident = (res: RawResident) => { const obj: any = {} - obj.online = res.status.isOnline + if (res.status) + obj.status = res.status if (res.stats?.balance) obj.balance = res.stats.balance @@ -22,13 +23,13 @@ const parseResident = (res: RawResident) => { if (res.timestamps) obj.timestamps = res.timestamps - if (res.strings?.username) obj.name = res.strings.username - if (res.strings?.title) obj.title = res.strings.title - if (res.strings?.surname) obj.surname = res.strings.surname + if (res.name) obj.name = res.name + if (res.uuid) obj.uuid = res.uuid + if (res.title) obj.title = res.title + if (res.surname) obj.surname = res.surname - const affiliation = res.affiliation - if (affiliation?.town) obj.town = affiliation.town - if (affiliation?.nation) obj.nation = affiliation.nation + if (res?.town) obj.town = res.town + if (res?.nation) obj.nation = res.nation if (res.ranks?.townRanks) obj.townRanks = res.ranks.townRanks if (res.ranks?.nationRanks) obj.nationRanks = res.ranks.nationRanks @@ -58,9 +59,6 @@ const parseTown = (town: RawTown) => { const obj: any = { ...town, - name: town.strings.town, - nation: town.affiliation.nation, - founder: town.strings.founder, created: town.timestamps?.registered, joinedNation: town.timestamps?.joinedNationAt, perms: { @@ -72,12 +70,8 @@ const parseTown = (town: RawTown) => { } } - delete obj.affiliation.nation delete obj.timestamps - delete obj.strings.town - delete obj.strings.founder - delete obj.perms.rnaoPerms delete obj.perms.flagPerms @@ -113,7 +107,6 @@ class OfficialAPI { if (!nation) return // TODO: Implement a proper error return { - name: nation.strings.nation, created: nation.timestamps.registered, ...nation } as OAPINation diff --git a/src/types.ts b/src/types.ts index bf162a4..f7d767c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -export * from './types/oapi_v1.js' +export * from './types/oapi_v2.js' export * from './types/dynmap.js' export * from './types/gps.js' diff --git a/src/types/oapi_v1.ts b/src/types/oapi_v1.ts index 820e2d3..60559e6 100644 --- a/src/types/oapi_v1.ts +++ b/src/types/oapi_v1.ts @@ -1,11 +1,5 @@ import { Location } from '../types.js' - -type NestedOmit = { - [P in keyof T as P extends K ? never : P]: - NestedOmit}.${infer R}` ? R : never> -} extends infer O ? { [P in keyof O]: O[P] } : never; - -export type ValidateShape = T extends Shape ? Exclude extends never ? T : never : never; +import { NestedOmit } from './util.js' //#region Parsed export type OAPITown = NestedOmit @@ -150,9 +141,7 @@ export type RawNation = RawEntity & { capital: string mapColorHexCode: string } - timestamps?: { - registered?: number - } + timestamps?: Timestamps towns: string[] residents: string[] allies: string[] diff --git a/src/types/oapi_v2.ts b/src/types/oapi_v2.ts new file mode 100644 index 0000000..a18f54f --- /dev/null +++ b/src/types/oapi_v2.ts @@ -0,0 +1,200 @@ +import { Location } from '../types.js' +import { NestedOmit } from './util.js' + +//#region Parsed +export type OAPITown = NestedOmit & { + name: string + nation: string + founder: string + created: number + joinedNation: number + perms: { + build: RawTownPerms + destroy: RawTownPerms + switch: RawTownPerms + itemUse: RawTownPerms + flags: RawFlagPerms + } +} + +export type OAPINation = NestedOmit & { + name: string + created: number +} + +export type OAPIResident = NestedOmit & { + name: string + uuid: string + title?: string + surname?: string + town?: string + nation?: string + balance: number + timestamps: Timestamps + townRanks?: string[] + nationRanks?: string[] + perms?: { + build: RawResidentPerms + destroy: RawResidentPerms + switch: RawResidentPerms + itemUse: RawResidentPerms + flags: RawFlagPerms + } +} +//#endregion + +//#region Raw, unparsed types +export type RawEntity = { + uuid: string + status: RawEntityStatus + stats: RawEntityStats + ranks?: { [key: string]: string[] } +} + +export type RawEntityStatus = Partial<{ + isPublic: boolean + isOpen: boolean + isNeutral: boolean + isCapital: boolean + isOverClaimed: boolean + isRuined: boolean + isOnline: boolean + isNPC: boolean +}> + +export type RawEntityStats = { + maxTownBlocks?: number + numTownBlocks?: number + numResidents?: number + numTowns?: number + balance: number +} + +export type RawResidentPerms = { + friend: boolean + town: boolean + ally: boolean + outsider: boolean +} + +export type RawTownPerms = { + resident: boolean + nation: boolean + ally: boolean + outsider: boolean +} + +export type RawFlagPerms = { + pvp: boolean + explosion: boolean + fire: boolean + mobs: boolean +} + +export type RawEntityPerms = { + flagPerms: RawFlagPerms + rnaoPerms: { + buildPerms: PermsType + destroyPerms: PermsType + switchPerms: PermsType + itemUsePerms: PermsType + } +} + +export type TownSpawn = Location & { + world: string + pitch?: number + yaw?: number +} + +export type TownCoordinates = { + spawn: TownSpawn + home: number[] + townBlocks: { + x: number[] + z: number[] + } +} + +export type RawTown = RawEntity & { + name: string + board: string + mayor: string + founder: string + mapColorHexCode: string + nation?: string + timestamps?: Timestamps + perms: RawEntityPerms + coordinates: TownCoordinates + residents: string[] + trusted?: string[] + outlaws?: string[] +} + +export type RawNation = RawEntity & { + name: string + board: string + king: string + capital: string + mapColorHexCode: string + timestamps?: Timestamps + towns: string[] + residents: string[] + allies: string[] + enemies: string[] +} + +export type Timestamps = { + joinedNationAt?: number + joinedTownAt?: number + registered: number + lastOnline?: number +} + +export type RawResident = RawEntity & { + name: string + title: string + surname: string + town?: string + nation?: string + timestamps?: Timestamps + perms: RawEntityPerms + friends?: string[] +} + +export type RawServerInfo = { + world: { + hasStorm: boolean + isThundering: boolean + time: number + fullTime: number + } + players: { + maxPlayers: number + numOnlineTownless: number + numOnlinePlayers: number + } + stats: { + numResidents: number + numTownless: number + numTowns: number + numNations: number + numTownBlocks: number + } +} +//#endregion \ No newline at end of file diff --git a/src/types/util.ts b/src/types/util.ts new file mode 100644 index 0000000..7109698 --- /dev/null +++ b/src/types/util.ts @@ -0,0 +1,6 @@ +export type NestedOmit = { + [P in keyof T as P extends K ? never : P]: + NestedOmit}.${infer R}` ? R : never> +} extends infer O ? { [P in keyof O]: O[P] } : never; + +export type ValidateShape = T extends Shape ? Exclude extends never ? T : never : never; \ No newline at end of file diff --git a/src/utils/endpoint.ts b/src/utils/endpoint.ts index fb2ca15..a4e7e1b 100644 --- a/src/utils/endpoint.ts +++ b/src/utils/endpoint.ts @@ -54,20 +54,20 @@ const configData = (mapName: ValidMapName) => const playerData = (mapName: ValidMapName) => asJSON(get("players", mapName)) as unknown as PlayersResponse -const townyData = async (endpoint = '', version = 'v1') => { - if (endpoint.startsWith("/")) - endpoint.replace("/", "") - - const url = get("towny", `${version}/aurora`) - return await asJSON(`${url}${endpoint}?${genRandomString()}`) as unknown -} - const mapData = async (mapName: ValidMapName) => { const url = await get("map", mapName) const res: unknown = await !archiveTs ? asJSON(url) : getArchive(url, archiveTs) return res as MapResponse } + +const townyData = async (endpoint = '', version = 'v2') => { + if (endpoint.startsWith("/")) + endpoint.replace("/", "") + + const url = get("towny", `${version}/aurora`) + return await asJSON(`${url}${endpoint}?${genRandomString()}`) as unknown +} export { get, asJSON, diff --git a/tests/gps.test.ts b/tests/gps.test.ts index 2593f12..61113cc 100644 --- a/tests/gps.test.ts +++ b/tests/gps.test.ts @@ -19,12 +19,13 @@ describe('GPS', () => { expect(route.distance).toBeGreaterThanOrEqual(0) }) - it('can check player is online when emitting', async () => { - const player = await globalThis.Aurora.GPS.getPlayer('Owen3H') - expect(player).not.toBeInstanceOf(NotFoundError) + it('can check player is online when emitting', async () => { + const ops = await globalThis.Aurora.Players.online() + const op = await globalThis.Aurora.GPS.getPlayer(ops[0]['name']) + expect(op).not.toBeInstanceOf(NotFoundError) - const online = await globalThis.Aurora.GPS.playerIsOnline(player) - expect(online).toEqual(false) + const online = await globalThis.Aurora.GPS.playerIsOnline(op) + expect(online).toEqual(true) }) it('can throw not found error', async () => { diff --git a/tests/oapi.test.ts b/tests/oapi.test.ts index a40bcea..f12f381 100644 --- a/tests/oapi.test.ts +++ b/tests/oapi.test.ts @@ -22,17 +22,17 @@ describe('OfficialAPI', async () => { expect(info.stats.numNations).toBeGreaterThanOrEqual(300) }) - it('can get valid resident (v1)', async () => { + it('can get valid resident', async () => { const res = await OfficialAPI.resident('owen3h') expect(res).toBeDefined() assertType(res) expect(res.name).toBe("Owen3H") - //console.log(res) + console.log(res) }) - it('can get valid nation (v1)', async () => { + it('can get valid nation', async () => { const nation = await OfficialAPI.nation('venice') expect(nation).toBeDefined() @@ -42,13 +42,13 @@ describe('OfficialAPI', async () => { //console.log(nation) }) - it('can get valid nation (v1)', async () => { + it('can get valid nation', async () => { const town = await OfficialAPI.town('venice') expect(town).toBeDefined() assertType(town) expect(town.name).toBe("Venice") - console.log(town) + //console.log(town) }) }) \ No newline at end of file diff --git a/tests/residents.test.ts b/tests/residents.test.ts index 6a5cc67..35b6252 100644 --- a/tests/residents.test.ts +++ b/tests/residents.test.ts @@ -12,16 +12,16 @@ describe('Residents', () => { }) it('can get single resident without error', async () => { - const resident = await globalThis.Aurora.Residents.get('owen3h') + const resident = await globalThis.Aurora.Residents.get('3meraldk') expect(resident).toBeDefined() expectTypeOf(resident).not.toEqualTypeOf() assertType(resident) - expect(resident.name).toBe("Owen3H") - expect(resident.rank).toBe("Resident") + expect(resident.name).toBe("3meraldK") + expect(resident.rank).toBe("Mayor") expect(resident.timestamps).toBeDefined() - expect(resident.timestamps.registered).toEqual(1659309285893) + expect(resident.timestamps.registered).toEqual(1652454407381) }) it('should return different resident info on Aurora and Nova', async () => {