From f38171311c1dbf25756929c2b1e43026ba964151 Mon Sep 17 00:00:00 2001 From: Natalie Rose Date: Thu, 20 Aug 2026 10:32:18 +1000 Subject: [PATCH] Fix url handling issue --- lib/core/endpoint.ts | 13 +- lib/core/server.ts | 14 +- lib/core/util.test.ts | 6 + lib/core/util.ts | 2 + lib/endpoints/alliance.ts | 6 +- lib/endpoints/body.ts | 6 +- lib/endpoints/building.ts | 6 +- lib/endpoints/buildings/archaeology.ts | 4 +- lib/endpoints/buildings/capitol.ts | 4 +- lib/endpoints/buildings/development.ts | 4 +- .../buildings/distribution-center.ts | 4 +- lib/endpoints/buildings/embassy.ts | 4 +- lib/endpoints/buildings/energy-reserve.ts | 4 +- lib/endpoints/buildings/entertainment.ts | 4 +- lib/endpoints/buildings/essentia-vein.ts | 4 +- lib/endpoints/buildings/food-reserve.ts | 4 +- lib/endpoints/buildings/genetics-lab.ts | 4 +- lib/endpoints/buildings/intelligence.ts | 4 +- lib/endpoints/buildings/library-of-jith.ts | 4 +- lib/endpoints/buildings/mercenaries-guild.ts | 4 +- lib/endpoints/buildings/mining-ministry.ts | 4 +- lib/endpoints/buildings/mission-command.ts | 4 +- lib/endpoints/buildings/network19.ts | 4 +- lib/endpoints/buildings/observatory.ts | 4 +- lib/endpoints/buildings/oracle-of-anid.ts | 4 +- lib/endpoints/buildings/ore-storage.ts | 4 +- lib/endpoints/buildings/park.ts | 4 +- lib/endpoints/buildings/parliament.ts | 4 +- lib/endpoints/buildings/planetary-command.ts | 4 +- lib/endpoints/buildings/police-station.ts | 4 +- lib/endpoints/buildings/security.ts | 4 +- lib/endpoints/buildings/shipyard.ts | 4 +- lib/endpoints/buildings/space-port.ts | 4 +- lib/endpoints/buildings/space-station-lab.ts | 4 +- lib/endpoints/buildings/station-command.ts | 4 +- .../buildings/subspace-supply-depot.ts | 4 +- .../buildings/temple-of-the-drajilites.ts | 4 +- lib/endpoints/buildings/the-dillon-forge.ts | 4 +- lib/endpoints/buildings/theme-park.ts | 4 +- lib/endpoints/buildings/trade.ts | 4 +- lib/endpoints/buildings/transporter.ts | 4 +- lib/endpoints/buildings/waste-exchanger.ts | 4 +- lib/endpoints/buildings/waste-recycling.ts | 4 +- lib/endpoints/buildings/water-storage.ts | 4 +- lib/endpoints/captcha.ts | 6 +- lib/endpoints/empire.ts | 6 +- lib/endpoints/inbox.ts | 6 +- lib/endpoints/map.ts | 6 +- lib/endpoints/stats.ts | 6 +- lib/lacuna.test.ts | 7 +- lib/lacuna.ts | 8 +- package-lock.json | 125 +++++++++++++++++- package.json | 4 +- 53 files changed, 259 insertions(+), 116 deletions(-) diff --git a/lib/core/endpoint.ts b/lib/core/endpoint.ts index c302fe0..2874539 100644 --- a/lib/core/endpoint.ts +++ b/lib/core/endpoint.ts @@ -2,19 +2,24 @@ import Lacuna from '../lacuna'; abstract class Endpoint { abstract lacuna: Lacuna; - abstract url: string; + abstract module: string; callWithSession(method: string, params: any) { - return this.lacuna.server.call({ module: this.url, method, params, addSession: true }); + return this.lacuna.server.call({ module: this.module, method, params, addSession: true }); } callWithoutSession(method: string, params: any) { - return this.lacuna.server.call({ module: this.url, method, params, addSession: false }); + return this.lacuna.server.call({ module: this.module, method, params, addSession: false }); } /** For RPC methods with no working /v2 equivalent. See Server#callLegacy. */ callLegacyWithSession(method: string, params: any) { - return this.lacuna.server.callLegacy({ module: this.url, method, params, addSession: true }); + return this.lacuna.server.callLegacy({ + module: this.module, + method, + params, + addSession: true, + }); } } diff --git a/lib/core/server.ts b/lib/core/server.ts index 297ce2b..2b06bfd 100644 --- a/lib/core/server.ts +++ b/lib/core/server.ts @@ -4,6 +4,7 @@ import { fixNumbers } from './util'; import { isBlockingError } from './responses'; import type { ResponseEvent } from './responses'; import type { paths } from '../types/schema'; +import urlJoin from 'proper-url-join'; export interface ServerRequest { module: string; @@ -77,15 +78,12 @@ class Server { async call(options: ServerRequest, attempt = 0): Promise> { this.lacuna.log.info('Calling', `${options.module}/${options.method}`, options.params); - const path = `/v2/${options.module}/${options.method}` as keyof paths; + const path = urlJoin('/v2', options.module, options.method) as any; - const { data, error } = await this.client.POST( - path as never, - { - body: options.params as never, - headers: this.authHeaders(options), - } as never - ); + const { data, error } = await this.client.POST(path, { + body: options.params, + headers: this.authHeaders(options), + }); const response: ServerResponse = data ? { result: fixNumbers((data as RpcResultBody).result) } diff --git a/lib/core/util.test.ts b/lib/core/util.test.ts index 093c4e3..b65b68e 100644 --- a/lib/core/util.test.ts +++ b/lib/core/util.test.ts @@ -91,6 +91,12 @@ test('util.fixNumbers', () => { expect(util.fixNumbers(['100', 'ok'])).toStrictEqual([100, 'ok']); }); +test('util.removeLeadingSlash', () => { + expect(util.removeLeadingSlash('development')).toBe('development'); + expect(util.removeLeadingSlash('/mine')).toBe('mine'); + expect(util.removeLeadingSlash('/')).toBe(''); +}); + test('util.ensureTrailingSlash', () => { expect(util.ensureTrailingSlash('')).toBe('/'); expect(util.ensureTrailingSlash('/')).toBe('/'); diff --git a/lib/core/util.ts b/lib/core/util.ts index 287ee9c..f2bed40 100644 --- a/lib/core/util.ts +++ b/lib/core/util.ts @@ -167,6 +167,8 @@ export const fixNumbers = function (data: any): any { return handleObj(data); }; +export const removeLeadingSlash = (url: string) => (url.slice(0, 1) !== '/' ? url : url.slice(1)); + export const ensureTrailingSlash = (url: string) => (url.slice(-1) === '/' ? url : `${url}/`); export const humanize = (text: string) => { diff --git a/lib/endpoints/alliance.ts b/lib/endpoints/alliance.ts index 46f503a..ca07213 100644 --- a/lib/endpoints/alliance.ts +++ b/lib/endpoints/alliance.ts @@ -4,12 +4,12 @@ import * as alliance from '../types/alliance'; class Alliance extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } viewProfile(params: alliance.ViewProfileParams) { diff --git a/lib/endpoints/body.ts b/lib/endpoints/body.ts index 98b65d5..7f9f68a 100644 --- a/lib/endpoints/body.ts +++ b/lib/endpoints/body.ts @@ -4,12 +4,12 @@ import * as B from '../types/body'; class Body extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } getBuildings(params: B.GetBuildingsParams) { diff --git a/lib/endpoints/building.ts b/lib/endpoints/building.ts index 10b0d16..1766052 100644 --- a/lib/endpoints/building.ts +++ b/lib/endpoints/building.ts @@ -4,12 +4,12 @@ import * as B from '../types/building'; class Building extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } view(params: B.ViewParams) { diff --git a/lib/endpoints/buildings/archaeology.ts b/lib/endpoints/buildings/archaeology.ts index 5931fb4..f19b1bc 100644 --- a/lib/endpoints/buildings/archaeology.ts +++ b/lib/endpoints/buildings/archaeology.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as archaeology from '../../types/archaeology'; class Archaeology extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } searchForGlyph(params: archaeology.SearchForGlyphParams) { diff --git a/lib/endpoints/buildings/capitol.ts b/lib/endpoints/buildings/capitol.ts index c963b40..c10891d 100644 --- a/lib/endpoints/buildings/capitol.ts +++ b/lib/endpoints/buildings/capitol.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as capitol from '../../types/capitol'; class Capitol extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } renameEmpire(params: capitol.RenameEmpireParams) { diff --git a/lib/endpoints/buildings/development.ts b/lib/endpoints/buildings/development.ts index aca0050..9b5fe71 100644 --- a/lib/endpoints/buildings/development.ts +++ b/lib/endpoints/buildings/development.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as development from '../../types/development'; class Development extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } subsidizeBuildQueue(params: development.SubsidizeBuildQueueParams) { diff --git a/lib/endpoints/buildings/distribution-center.ts b/lib/endpoints/buildings/distribution-center.ts index 1238dcd..43758a6 100644 --- a/lib/endpoints/buildings/distribution-center.ts +++ b/lib/endpoints/buildings/distribution-center.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as distributionCenter from '../../types/distribution-center'; class DistributionCenter extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } reserve(params: distributionCenter.ReserveParams) { diff --git a/lib/endpoints/buildings/embassy.ts b/lib/endpoints/buildings/embassy.ts index 7f924af..d7f7ad6 100644 --- a/lib/endpoints/buildings/embassy.ts +++ b/lib/endpoints/buildings/embassy.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as embassy from '../../types/embassy'; class Embassy extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } createAlliance(params: embassy.CreateAllianceParams) { diff --git a/lib/endpoints/buildings/energy-reserve.ts b/lib/endpoints/buildings/energy-reserve.ts index 7ebcebb..8b0b1d8 100644 --- a/lib/endpoints/buildings/energy-reserve.ts +++ b/lib/endpoints/buildings/energy-reserve.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as energyReserve from '../../types/energy-reserve'; class EnergyReserve extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } dump(params: energyReserve.DumpParams) { diff --git a/lib/endpoints/buildings/entertainment.ts b/lib/endpoints/buildings/entertainment.ts index cb0b6a6..9544393 100644 --- a/lib/endpoints/buildings/entertainment.ts +++ b/lib/endpoints/buildings/entertainment.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as entertainment from '../../types/entertainment'; class Entertainment extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } getLotteryVotingOptions(params: entertainment.GetLotteryVotingOptionsParams) { diff --git a/lib/endpoints/buildings/essentia-vein.ts b/lib/endpoints/buildings/essentia-vein.ts index e8cf658..c649958 100644 --- a/lib/endpoints/buildings/essentia-vein.ts +++ b/lib/endpoints/buildings/essentia-vein.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as EV from '../../types/essentia-vein'; class EssentiaVein extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } drain(params: EV.DrainParams) { diff --git a/lib/endpoints/buildings/food-reserve.ts b/lib/endpoints/buildings/food-reserve.ts index 0d5904a..14b1772 100644 --- a/lib/endpoints/buildings/food-reserve.ts +++ b/lib/endpoints/buildings/food-reserve.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as foodReserve from '../../types/food-reserve'; class FoodReserve extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } dump(params: foodReserve.DumpParams) { diff --git a/lib/endpoints/buildings/genetics-lab.ts b/lib/endpoints/buildings/genetics-lab.ts index 414f061..7f25268 100644 --- a/lib/endpoints/buildings/genetics-lab.ts +++ b/lib/endpoints/buildings/genetics-lab.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as geneticsLab from '../../types/genetics-lab'; class GeneticsLab extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } prepareExperiment(params: geneticsLab.PrepareExperimentParams) { diff --git a/lib/endpoints/buildings/intelligence.ts b/lib/endpoints/buildings/intelligence.ts index 82fb159..e46801c 100644 --- a/lib/endpoints/buildings/intelligence.ts +++ b/lib/endpoints/buildings/intelligence.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as intelligence from '../../types/intelligence'; class Intelligence extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } trainSpy(params: intelligence.TrainSpyParams) { diff --git a/lib/endpoints/buildings/library-of-jith.ts b/lib/endpoints/buildings/library-of-jith.ts index 73a2a0d..015613b 100644 --- a/lib/endpoints/buildings/library-of-jith.ts +++ b/lib/endpoints/buildings/library-of-jith.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as libraryOfJith from '../../types/library-of-jith'; class LibraryOfJith extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } researchSpecies(params: libraryOfJith.ResearchSpeciesParams) { diff --git a/lib/endpoints/buildings/mercenaries-guild.ts b/lib/endpoints/buildings/mercenaries-guild.ts index d9c7042..6ba050e 100644 --- a/lib/endpoints/buildings/mercenaries-guild.ts +++ b/lib/endpoints/buildings/mercenaries-guild.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as mercenariesGuild from '../../types/mercenaries-guild'; class MercenariesGuild extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } addToMarket(params: mercenariesGuild.AddToMarketParams) { diff --git a/lib/endpoints/buildings/mining-ministry.ts b/lib/endpoints/buildings/mining-ministry.ts index aad7ee5..db0e5dc 100644 --- a/lib/endpoints/buildings/mining-ministry.ts +++ b/lib/endpoints/buildings/mining-ministry.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as miningMinistry from '../../types/mining-ministry'; class MiningMinistry extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewPlatforms(params: miningMinistry.ViewPlatformsParams) { diff --git a/lib/endpoints/buildings/mission-command.ts b/lib/endpoints/buildings/mission-command.ts index dc7de50..907a4b9 100644 --- a/lib/endpoints/buildings/mission-command.ts +++ b/lib/endpoints/buildings/mission-command.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as missionCommand from '../../types/mission-command'; class MissionCommand extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } getMissions(params: missionCommand.GetMissionsParams) { diff --git a/lib/endpoints/buildings/network19.ts b/lib/endpoints/buildings/network19.ts index e33cf0f..76ab33e 100644 --- a/lib/endpoints/buildings/network19.ts +++ b/lib/endpoints/buildings/network19.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as network19 from '../../types/network19'; class Network19 extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } restrictCoverage(params: network19.RestrictCoverageParams) { diff --git a/lib/endpoints/buildings/observatory.ts b/lib/endpoints/buildings/observatory.ts index e90e73d..a2da88f 100644 --- a/lib/endpoints/buildings/observatory.ts +++ b/lib/endpoints/buildings/observatory.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as observatory from '../../types/observatory'; class Observatory extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } getProbedStars(params: observatory.GetProbedStarsParams) { diff --git a/lib/endpoints/buildings/oracle-of-anid.ts b/lib/endpoints/buildings/oracle-of-anid.ts index c3a5d19..3127f53 100644 --- a/lib/endpoints/buildings/oracle-of-anid.ts +++ b/lib/endpoints/buildings/oracle-of-anid.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as oracleOfAnid from '../../types/oracle-of-anid'; class OracleOfAnid extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } getStar(params: oracleOfAnid.GetStarParams) { diff --git a/lib/endpoints/buildings/ore-storage.ts b/lib/endpoints/buildings/ore-storage.ts index b6e1867..04aabcd 100644 --- a/lib/endpoints/buildings/ore-storage.ts +++ b/lib/endpoints/buildings/ore-storage.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as oreStorage from '../../types/ore-storage'; class OreStorage extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } dump(params: oreStorage.DumpParams) { diff --git a/lib/endpoints/buildings/park.ts b/lib/endpoints/buildings/park.ts index f808b16..ead5382 100644 --- a/lib/endpoints/buildings/park.ts +++ b/lib/endpoints/buildings/park.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as park from '../../types/park'; class Park extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } throwAParty(params: park.ThrowAPartyParams) { diff --git a/lib/endpoints/buildings/parliament.ts b/lib/endpoints/buildings/parliament.ts index 24614ba..089e6bc 100644 --- a/lib/endpoints/buildings/parliament.ts +++ b/lib/endpoints/buildings/parliament.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as parliament from '../../types/parliament'; class Parliament extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewLaws(params: parliament.ViewLawsParams) { diff --git a/lib/endpoints/buildings/planetary-command.ts b/lib/endpoints/buildings/planetary-command.ts index db54b1e..3371033 100644 --- a/lib/endpoints/buildings/planetary-command.ts +++ b/lib/endpoints/buildings/planetary-command.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as planetaryCommand from '../../types/planetary-command'; class PlanetaryCommand extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewPlans(params: planetaryCommand.ViewPlansParams) { diff --git a/lib/endpoints/buildings/police-station.ts b/lib/endpoints/buildings/police-station.ts index 8927852..0eba255 100644 --- a/lib/endpoints/buildings/police-station.ts +++ b/lib/endpoints/buildings/police-station.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as policeStation from '../../types/police-station'; class PoliceStation extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewPrisoners(params: policeStation.ViewPrisonersParams) { diff --git a/lib/endpoints/buildings/security.ts b/lib/endpoints/buildings/security.ts index 819fed6..453ccdb 100644 --- a/lib/endpoints/buildings/security.ts +++ b/lib/endpoints/buildings/security.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as security from '../../types/security'; class Security extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewPrisoners(params: security.ViewPrisonersParams) { diff --git a/lib/endpoints/buildings/shipyard.ts b/lib/endpoints/buildings/shipyard.ts index d5e7af7..2dc91b0 100644 --- a/lib/endpoints/buildings/shipyard.ts +++ b/lib/endpoints/buildings/shipyard.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as SY from '../../types/shipyard'; class Shipyard extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewBuildQueue(params: SY.ViewBuildQueueParams) { diff --git a/lib/endpoints/buildings/space-port.ts b/lib/endpoints/buildings/space-port.ts index 8668ba9..2bad33c 100644 --- a/lib/endpoints/buildings/space-port.ts +++ b/lib/endpoints/buildings/space-port.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as SP from '../../types/space-port'; class SpacePort extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewAllShips(params: SP.ViewAllShipsParams) { diff --git a/lib/endpoints/buildings/space-station-lab.ts b/lib/endpoints/buildings/space-station-lab.ts index 066eaae..c467597 100644 --- a/lib/endpoints/buildings/space-station-lab.ts +++ b/lib/endpoints/buildings/space-station-lab.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as spaceStationLab from '../../types/space-station-lab'; class SpaceStationLab extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } makePlan(params: spaceStationLab.MakePlanParams) { diff --git a/lib/endpoints/buildings/station-command.ts b/lib/endpoints/buildings/station-command.ts index f60b57a..26b9cc4 100644 --- a/lib/endpoints/buildings/station-command.ts +++ b/lib/endpoints/buildings/station-command.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as stationCommand from '../../types/station-command'; class StationCommand extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } viewPlans(params: stationCommand.ViewPlansParams) { diff --git a/lib/endpoints/buildings/subspace-supply-depot.ts b/lib/endpoints/buildings/subspace-supply-depot.ts index bad5fff..eae9da0 100644 --- a/lib/endpoints/buildings/subspace-supply-depot.ts +++ b/lib/endpoints/buildings/subspace-supply-depot.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as subspaceSupplyDepot from '../../types/subspace-supply-depot'; class SubspaceSupplyDepot extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } transmitFood(params: subspaceSupplyDepot.TransmitFoodParams) { diff --git a/lib/endpoints/buildings/temple-of-the-drajilites.ts b/lib/endpoints/buildings/temple-of-the-drajilites.ts index e11b2ad..160a326 100644 --- a/lib/endpoints/buildings/temple-of-the-drajilites.ts +++ b/lib/endpoints/buildings/temple-of-the-drajilites.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as templeOfTheDrajilites from '../../types/temple-of-the-drajilites'; class TempleOfTheDrajilites extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } listPlanets(params: templeOfTheDrajilites.ListPlanetsParams) { diff --git a/lib/endpoints/buildings/the-dillon-forge.ts b/lib/endpoints/buildings/the-dillon-forge.ts index 5b1c57f..3e34ace 100644 --- a/lib/endpoints/buildings/the-dillon-forge.ts +++ b/lib/endpoints/buildings/the-dillon-forge.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as theDillonForge from '../../types/the-dillon-forge'; class TheDillonForge extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } makePlan(params: theDillonForge.MakePlanParams) { diff --git a/lib/endpoints/buildings/theme-park.ts b/lib/endpoints/buildings/theme-park.ts index 411768d..5493a61 100644 --- a/lib/endpoints/buildings/theme-park.ts +++ b/lib/endpoints/buildings/theme-park.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as themePark from '../../types/theme-park'; class ThemePark extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } operate(params: themePark.OperateParams) { diff --git a/lib/endpoints/buildings/trade.ts b/lib/endpoints/buildings/trade.ts index dc77ec9..9bd1ad7 100644 --- a/lib/endpoints/buildings/trade.ts +++ b/lib/endpoints/buildings/trade.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as trade from '../../types/trade'; class Trade extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } addToMarket(params: trade.AddToMarketParams) { diff --git a/lib/endpoints/buildings/transporter.ts b/lib/endpoints/buildings/transporter.ts index f01448d..363d2fc 100644 --- a/lib/endpoints/buildings/transporter.ts +++ b/lib/endpoints/buildings/transporter.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as transporter from '../../types/transporter'; class Transporter extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } addToMarket(params: transporter.AddToMarketParams) { diff --git a/lib/endpoints/buildings/waste-exchanger.ts b/lib/endpoints/buildings/waste-exchanger.ts index e0d961f..6b35ef8 100644 --- a/lib/endpoints/buildings/waste-exchanger.ts +++ b/lib/endpoints/buildings/waste-exchanger.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as wasteExchanger from '../../types/waste-exchanger'; class WasteExchanger extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } recycle(params: wasteExchanger.RecycleParams) { diff --git a/lib/endpoints/buildings/waste-recycling.ts b/lib/endpoints/buildings/waste-recycling.ts index 9361f18..d41bbbe 100644 --- a/lib/endpoints/buildings/waste-recycling.ts +++ b/lib/endpoints/buildings/waste-recycling.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as wasteRecycling from '../../types/waste-recycling'; class WasteRecycling extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } recycle(params: wasteRecycling.RecycleParams) { diff --git a/lib/endpoints/buildings/water-storage.ts b/lib/endpoints/buildings/water-storage.ts index 0ed775e..9631781 100644 --- a/lib/endpoints/buildings/water-storage.ts +++ b/lib/endpoints/buildings/water-storage.ts @@ -3,8 +3,8 @@ import Building from '../building'; import * as waterStorage from '../../types/water-storage'; class WaterStorage extends Building { - constructor(lacuna: Lacuna, url: string) { - super(lacuna, url); + constructor(lacuna: Lacuna, module: string) { + super(lacuna, module); } dump(params: waterStorage.DumpParams) { diff --git a/lib/endpoints/captcha.ts b/lib/endpoints/captcha.ts index 53cc425..0b75d5b 100644 --- a/lib/endpoints/captcha.ts +++ b/lib/endpoints/captcha.ts @@ -4,12 +4,12 @@ import * as C from '../types/captcha'; class Captcha extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } fetch(params: C.FetchParams = {}) { diff --git a/lib/endpoints/empire.ts b/lib/endpoints/empire.ts index 67dad53..c1f973b 100644 --- a/lib/endpoints/empire.ts +++ b/lib/endpoints/empire.ts @@ -4,12 +4,12 @@ import * as E from '../types/empire'; class Empire extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } isNameAvailable(params: E.IsNameAvailableParams) { diff --git a/lib/endpoints/inbox.ts b/lib/endpoints/inbox.ts index 4514516..2c5ed2e 100644 --- a/lib/endpoints/inbox.ts +++ b/lib/endpoints/inbox.ts @@ -4,12 +4,12 @@ import * as inbox from '../types/inbox'; class Inbox extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } viewInbox(params: inbox.ViewInboxParams) { diff --git a/lib/endpoints/map.ts b/lib/endpoints/map.ts index 794d36a..2d7d45d 100644 --- a/lib/endpoints/map.ts +++ b/lib/endpoints/map.ts @@ -4,12 +4,12 @@ import * as map from '../types/map'; class Map extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } getStarMap(params: map.GetStarMapParams) { diff --git a/lib/endpoints/stats.ts b/lib/endpoints/stats.ts index 50d1aaa..3094f76 100644 --- a/lib/endpoints/stats.ts +++ b/lib/endpoints/stats.ts @@ -4,12 +4,12 @@ import * as S from '../types/stats'; class Stats extends Endpoint { lacuna: Lacuna; - url: string; + module: string; - constructor(lacuna: Lacuna, url: string) { + constructor(lacuna: Lacuna, module: string) { super(); this.lacuna = lacuna; - this.url = url; + this.module = module; } credits(params: S.CreditsParams = {}) { diff --git a/lib/lacuna.test.ts b/lib/lacuna.test.ts index 42b8dfb..0b5cd62 100644 --- a/lib/lacuna.test.ts +++ b/lib/lacuna.test.ts @@ -28,7 +28,12 @@ test('buildingFromUrl', () => { const pcc = lacuna.buildingFromUrl('planetarycommand'); expect(pcc).toBeDefined(); - expect(pcc.url).toBe('planetarycommand'); + expect(pcc.module).toBe('planetarycommand'); + + const development = lacuna.buildingFromUrl('/development'); + + expect(development).toBeDefined(); + expect(development.module).toBe('development'); }); test('version', () => { diff --git a/lib/lacuna.ts b/lib/lacuna.ts index 03b45d4..4b8015d 100644 --- a/lib/lacuna.ts +++ b/lib/lacuna.ts @@ -55,12 +55,13 @@ import type { ResponseHandler } from './core/responses'; import type { RpcLimitHandlerOptions } from './core/rpc-limit-handler'; import { LacunaConfig } from './types'; import { version } from '../package.json'; +import * as util from './core/util'; // Buildings with methods beyond the shared build/upgrade/downgrade/demolish/ // repair/get_stats_for_level/view set get a dedicated subclass here so // Lacuna#buildingFromUrl returns the right one. Every other building module // is served by the generic Building class. -const BUILDING_SUBCLASSES: Record Building> = { +const BUILDING_SUBCLASSES: Record Building> = { archaeology: Archaeology, capitol: Capitol, distributioncenter: DistributionCenter, @@ -253,8 +254,9 @@ class Lacuna { } buildingFromUrl(url: string) { - const BuildingClass = BUILDING_SUBCLASSES[url] || Building; - return new BuildingClass(this, url); + const module = util.removeLeadingSlash(url); + const BuildingClass = BUILDING_SUBCLASSES[module] || Building; + return new BuildingClass(this, module); } } diff --git a/package-lock.json b/package-lock.json index 70a05a4..6580136 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,13 @@ "@types/lodash": "^4.17.25", "lodash": "^4.18.1", "moment": "^2.30.1", - "openapi-fetch": "^0.17.0" + "openapi-fetch": "^0.17.0", + "proper-url-join": "^2.1.2" }, "devDependencies": { "@tlecommunity/api-spec": "^1.1.0", "@types/jest": "^30.0.0", + "@types/proper-url-join": "^2.1.5", "ajv": "^8.20.0", "jest": "^30.4.2", "openapi-typescript": "^7.13.0", @@ -1662,6 +1664,16 @@ "undici-types": "~7.10.0" } }, + "node_modules/@types/proper-url-join": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/proper-url-join/-/proper-url-join-2.1.5.tgz", + "integrity": "sha512-jPPpj0tQFl5mL6BVwlUCqJXXTjel5zig+AQgIYjERwm2rdS04y6cxQsVndmWPaz1Cv+DDGtxtYzvhSLmp/eYEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "query-string": "^7.1.3" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -2598,6 +2610,15 @@ } } }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/dedent": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", @@ -2833,6 +2854,15 @@ "bser": "2.1.1" } }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -4839,6 +4869,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/proper-url-join": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/proper-url-join/-/proper-url-join-2.1.2.tgz", + "integrity": "sha512-wp0MVpPYbQhwxRFjFkhWwHUoH5PyAA0SCVUpwRxjc9JzSzddPB4GDhu5I+eCYhdpG0S7jvVubsLPEi4pFd77rg==", + "license": "MIT", + "dependencies": { + "query-string": "^7.1.3" + } + }, "node_modules/pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", @@ -4873,6 +4912,24 @@ ], "license": "MIT" }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/react-is-18": { "name": "react-is", "version": "18.3.1", @@ -5053,6 +5110,15 @@ "source-map": "^0.6.0" } }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -5073,6 +5139,15 @@ "node": ">=10" } }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -7204,6 +7279,15 @@ "undici-types": "~7.10.0" } }, + "@types/proper-url-join": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/proper-url-join/-/proper-url-join-2.1.5.tgz", + "integrity": "sha512-jPPpj0tQFl5mL6BVwlUCqJXXTjel5zig+AQgIYjERwm2rdS04y6cxQsVndmWPaz1Cv+DDGtxtYzvhSLmp/eYEw==", + "dev": true, + "requires": { + "query-string": "^7.1.3" + } + }, "@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -7789,6 +7873,11 @@ "ms": "^2.1.3" } }, + "decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" + }, "dedent": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", @@ -7949,6 +8038,11 @@ "bser": "2.1.1" } }, + "filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==" + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -9245,6 +9339,14 @@ } } }, + "proper-url-join": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/proper-url-join/-/proper-url-join-2.1.2.tgz", + "integrity": "sha512-wp0MVpPYbQhwxRFjFkhWwHUoH5PyAA0SCVUpwRxjc9JzSzddPB4GDhu5I+eCYhdpG0S7jvVubsLPEi4pFd77rg==", + "requires": { + "query-string": "^7.1.3" + } + }, "pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", @@ -9257,6 +9359,17 @@ "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", "dev": true }, + "query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "requires": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + } + }, "react-is-18": { "version": "npm:react-is@18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -9375,6 +9488,11 @@ "source-map": "^0.6.0" } }, + "split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -9390,6 +9508,11 @@ "escape-string-regexp": "^2.0.0" } }, + "strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==" + }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", diff --git a/package.json b/package.json index 0e6b800..d6ac068 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "devDependencies": { "@tlecommunity/api-spec": "^1.1.0", "@types/jest": "^30.0.0", + "@types/proper-url-join": "^2.1.5", "ajv": "^8.20.0", "jest": "^30.4.2", "openapi-typescript": "^7.13.0", @@ -46,7 +47,8 @@ "@types/lodash": "^4.17.25", "lodash": "^4.18.1", "moment": "^2.30.1", - "openapi-fetch": "^0.17.0" + "openapi-fetch": "^0.17.0", + "proper-url-join": "^2.1.2" }, "allowScripts": { "unrs-resolver@1.12.2": true -- 2.51.2