From cc8edbed02710e9d69f6e5bc77ad252afa88b3ca Mon Sep 17 00:00:00 2001 From: Lily Rose Date: Tue, 17 Jun 2025 01:43:06 +1000 Subject: [PATCH] Add functioning sdk --- .gitignore | 1 + dev/spacetraders.openapi.json | 7223 +++++++++++++++++ dev/spacetraders_sdk_dev.gleam | 17 + gleam.toml | 10 + manifest.toml | 34 + src/endpoints/accounts.gleam | 82 + src/endpoints/agents.gleam | 102 + src/endpoints/contracts.gleam | 161 + src/endpoints/data.gleam | 63 + src/endpoints/factions.gleam | 99 + src/endpoints/fleet.gleam | 1327 +++ src/endpoints/global.gleam | 192 + src/endpoints/systems.gleam | 321 + src/models/account.gleam | 20 + src/models/activity_level.gleam | 32 + src/models/agent.gleam | 30 + src/models/agent_event.gleam | 23 + src/models/agent_symbol.gleam | 8 + src/models/chart.gleam | 21 + src/models/chart_transaction.gleam | 28 + src/models/construction.gleam | 20 + src/models/construction_material.gleam | 13 + src/models/contract.gleam | 38 + src/models/contract_deliver_good.gleam | 23 + src/models/contract_payment.gleam | 11 + src/models/contract_terms.gleam | 23 + src/models/cooldown.gleam | 29 + src/models/crew_rotation.gleam | 26 + src/models/engine_symbol.gleam | 32 + src/models/extraction.gleam | 13 + src/models/extraction_yield.gleam | 12 + src/models/faction.gleam | 36 + src/models/faction_symbol.gleam | 77 + src/models/faction_trait.gleam | 13 + src/models/faction_trait_symbol.gleam | 199 + src/models/frame_symbol.gleam | 68 + src/models/jump_gate.gleam | 12 + src/models/market.gleam | 41 + src/models/market_symbol.gleam | 8 + src/models/market_trade_good.gleam | 41 + src/models/market_transaction.gleam | 42 + src/models/meta.gleam | 12 + src/models/module_symbol.gleam | 80 + src/models/mount_deposit.gleam | 62 + src/models/mount_symbol.gleam | 65 + src/models/public_agent.gleam | 26 + src/models/reactor_symbol.gleam | 35 + src/models/refinement_produce.gleam | 49 + src/models/refinement_yield.gleam | 12 + src/models/repair_transaction.gleam | 28 + src/models/scanned_ship.gleam | 50 + src/models/scanned_ship_engine.gleam | 11 + src/models/scanned_ship_frame.gleam | 11 + src/models/scanned_ship_mount.gleam | 11 + src/models/scanned_ship_reactor.gleam | 11 + src/models/scanned_system.gleam | 31 + src/models/scanned_waypoint.gleam | 57 + src/models/scrap_transaction.gleam | 28 + src/models/ship.gleam | 59 + src/models/ship_cargo.gleam | 16 + src/models/ship_cargo_item.gleam | 19 + src/models/ship_component.gleam | 29 + src/models/ship_component_condition.gleam | 8 + src/models/ship_component_integrity.gleam | 8 + src/models/ship_component_quality.gleam | 8 + src/models/ship_condition_event.gleam | 20 + src/models/ship_condition_event_symbol.gleam | 105 + src/models/ship_crew.gleam | 30 + src/models/ship_engine.gleam | 40 + src/models/ship_frame.gleam | 46 + src/models/ship_fuel.gleam | 18 + src/models/ship_fuel_consumed.gleam | 11 + .../ship_modification_transaction.gleam | 32 + src/models/ship_module.gleam | 33 + src/models/ship_mount.gleam | 37 + src/models/ship_nav.gleam | 34 + src/models/ship_nav_flight_mode.gleam | 34 + src/models/ship_nav_route.gleam | 22 + src/models/ship_nav_route_waypoint.gleam | 23 + src/models/ship_nav_status.gleam | 31 + src/models/ship_reactor.gleam | 40 + src/models/ship_registration.gleam | 14 + src/models/ship_requirements.gleam | 14 + src/models/ship_role.gleam | 62 + src/models/ship_symbol.gleam | 8 + src/models/ship_type.gleam | 35 + src/models/shipyard.gleam | 38 + src/models/shipyard_ship.gleam | 61 + src/models/shipyard_ship_crew.gleam | 11 + src/models/shipyard_symbol.gleam | 8 + src/models/shipyard_transaction.gleam | 32 + src/models/siphon.gleam | 13 + src/models/siphon_yield.gleam | 12 + src/models/supply_level.gleam | 35 + src/models/survey.gleam | 38 + src/models/survey_deposit.gleam | 16 + src/models/survey_signature.gleam | 8 + src/models/survey_size.gleam | 34 + src/models/system.gleam | 54 + src/models/system_faction.gleam | 11 + src/models/system_symbol.gleam | 8 + src/models/system_type.gleam | 50 + src/models/system_waypoint.gleam | 30 + src/models/trade_good.gleam | 13 + src/models/trade_good_type.gleam | 31 + src/models/trade_symbol.gleam | 460 ++ src/models/transaction_type.gleam | 28 + src/models/waypoint.gleam | 66 + src/models/waypoint_faction.gleam | 11 + src/models/waypoint_modifier.gleam | 17 + src/models/waypoint_modifier_symbol.gleam | 37 + src/models/waypoint_orbital.gleam | 11 + src/models/waypoint_symbol.gleam | 8 + src/models/waypoint_trait.gleam | 13 + src/models/waypoint_trait_symbol.gleam | 229 + src/models/waypoint_type.gleam | 62 + src/utils/auth.gleam | 71 + src/utils/decode.gleam | 68 + src/utils/env.gleam | 41 + src/utils/jwt.gleam | 137 + src/utils/request.gleam | 144 + src/utils/response.gleam | 29 + src/utils/types.gleam | 28 + test/spacetraders_sdk_test.gleam | 19 +- 124 files changed, 13962 insertions(+), 6 deletions(-) create mode 100644 dev/spacetraders.openapi.json create mode 100644 dev/spacetraders_sdk_dev.gleam create mode 100644 src/endpoints/accounts.gleam create mode 100644 src/endpoints/agents.gleam create mode 100644 src/endpoints/contracts.gleam create mode 100644 src/endpoints/data.gleam create mode 100644 src/endpoints/factions.gleam create mode 100644 src/endpoints/fleet.gleam create mode 100644 src/endpoints/global.gleam create mode 100644 src/endpoints/systems.gleam create mode 100644 src/models/account.gleam create mode 100644 src/models/activity_level.gleam create mode 100644 src/models/agent.gleam create mode 100644 src/models/agent_event.gleam create mode 100644 src/models/agent_symbol.gleam create mode 100644 src/models/chart.gleam create mode 100644 src/models/chart_transaction.gleam create mode 100644 src/models/construction.gleam create mode 100644 src/models/construction_material.gleam create mode 100644 src/models/contract.gleam create mode 100644 src/models/contract_deliver_good.gleam create mode 100644 src/models/contract_payment.gleam create mode 100644 src/models/contract_terms.gleam create mode 100644 src/models/cooldown.gleam create mode 100644 src/models/crew_rotation.gleam create mode 100644 src/models/engine_symbol.gleam create mode 100644 src/models/extraction.gleam create mode 100644 src/models/extraction_yield.gleam create mode 100644 src/models/faction.gleam create mode 100644 src/models/faction_symbol.gleam create mode 100644 src/models/faction_trait.gleam create mode 100644 src/models/faction_trait_symbol.gleam create mode 100644 src/models/frame_symbol.gleam create mode 100644 src/models/jump_gate.gleam create mode 100644 src/models/market.gleam create mode 100644 src/models/market_symbol.gleam create mode 100644 src/models/market_trade_good.gleam create mode 100644 src/models/market_transaction.gleam create mode 100644 src/models/meta.gleam create mode 100644 src/models/module_symbol.gleam create mode 100644 src/models/mount_deposit.gleam create mode 100644 src/models/mount_symbol.gleam create mode 100644 src/models/public_agent.gleam create mode 100644 src/models/reactor_symbol.gleam create mode 100644 src/models/refinement_produce.gleam create mode 100644 src/models/refinement_yield.gleam create mode 100644 src/models/repair_transaction.gleam create mode 100644 src/models/scanned_ship.gleam create mode 100644 src/models/scanned_ship_engine.gleam create mode 100644 src/models/scanned_ship_frame.gleam create mode 100644 src/models/scanned_ship_mount.gleam create mode 100644 src/models/scanned_ship_reactor.gleam create mode 100644 src/models/scanned_system.gleam create mode 100644 src/models/scanned_waypoint.gleam create mode 100644 src/models/scrap_transaction.gleam create mode 100644 src/models/ship.gleam create mode 100644 src/models/ship_cargo.gleam create mode 100644 src/models/ship_cargo_item.gleam create mode 100644 src/models/ship_component.gleam create mode 100644 src/models/ship_component_condition.gleam create mode 100644 src/models/ship_component_integrity.gleam create mode 100644 src/models/ship_component_quality.gleam create mode 100644 src/models/ship_condition_event.gleam create mode 100644 src/models/ship_condition_event_symbol.gleam create mode 100644 src/models/ship_crew.gleam create mode 100644 src/models/ship_engine.gleam create mode 100644 src/models/ship_frame.gleam create mode 100644 src/models/ship_fuel.gleam create mode 100644 src/models/ship_fuel_consumed.gleam create mode 100644 src/models/ship_modification_transaction.gleam create mode 100644 src/models/ship_module.gleam create mode 100644 src/models/ship_mount.gleam create mode 100644 src/models/ship_nav.gleam create mode 100644 src/models/ship_nav_flight_mode.gleam create mode 100644 src/models/ship_nav_route.gleam create mode 100644 src/models/ship_nav_route_waypoint.gleam create mode 100644 src/models/ship_nav_status.gleam create mode 100644 src/models/ship_reactor.gleam create mode 100644 src/models/ship_registration.gleam create mode 100644 src/models/ship_requirements.gleam create mode 100644 src/models/ship_role.gleam create mode 100644 src/models/ship_symbol.gleam create mode 100644 src/models/ship_type.gleam create mode 100644 src/models/shipyard.gleam create mode 100644 src/models/shipyard_ship.gleam create mode 100644 src/models/shipyard_ship_crew.gleam create mode 100644 src/models/shipyard_symbol.gleam create mode 100644 src/models/shipyard_transaction.gleam create mode 100644 src/models/siphon.gleam create mode 100644 src/models/siphon_yield.gleam create mode 100644 src/models/supply_level.gleam create mode 100644 src/models/survey.gleam create mode 100644 src/models/survey_deposit.gleam create mode 100644 src/models/survey_signature.gleam create mode 100644 src/models/survey_size.gleam create mode 100644 src/models/system.gleam create mode 100644 src/models/system_faction.gleam create mode 100644 src/models/system_symbol.gleam create mode 100644 src/models/system_type.gleam create mode 100644 src/models/system_waypoint.gleam create mode 100644 src/models/trade_good.gleam create mode 100644 src/models/trade_good_type.gleam create mode 100644 src/models/trade_symbol.gleam create mode 100644 src/models/transaction_type.gleam create mode 100644 src/models/waypoint.gleam create mode 100644 src/models/waypoint_faction.gleam create mode 100644 src/models/waypoint_modifier.gleam create mode 100644 src/models/waypoint_modifier_symbol.gleam create mode 100644 src/models/waypoint_orbital.gleam create mode 100644 src/models/waypoint_symbol.gleam create mode 100644 src/models/waypoint_trait.gleam create mode 100644 src/models/waypoint_trait_symbol.gleam create mode 100644 src/models/waypoint_type.gleam create mode 100644 src/utils/auth.gleam create mode 100644 src/utils/decode.gleam create mode 100644 src/utils/env.gleam create mode 100644 src/utils/jwt.gleam create mode 100644 src/utils/request.gleam create mode 100644 src/utils/response.gleam create mode 100644 src/utils/types.gleam diff --git a/.gitignore b/.gitignore index 599be4e..dac4107 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.ez /build erl_crash.dump +.env \ No newline at end of file diff --git a/dev/spacetraders.openapi.json b/dev/spacetraders.openapi.json new file mode 100644 index 0000000..c0216ee --- /dev/null +++ b/dev/spacetraders.openapi.json @@ -0,0 +1,7223 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "SpaceTraders API", + "version": "v2.3.0", + "description": "SpaceTraders is an open-universe game and learning platform that offers a set of HTTP endpoints to control a fleet of ships and explore a multiplayer universe.\n\nThe API is documented using [OpenAPI](https://github.com/SpaceTradersAPI/api-docs). You can send your first request right here in your browser to check the status of the game server.\n\n```json http\n{\n \"method\": \"GET\",\n \"url\": \"https://api.spacetraders.io/v2\",\n}\n```\n\nUnlike a traditional game, SpaceTraders does not have a first-party client or app to play the game. Instead, you can use the API to build your own client, write a script to automate your ships, or try an app built by the community.\n\nWe have a [Discord channel](https://discord.com/invite/jh6zurdWk5) where you can share your projects, ask questions, and get help from other players.\n\n\n", + "contact": { + "email": "joel@spacetraders.io", + "name": "Joel Brubaker" + }, + "license": { + "name": "No Permission", + "url": "https://choosealicense.com/no-permission/" + } + }, + "components": { + "callbacks": {}, + "links": {}, + "securitySchemes": { + "AgentToken": { + "type": "http", + "scheme": "bearer", + "description": "When you register a new agent you will be granted a private bearer token which grants authorization to use the API during a specific reset.", + "bearerFormat": "JWT" + }, + "AccountToken": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT", + "description": "When you create an account you will be able to generate a private bearer token which grants authorization to create agents." + } + }, + "schemas": { + "Faction": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/FactionSymbol" + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the faction." + }, + "description": { + "type": "string", + "minLength": 1, + "description": "Description of the faction." + }, + "headquarters": { + "type": "string", + "minLength": 1, + "description": "The waypoint in which the faction's HQ is located in." + }, + "traits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTrait" + }, + "description": "List of traits that define this faction." + }, + "isRecruiting": { + "type": "boolean", + "description": "Whether or not the faction is currently recruiting new agents." + } + }, + "required": [ + "symbol", + "name", + "description", + "traits", + "isRecruiting" + ], + "description": "Faction details." + }, + "FactionSymbol": { + "type": "string", + "enum": [ + "COSMIC", + "VOID", + "GALACTIC", + "QUANTUM", + "DOMINION", + "ASTRO", + "CORSAIRS", + "OBSIDIAN", + "AEGIS", + "UNITED", + "SOLITARY", + "COBALT", + "OMEGA", + "ECHO", + "LORDS", + "CULT", + "ANCIENTS", + "SHADOW", + "ETHEREAL" + ], + "description": "The symbol of the faction." + }, + "FactionTrait": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/FactionTraitSymbol" + }, + "name": { + "type": "string", + "description": "The name of the trait." + }, + "description": { + "type": "string", + "description": "A description of the trait." + } + }, + "required": [ + "symbol", + "name", + "description" + ] + }, + "FactionTraitSymbol": { + "type": "string", + "enum": [ + "BUREAUCRATIC", + "SECRETIVE", + "CAPITALISTIC", + "INDUSTRIOUS", + "PEACEFUL", + "DISTRUSTFUL", + "WELCOMING", + "SMUGGLERS", + "SCAVENGERS", + "REBELLIOUS", + "EXILES", + "PIRATES", + "RAIDERS", + "CLAN", + "GUILD", + "DOMINION", + "FRINGE", + "FORSAKEN", + "ISOLATED", + "LOCALIZED", + "ESTABLISHED", + "NOTABLE", + "DOMINANT", + "INESCAPABLE", + "INNOVATIVE", + "BOLD", + "VISIONARY", + "CURIOUS", + "DARING", + "EXPLORATORY", + "RESOURCEFUL", + "FLEXIBLE", + "COOPERATIVE", + "UNITED", + "STRATEGIC", + "INTELLIGENT", + "RESEARCH_FOCUSED", + "COLLABORATIVE", + "PROGRESSIVE", + "MILITARISTIC", + "TECHNOLOGICALLY_ADVANCED", + "AGGRESSIVE", + "IMPERIALISTIC", + "TREASURE_HUNTERS", + "DEXTEROUS", + "UNPREDICTABLE", + "BRUTAL", + "FLEETING", + "ADAPTABLE", + "SELF_SUFFICIENT", + "DEFENSIVE", + "PROUD", + "DIVERSE", + "INDEPENDENT", + "SELF_INTERESTED", + "FRAGMENTED", + "COMMERCIAL", + "FREE_MARKETS", + "ENTREPRENEURIAL" + ], + "description": "The unique identifier of the trait." + }, + "Meta": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "minimum": 0, + "description": "Shows the total amount of items of this kind that exist." + }, + "page": { + "type": "integer", + "minimum": 1, + "default": 1, + "description": "A page denotes an amount of items, offset from the first item. Each page holds an amount of items equal to the `limit`." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "description": "The amount of items in each page. Limits how many items can be fetched at once." + } + }, + "required": [ + "total", + "page", + "limit" + ], + "description": "Meta details for pagination.", + "x-examples": { + "example-1": { + "limit": 20, + "page": 1, + "total": 6 + } + } + }, + "PublicAgent": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Symbol of the agent.", + "maxLength": 14, + "minLength": 3 + }, + "headquarters": { + "type": "string", + "description": "The headquarters of the agent.", + "minLength": 1 + }, + "credits": { + "type": "integer", + "description": "The number of credits the agent has available. Credits can be negative if funds have been overdrawn.", + "format": "int64" + }, + "startingFaction": { + "type": "string", + "description": "The faction the agent started with.", + "minLength": 1 + }, + "shipCount": { + "type": "integer", + "description": "How many ships are owned by the agent." + } + }, + "required": [ + "symbol", + "headquarters", + "credits", + "startingFaction", + "shipCount" + ], + "description": "Public agent details." + }, + "System": { + "type": "object", + "properties": { + "constellation": { + "type": "string", + "description": "The constellation that the system is part of." + }, + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the system." + }, + "sectorSymbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the sector." + }, + "type": { + "$ref": "#/components/schemas/SystemType" + }, + "x": { + "type": "integer", + "description": "Relative position of the system in the sector in the x axis." + }, + "y": { + "type": "integer", + "description": "Relative position of the system in the sector in the y axis." + }, + "waypoints": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SystemWaypoint" + }, + "description": "Waypoints in this system." + }, + "factions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SystemFaction" + }, + "description": "Factions that control this system." + }, + "name": { + "type": "string", + "description": "The name of the system." + } + }, + "required": [ + "symbol", + "sectorSymbol", + "type", + "x", + "y", + "waypoints", + "factions" + ], + "description": "System details." + }, + "SystemType": { + "type": "string", + "enum": [ + "NEUTRON_STAR", + "RED_STAR", + "ORANGE_STAR", + "BLUE_STAR", + "YOUNG_STAR", + "WHITE_DWARF", + "BLACK_HOLE", + "HYPERGIANT", + "NEBULA", + "UNSTABLE" + ], + "description": "The type of system." + }, + "SystemWaypoint": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "type": { + "$ref": "#/components/schemas/WaypointType" + }, + "x": { + "type": "integer", + "description": "Relative position of the waypoint on the system's x axis. This is not an absolute position in the universe." + }, + "y": { + "type": "integer", + "description": "Relative position of the waypoint on the system's y axis. This is not an absolute position in the universe." + }, + "orbitals": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointOrbital" + }, + "description": "Waypoints that orbit this waypoint." + }, + "orbits": { + "type": "string", + "minLength": 1, + "description": "The symbol of the parent waypoint, if this waypoint is in orbit around another waypoint. Otherwise this value is undefined." + } + }, + "required": [ + "symbol", + "type", + "x", + "y", + "orbitals" + ], + "description": "Waypoint details." + }, + "WaypointSymbol": { + "type": "string", + "description": "The symbol of the waypoint.", + "minLength": 1, + "x-faker": { + "fake": [ + "X1-{{random.alphaNumeric(4)}}-{{random.alphaNumeric(4)}}" + ] + } + }, + "WaypointType": { + "type": "string", + "enum": [ + "PLANET", + "GAS_GIANT", + "MOON", + "ORBITAL_STATION", + "JUMP_GATE", + "ASTEROID_FIELD", + "ASTEROID", + "ENGINEERED_ASTEROID", + "ASTEROID_BASE", + "NEBULA", + "DEBRIS_FIELD", + "GRAVITY_WELL", + "ARTIFICIAL_GRAVITY_WELL", + "FUEL_STATION" + ], + "description": "The type of waypoint." + }, + "WaypointOrbital": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the orbiting waypoint." + } + }, + "required": [ + "symbol" + ], + "description": "An orbital is another waypoint that orbits a parent waypoint." + }, + "SystemFaction": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/FactionSymbol" + } + }, + "required": [ + "symbol" + ] + }, + "Waypoint": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "type": { + "$ref": "#/components/schemas/WaypointType" + }, + "systemSymbol": { + "$ref": "#/components/schemas/SystemSymbol" + }, + "x": { + "type": "integer", + "description": "Relative position of the waypoint on the system's x axis. This is not an absolute position in the universe." + }, + "y": { + "type": "integer", + "description": "Relative position of the waypoint on the system's y axis. This is not an absolute position in the universe." + }, + "orbitals": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointOrbital" + }, + "description": "Waypoints that orbit this waypoint." + }, + "orbits": { + "type": "string", + "minLength": 1, + "description": "The symbol of the parent waypoint, if this waypoint is in orbit around another waypoint. Otherwise this value is undefined." + }, + "faction": { + "$ref": "#/components/schemas/WaypointFaction" + }, + "traits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointTrait" + }, + "description": "The traits of the waypoint." + }, + "modifiers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointModifier" + }, + "description": "The modifiers of the waypoint." + }, + "chart": { + "$ref": "#/components/schemas/Chart" + }, + "isUnderConstruction": { + "type": "boolean", + "description": "True if the waypoint is under construction." + } + }, + "required": [ + "symbol", + "type", + "systemSymbol", + "x", + "y", + "orbitals", + "traits", + "isUnderConstruction" + ], + "description": "A waypoint is a location that ships can travel to such as a Planet, Moon or Space Station." + }, + "SystemSymbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the system.", + "x-faker": { + "fake": [ + "X1-{{random.alphaNumeric(4)}}" + ] + } + }, + "WaypointFaction": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/FactionSymbol" + } + }, + "required": [ + "symbol" + ], + "description": "The faction that controls the waypoint." + }, + "WaypointTrait": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/WaypointTraitSymbol" + }, + "name": { + "type": "string", + "description": "The name of the trait." + }, + "description": { + "type": "string", + "description": "A description of the trait." + } + }, + "required": [ + "symbol", + "name", + "description" + ] + }, + "WaypointTraitSymbol": { + "type": "string", + "enum": [ + "UNCHARTED", + "UNDER_CONSTRUCTION", + "MARKETPLACE", + "SHIPYARD", + "OUTPOST", + "SCATTERED_SETTLEMENTS", + "SPRAWLING_CITIES", + "MEGA_STRUCTURES", + "PIRATE_BASE", + "OVERCROWDED", + "HIGH_TECH", + "CORRUPT", + "BUREAUCRATIC", + "TRADING_HUB", + "INDUSTRIAL", + "BLACK_MARKET", + "RESEARCH_FACILITY", + "MILITARY_BASE", + "SURVEILLANCE_OUTPOST", + "EXPLORATION_OUTPOST", + "MINERAL_DEPOSITS", + "COMMON_METAL_DEPOSITS", + "PRECIOUS_METAL_DEPOSITS", + "RARE_METAL_DEPOSITS", + "METHANE_POOLS", + "ICE_CRYSTALS", + "EXPLOSIVE_GASES", + "STRONG_MAGNETOSPHERE", + "VIBRANT_AURORAS", + "SALT_FLATS", + "CANYONS", + "PERPETUAL_DAYLIGHT", + "PERPETUAL_OVERCAST", + "DRY_SEABEDS", + "MAGMA_SEAS", + "SUPERVOLCANOES", + "ASH_CLOUDS", + "VAST_RUINS", + "MUTATED_FLORA", + "TERRAFORMED", + "EXTREME_TEMPERATURES", + "EXTREME_PRESSURE", + "DIVERSE_LIFE", + "SCARCE_LIFE", + "FOSSILS", + "WEAK_GRAVITY", + "STRONG_GRAVITY", + "CRUSHING_GRAVITY", + "TOXIC_ATMOSPHERE", + "CORROSIVE_ATMOSPHERE", + "BREATHABLE_ATMOSPHERE", + "THIN_ATMOSPHERE", + "JOVIAN", + "ROCKY", + "VOLCANIC", + "FROZEN", + "SWAMP", + "BARREN", + "TEMPERATE", + "JUNGLE", + "OCEAN", + "RADIOACTIVE", + "MICRO_GRAVITY_ANOMALIES", + "DEBRIS_CLUSTER", + "DEEP_CRATERS", + "SHALLOW_CRATERS", + "UNSTABLE_COMPOSITION", + "HOLLOWED_INTERIOR", + "STRIPPED" + ], + "description": "The unique identifier of the trait." + }, + "WaypointModifier": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/WaypointModifierSymbol" + }, + "name": { + "type": "string", + "description": "The name of the trait." + }, + "description": { + "type": "string", + "description": "A description of the trait." + } + }, + "required": [ + "symbol", + "name", + "description" + ] + }, + "WaypointModifierSymbol": { + "type": "string", + "enum": [ + "STRIPPED", + "UNSTABLE", + "RADIATION_LEAK", + "CRITICAL_LIMIT", + "CIVIL_UNREST" + ], + "title": "Waypoint Modifier Symbol", + "description": "The unique identifier of the modifier." + }, + "Chart": { + "type": "object", + "properties": { + "waypointSymbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "submittedBy": { + "type": "string", + "description": "The agent that submitted the chart for this waypoint." + }, + "submittedOn": { + "type": "string", + "format": "date-time", + "description": "The time the chart for this waypoint was submitted." + } + }, + "required": [ + "waypointSymbol", + "submittedBy", + "submittedOn" + ], + "description": "The chart of a system or waypoint, which makes the location visible to other agents." + }, + "Construction": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The symbol of the waypoint." + }, + "materials": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConstructionMaterial" + }, + "description": "The materials required to construct the waypoint." + }, + "isComplete": { + "type": "boolean", + "description": "Whether the waypoint has been constructed." + } + }, + "required": [ + "symbol", + "materials", + "isComplete" + ], + "description": "The construction details of a waypoint." + }, + "ConstructionMaterial": { + "type": "object", + "properties": { + "tradeSymbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "required": { + "type": "integer", + "description": "The number of units required." + }, + "fulfilled": { + "type": "integer", + "description": "The number of units fulfilled toward the required amount." + } + }, + "required": [ + "tradeSymbol", + "required", + "fulfilled" + ], + "description": "The details of the required construction materials for a given waypoint under construction." + }, + "TradeSymbol": { + "type": "string", + "enum": [ + "PRECIOUS_STONES", + "QUARTZ_SAND", + "SILICON_CRYSTALS", + "AMMONIA_ICE", + "LIQUID_HYDROGEN", + "LIQUID_NITROGEN", + "ICE_WATER", + "EXOTIC_MATTER", + "ADVANCED_CIRCUITRY", + "GRAVITON_EMITTERS", + "IRON", + "IRON_ORE", + "COPPER", + "COPPER_ORE", + "ALUMINUM", + "ALUMINUM_ORE", + "SILVER", + "SILVER_ORE", + "GOLD", + "GOLD_ORE", + "PLATINUM", + "PLATINUM_ORE", + "DIAMONDS", + "URANITE", + "URANITE_ORE", + "MERITIUM", + "MERITIUM_ORE", + "HYDROCARBON", + "ANTIMATTER", + "FAB_MATS", + "FERTILIZERS", + "FABRICS", + "FOOD", + "JEWELRY", + "MACHINERY", + "FIREARMS", + "ASSAULT_RIFLES", + "MILITARY_EQUIPMENT", + "EXPLOSIVES", + "LAB_INSTRUMENTS", + "AMMUNITION", + "ELECTRONICS", + "SHIP_PLATING", + "SHIP_PARTS", + "EQUIPMENT", + "FUEL", + "MEDICINE", + "DRUGS", + "CLOTHING", + "MICROPROCESSORS", + "PLASTICS", + "POLYNUCLEOTIDES", + "BIOCOMPOSITES", + "QUANTUM_STABILIZERS", + "NANOBOTS", + "AI_MAINFRAMES", + "QUANTUM_DRIVES", + "ROBOTIC_DRONES", + "CYBER_IMPLANTS", + "GENE_THERAPEUTICS", + "NEURAL_CHIPS", + "MOOD_REGULATORS", + "VIRAL_AGENTS", + "MICRO_FUSION_GENERATORS", + "SUPERGRAINS", + "LASER_RIFLES", + "HOLOGRAPHICS", + "SHIP_SALVAGE", + "RELIC_TECH", + "NOVEL_LIFEFORMS", + "BOTANICAL_SPECIMENS", + "CULTURAL_ARTIFACTS", + "FRAME_PROBE", + "FRAME_DRONE", + "FRAME_INTERCEPTOR", + "FRAME_RACER", + "FRAME_FIGHTER", + "FRAME_FRIGATE", + "FRAME_SHUTTLE", + "FRAME_EXPLORER", + "FRAME_MINER", + "FRAME_LIGHT_FREIGHTER", + "FRAME_HEAVY_FREIGHTER", + "FRAME_TRANSPORT", + "FRAME_DESTROYER", + "FRAME_CRUISER", + "FRAME_CARRIER", + "FRAME_BULK_FREIGHTER", + "REACTOR_SOLAR_I", + "REACTOR_FUSION_I", + "REACTOR_FISSION_I", + "REACTOR_CHEMICAL_I", + "REACTOR_ANTIMATTER_I", + "ENGINE_IMPULSE_DRIVE_I", + "ENGINE_ION_DRIVE_I", + "ENGINE_ION_DRIVE_II", + "ENGINE_HYPER_DRIVE_I", + "MODULE_MINERAL_PROCESSOR_I", + "MODULE_GAS_PROCESSOR_I", + "MODULE_CARGO_HOLD_I", + "MODULE_CARGO_HOLD_II", + "MODULE_CARGO_HOLD_III", + "MODULE_CREW_QUARTERS_I", + "MODULE_ENVOY_QUARTERS_I", + "MODULE_PASSENGER_CABIN_I", + "MODULE_MICRO_REFINERY_I", + "MODULE_SCIENCE_LAB_I", + "MODULE_JUMP_DRIVE_I", + "MODULE_JUMP_DRIVE_II", + "MODULE_JUMP_DRIVE_III", + "MODULE_WARP_DRIVE_I", + "MODULE_WARP_DRIVE_II", + "MODULE_WARP_DRIVE_III", + "MODULE_SHIELD_GENERATOR_I", + "MODULE_SHIELD_GENERATOR_II", + "MODULE_ORE_REFINERY_I", + "MODULE_FUEL_REFINERY_I", + "MOUNT_GAS_SIPHON_I", + "MOUNT_GAS_SIPHON_II", + "MOUNT_GAS_SIPHON_III", + "MOUNT_SURVEYOR_I", + "MOUNT_SURVEYOR_II", + "MOUNT_SURVEYOR_III", + "MOUNT_SENSOR_ARRAY_I", + "MOUNT_SENSOR_ARRAY_II", + "MOUNT_SENSOR_ARRAY_III", + "MOUNT_MINING_LASER_I", + "MOUNT_MINING_LASER_II", + "MOUNT_MINING_LASER_III", + "MOUNT_LASER_CANNON_I", + "MOUNT_MISSILE_LAUNCHER_I", + "MOUNT_TURRET_I", + "SHIP_PROBE", + "SHIP_MINING_DRONE", + "SHIP_SIPHON_DRONE", + "SHIP_INTERCEPTOR", + "SHIP_LIGHT_HAULER", + "SHIP_COMMAND_FRIGATE", + "SHIP_EXPLORER", + "SHIP_HEAVY_FREIGHTER", + "SHIP_LIGHT_SHUTTLE", + "SHIP_ORE_HOUND", + "SHIP_REFINING_FREIGHTER", + "SHIP_SURVEYOR", + "SHIP_BULK_FREIGHTER" + ], + "description": "The good's symbol." + }, + "ShipCargo": { + "type": "object", + "properties": { + "capacity": { + "type": "integer", + "minimum": 0, + "description": "The max number of items that can be stored in the cargo hold." + }, + "units": { + "type": "integer", + "minimum": 0, + "description": "The number of items currently stored in the cargo hold." + }, + "inventory": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipCargoItem" + }, + "description": "The items currently in the cargo hold." + } + }, + "required": [ + "capacity", + "units", + "inventory" + ], + "description": "Ship cargo details." + }, + "ShipCargoItem": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "name": { + "type": "string", + "description": "The name of the cargo item type." + }, + "description": { + "type": "string", + "description": "The description of the cargo item type." + }, + "units": { + "type": "integer", + "description": "The number of units of the cargo item.", + "minimum": 1 + } + }, + "required": [ + "symbol", + "name", + "description", + "units" + ], + "description": "The type of cargo item and the number of units." + }, + "Market": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The symbol of the market. The symbol is the same as the waypoint where the market is located." + }, + "exports": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TradeGood" + }, + "description": "The list of goods that are exported from this market." + }, + "imports": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TradeGood" + }, + "description": "The list of goods that are sought as imports in this market." + }, + "exchange": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TradeGood" + }, + "description": "The list of goods that are bought and sold between agents at this market." + }, + "transactions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MarketTransaction" + }, + "description": "The list of recent transactions at this market. Visible only when a ship is present at the market." + }, + "tradeGoods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MarketTradeGood" + }, + "description": "The list of goods that are traded at this market. Visible only when a ship is present at the market." + } + }, + "required": [ + "symbol", + "exports", + "imports", + "exchange" + ], + "description": "Market details." + }, + "TradeGood": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "name": { + "type": "string", + "description": "The name of the good." + }, + "description": { + "type": "string", + "description": "The description of the good." + } + }, + "required": [ + "symbol", + "name", + "description" + ], + "description": "A good that can be traded for other goods or currency." + }, + "MarketTransaction": { + "type": "object", + "properties": { + "waypointSymbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship that made the transaction." + }, + "tradeSymbol": { + "type": "string", + "description": "The symbol of the trade good." + }, + "type": { + "type": "string", + "enum": [ + "PURCHASE", + "SELL" + ], + "description": "The type of transaction." + }, + "units": { + "type": "integer", + "minimum": 0, + "description": "The number of units of the transaction." + }, + "pricePerUnit": { + "type": "integer", + "minimum": 0, + "description": "The price per unit of the transaction." + }, + "totalPrice": { + "type": "integer", + "minimum": 0, + "description": "The total price of the transaction." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the transaction." + } + }, + "required": [ + "waypointSymbol", + "shipSymbol", + "tradeSymbol", + "type", + "units", + "pricePerUnit", + "totalPrice", + "timestamp" + ], + "description": "Result of a transaction with a market." + }, + "MarketTradeGood": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "type": { + "type": "string", + "enum": [ + "EXPORT", + "IMPORT", + "EXCHANGE" + ], + "description": "The type of trade good (export, import, or exchange)." + }, + "tradeVolume": { + "type": "integer", + "minimum": 1, + "description": "This is the maximum number of units that can be purchased or sold at this market in a single trade for this good. Trade volume also gives an indication of price volatility. A market with a low trade volume will have large price swings, while high trade volume will be more resilient to price changes." + }, + "supply": { + "$ref": "#/components/schemas/SupplyLevel" + }, + "activity": { + "$ref": "#/components/schemas/ActivityLevel" + }, + "purchasePrice": { + "type": "integer", + "minimum": 0, + "description": "The price at which this good can be purchased from the market." + }, + "sellPrice": { + "type": "integer", + "minimum": 0, + "description": "The price at which this good can be sold to the market." + } + }, + "required": [ + "symbol", + "type", + "tradeVolume", + "supply", + "purchasePrice", + "sellPrice" + ] + }, + "SupplyLevel": { + "type": "string", + "enum": [ + "SCARCE", + "LIMITED", + "MODERATE", + "HIGH", + "ABUNDANT" + ], + "description": "The supply level of a trade good." + }, + "ActivityLevel": { + "type": "string", + "enum": [ + "WEAK", + "GROWING", + "STRONG", + "RESTRICTED" + ], + "description": "The activity level of a trade good. If the good is an import, this represents how strong consumption is. If the good is an export, this represents how strong the production is for the good. When activity is strong, consumption or production is near maximum capacity. When activity is weak, consumption or production is near minimum capacity.", + "x-enumDescriptions": { + "GROWING": "Represents increasing activity in production or consumption, suggesting a developing market.", + "RESTRICTED": "Reflects a bottleneck in production or consumption, possibly due to a lack of supply or demand in related goods.", + "STRONG": "Signifies high levels of production or consumption. Indicates a healthy and active market with high demand or supply.", + "WEAK": "Indicates very low production or consumption activity. This may suggest a surplus in supply or a lack of demand." + } + }, + "JumpGate": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "connections": { + "type": "array", + "items": { + "type": "string", + "description": "The symbol of the waypoint that has a corresponding gate." + }, + "description": "All the gates that are connected to this waypoint." + } + }, + "required": [ + "symbol", + "connections" + ], + "description": "Details of a jump gate waypoint." + }, + "Shipyard": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the shipyard. The symbol is the same as the waypoint where the shipyard is located." + }, + "shipTypes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/ShipType" + } + }, + "required": [ + "type" + ] + }, + "description": "The list of ship types available for purchase at this shipyard." + }, + "transactions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipyardTransaction" + }, + "description": "The list of recent transactions at this shipyard." + }, + "ships": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipyardShip" + }, + "description": "The ships that are currently available for purchase at the shipyard." + }, + "modificationsFee": { + "type": "integer", + "description": "The fee to modify a ship at this shipyard. This includes installing or removing modules and mounts on a ship. In the case of mounts, the fee is a flat rate per mount. In the case of modules, the fee is per slot the module occupies." + } + }, + "required": [ + "symbol", + "shipTypes", + "modificationsFee" + ], + "description": "Shipyard details." + }, + "ShipType": { + "type": "string", + "enum": [ + "SHIP_PROBE", + "SHIP_MINING_DRONE", + "SHIP_SIPHON_DRONE", + "SHIP_INTERCEPTOR", + "SHIP_LIGHT_HAULER", + "SHIP_COMMAND_FRIGATE", + "SHIP_EXPLORER", + "SHIP_HEAVY_FREIGHTER", + "SHIP_LIGHT_SHUTTLE", + "SHIP_ORE_HOUND", + "SHIP_REFINING_FREIGHTER", + "SHIP_SURVEYOR", + "SHIP_BULK_FREIGHTER" + ], + "description": "Type of ship" + }, + "ShipyardTransaction": { + "type": "object", + "properties": { + "waypointSymbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship type (e.g. SHIP_MINING_DRONE) that was the subject of the transaction. Contrary to what the name implies, this is NOT the symbol of the ship that was purchased.", + "deprecated": true + }, + "shipType": { + "type": "string", + "description": "The symbol of the ship type (e.g. SHIP_MINING_DRONE) that was the subject of the transaction." + }, + "price": { + "type": "integer", + "minimum": 0, + "description": "The price of the transaction." + }, + "agentSymbol": { + "type": "string", + "description": "The symbol of the agent that made the transaction." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the transaction." + } + }, + "required": [ + "waypointSymbol", + "shipSymbol", + "shipType", + "price", + "agentSymbol", + "timestamp" + ], + "description": "Results of a transaction with a shipyard." + }, + "ShipyardShip": { + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/ShipType" + }, + "name": { + "type": "string", + "description": "Name of the ship." + }, + "description": { + "type": "string", + "description": "Description of the ship." + }, + "activity": { + "$ref": "#/components/schemas/ActivityLevel" + }, + "supply": { + "$ref": "#/components/schemas/SupplyLevel" + }, + "purchasePrice": { + "type": "integer", + "description": "The purchase price of the ship." + }, + "frame": { + "$ref": "#/components/schemas/ShipFrame" + }, + "reactor": { + "$ref": "#/components/schemas/ShipReactor" + }, + "engine": { + "$ref": "#/components/schemas/ShipEngine" + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipModule" + }, + "description": "Modules installed in this ship." + }, + "mounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipMount" + }, + "description": "Mounts installed in this ship." + }, + "crew": { + "type": "object", + "properties": { + "required": { + "type": "integer", + "description": "The minimum number of crew members required to maintain the ship." + }, + "capacity": { + "type": "integer", + "description": "The maximum number of crew members the ship can support." + } + }, + "required": [ + "required", + "capacity" + ] + } + }, + "required": [ + "type", + "name", + "description", + "supply", + "purchasePrice", + "frame", + "reactor", + "engine", + "modules", + "mounts", + "crew" + ], + "description": "Ship details available at a shipyard." + }, + "ShipFrame": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "enum": [ + "FRAME_PROBE", + "FRAME_DRONE", + "FRAME_INTERCEPTOR", + "FRAME_RACER", + "FRAME_FIGHTER", + "FRAME_FRIGATE", + "FRAME_SHUTTLE", + "FRAME_EXPLORER", + "FRAME_MINER", + "FRAME_LIGHT_FREIGHTER", + "FRAME_HEAVY_FREIGHTER", + "FRAME_TRANSPORT", + "FRAME_DESTROYER", + "FRAME_CRUISER", + "FRAME_CARRIER", + "FRAME_BULK_FREIGHTER" + ], + "description": "Symbol of the frame." + }, + "name": { + "type": "string", + "description": "Name of the frame." + }, + "condition": { + "$ref": "#/components/schemas/ShipComponentCondition" + }, + "integrity": { + "$ref": "#/components/schemas/ShipComponentIntegrity" + }, + "description": { + "type": "string", + "description": "Description of the frame." + }, + "moduleSlots": { + "type": "integer", + "minimum": 0, + "description": "The amount of slots that can be dedicated to modules installed in the ship. Each installed module take up a number of slots, and once there are no more slots, no new modules can be installed." + }, + "mountingPoints": { + "type": "integer", + "minimum": 0, + "description": "The amount of slots that can be dedicated to mounts installed in the ship. Each installed mount takes up a number of points, and once there are no more points remaining, no new mounts can be installed." + }, + "fuelCapacity": { + "type": "integer", + "minimum": 0, + "description": "The maximum amount of fuel that can be stored in this ship. When refueling, the ship will be refueled to this amount." + }, + "requirements": { + "$ref": "#/components/schemas/ShipRequirements" + }, + "quality": { + "$ref": "#/components/schemas/ShipComponentQuality" + } + }, + "required": [ + "symbol", + "name", + "condition", + "integrity", + "description", + "moduleSlots", + "mountingPoints", + "fuelCapacity", + "requirements", + "quality" + ], + "description": "The frame of the ship. The frame determines the number of modules and mounting points of the ship, as well as base fuel capacity. As the condition of the frame takes more wear, the ship will become more sluggish and less maneuverable." + }, + "ShipComponentCondition": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The repairable condition of a component. A value of 0 indicates the component needs significant repairs, while a value of 1 indicates the component is in near perfect condition. As the condition of a component is repaired, the overall integrity of the component decreases.", + "format": "double" + }, + "ShipComponentIntegrity": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The overall integrity of the component, which determines the performance of the component. A value of 0 indicates that the component is almost completely degraded, while a value of 1 indicates that the component is in near perfect condition. The integrity of the component is non-repairable, and represents permanent wear over time.", + "format": "double" + }, + "ShipRequirements": { + "type": "object", + "properties": { + "power": { + "type": "integer", + "description": "The amount of power required from the reactor." + }, + "crew": { + "type": "integer", + "description": "The number of crew required for operation." + }, + "slots": { + "type": "integer", + "description": "The number of module slots required for installation." + } + }, + "description": "The requirements for installation on a ship" + }, + "ShipComponentQuality": { + "type": "number", + "description": "The overall quality of the component, which determines the quality of the component. High quality components return more ships parts and ship plating when a ship is scrapped. But also require more of these parts to repair. This is transparent to the player, as the parts are bought from/sold to the marketplace.", + "format": "integer" + }, + "ShipReactor": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "enum": [ + "REACTOR_SOLAR_I", + "REACTOR_FUSION_I", + "REACTOR_FISSION_I", + "REACTOR_CHEMICAL_I", + "REACTOR_ANTIMATTER_I" + ], + "description": "Symbol of the reactor." + }, + "name": { + "type": "string", + "description": "Name of the reactor." + }, + "condition": { + "$ref": "#/components/schemas/ShipComponentCondition" + }, + "integrity": { + "$ref": "#/components/schemas/ShipComponentIntegrity" + }, + "description": { + "type": "string", + "description": "Description of the reactor." + }, + "powerOutput": { + "type": "integer", + "minimum": 1, + "description": "The amount of power provided by this reactor. The more power a reactor provides to the ship, the lower the cooldown it gets when using a module or mount that taxes the ship's power." + }, + "requirements": { + "$ref": "#/components/schemas/ShipRequirements" + }, + "quality": { + "$ref": "#/components/schemas/ShipComponentQuality" + } + }, + "required": [ + "symbol", + "name", + "condition", + "integrity", + "description", + "powerOutput", + "requirements", + "quality" + ], + "description": "The reactor of the ship. The reactor is responsible for powering the ship's systems and weapons." + }, + "ShipEngine": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "enum": [ + "ENGINE_IMPULSE_DRIVE_I", + "ENGINE_ION_DRIVE_I", + "ENGINE_ION_DRIVE_II", + "ENGINE_HYPER_DRIVE_I" + ], + "description": "The symbol of the engine." + }, + "name": { + "type": "string", + "description": "The name of the engine." + }, + "condition": { + "$ref": "#/components/schemas/ShipComponentCondition" + }, + "integrity": { + "$ref": "#/components/schemas/ShipComponentIntegrity" + }, + "description": { + "type": "string", + "description": "The description of the engine." + }, + "speed": { + "type": "integer", + "minimum": 1, + "description": "The speed stat of this engine. The higher the speed, the faster a ship can travel from one point to another. Reduces the time of arrival when navigating the ship." + }, + "requirements": { + "$ref": "#/components/schemas/ShipRequirements" + }, + "quality": { + "$ref": "#/components/schemas/ShipComponentQuality" + } + }, + "required": [ + "symbol", + "name", + "condition", + "integrity", + "description", + "speed", + "requirements", + "quality" + ], + "description": "The engine determines how quickly a ship travels between waypoints." + }, + "ShipModule": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "enum": [ + "MODULE_MINERAL_PROCESSOR_I", + "MODULE_GAS_PROCESSOR_I", + "MODULE_CARGO_HOLD_I", + "MODULE_CARGO_HOLD_II", + "MODULE_CARGO_HOLD_III", + "MODULE_CREW_QUARTERS_I", + "MODULE_ENVOY_QUARTERS_I", + "MODULE_PASSENGER_CABIN_I", + "MODULE_MICRO_REFINERY_I", + "MODULE_ORE_REFINERY_I", + "MODULE_FUEL_REFINERY_I", + "MODULE_SCIENCE_LAB_I", + "MODULE_JUMP_DRIVE_I", + "MODULE_JUMP_DRIVE_II", + "MODULE_JUMP_DRIVE_III", + "MODULE_WARP_DRIVE_I", + "MODULE_WARP_DRIVE_II", + "MODULE_WARP_DRIVE_III", + "MODULE_SHIELD_GENERATOR_I", + "MODULE_SHIELD_GENERATOR_II" + ], + "description": "The symbol of the module." + }, + "name": { + "type": "string", + "description": "Name of this module." + }, + "description": { + "type": "string", + "description": "Description of this module." + }, + "capacity": { + "type": "integer", + "minimum": 0, + "description": "Modules that provide capacity, such as cargo hold or crew quarters will show this value to denote how much of a bonus the module grants." + }, + "range": { + "type": "integer", + "minimum": 0, + "description": "Modules that have a range will such as a sensor array show this value to denote how far can the module reach with its capabilities." + }, + "requirements": { + "$ref": "#/components/schemas/ShipRequirements" + } + }, + "required": [ + "symbol", + "name", + "description", + "requirements" + ], + "description": "A module can be installed in a ship and provides a set of capabilities such as storage space or quarters for crew. Module installations are permanent." + }, + "ShipMount": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "enum": [ + "MOUNT_GAS_SIPHON_I", + "MOUNT_GAS_SIPHON_II", + "MOUNT_GAS_SIPHON_III", + "MOUNT_SURVEYOR_I", + "MOUNT_SURVEYOR_II", + "MOUNT_SURVEYOR_III", + "MOUNT_SENSOR_ARRAY_I", + "MOUNT_SENSOR_ARRAY_II", + "MOUNT_SENSOR_ARRAY_III", + "MOUNT_MINING_LASER_I", + "MOUNT_MINING_LASER_II", + "MOUNT_MINING_LASER_III", + "MOUNT_LASER_CANNON_I", + "MOUNT_MISSILE_LAUNCHER_I", + "MOUNT_TURRET_I" + ], + "description": "Symbol of this mount." + }, + "name": { + "type": "string", + "description": "Name of this mount." + }, + "description": { + "type": "string", + "description": "Description of this mount." + }, + "strength": { + "type": "integer", + "minimum": 0, + "description": "Mounts that have this value, such as mining lasers, denote how powerful this mount's capabilities are." + }, + "deposits": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "QUARTZ_SAND", + "SILICON_CRYSTALS", + "PRECIOUS_STONES", + "ICE_WATER", + "AMMONIA_ICE", + "IRON_ORE", + "COPPER_ORE", + "SILVER_ORE", + "ALUMINUM_ORE", + "GOLD_ORE", + "PLATINUM_ORE", + "DIAMONDS", + "URANITE_ORE", + "MERITIUM_ORE" + ] + }, + "description": "Mounts that have this value denote what goods can be produced from using the mount." + }, + "requirements": { + "$ref": "#/components/schemas/ShipRequirements" + } + }, + "required": [ + "symbol", + "name", + "description", + "requirements" + ], + "description": "A mount is installed on the exterier of a ship." + }, + "Contract": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "description": "ID of the contract." + }, + "factionSymbol": { + "type": "string", + "description": "The symbol of the faction that this contract is for.", + "minLength": 1 + }, + "type": { + "type": "string", + "enum": [ + "PROCUREMENT", + "TRANSPORT", + "SHUTTLE" + ], + "description": "Type of contract." + }, + "terms": { + "$ref": "#/components/schemas/ContractTerms" + }, + "accepted": { + "type": "boolean", + "default": false, + "description": "Whether the contract has been accepted by the agent" + }, + "fulfilled": { + "type": "boolean", + "default": false, + "description": "Whether the contract has been fulfilled" + }, + "expiration": { + "type": "string", + "format": "date-time", + "description": "Deprecated in favor of deadlineToAccept", + "deprecated": true + }, + "deadlineToAccept": { + "type": "string", + "format": "date-time", + "description": "The time at which the contract is no longer available to be accepted" + } + }, + "required": [ + "id", + "factionSymbol", + "type", + "terms", + "accepted", + "fulfilled", + "expiration" + ], + "description": "Contract details." + }, + "ContractTerms": { + "type": "object", + "properties": { + "deadline": { + "type": "string", + "format": "date-time", + "description": "The deadline for the contract." + }, + "payment": { + "$ref": "#/components/schemas/ContractPayment" + }, + "deliver": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContractDeliverGood" + }, + "description": "The cargo that needs to be delivered to fulfill the contract." + } + }, + "required": [ + "deadline", + "payment" + ], + "description": "The terms to fulfill the contract." + }, + "ContractPayment": { + "type": "object", + "properties": { + "onAccepted": { + "type": "integer", + "description": "The amount of credits received up front for accepting the contract." + }, + "onFulfilled": { + "type": "integer", + "description": "The amount of credits received when the contract is fulfilled." + } + }, + "required": [ + "onAccepted", + "onFulfilled" + ], + "description": "Payments for the contract." + }, + "ContractDeliverGood": { + "type": "object", + "properties": { + "tradeSymbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the trade good to deliver." + }, + "destinationSymbol": { + "type": "string", + "minLength": 1, + "description": "The destination where goods need to be delivered." + }, + "unitsRequired": { + "type": "integer", + "description": "The number of units that need to be delivered on this contract." + }, + "unitsFulfilled": { + "type": "integer", + "description": "The number of units fulfilled on this contract." + } + }, + "required": [ + "tradeSymbol", + "destinationSymbol", + "unitsRequired", + "unitsFulfilled" + ], + "description": "The details of a delivery contract. Includes the type of good, units needed, and the destination." + }, + "Agent": { + "type": "object", + "properties": { + "accountId": { + "type": "string", + "description": "Account ID that is tied to this agent. Only included on your own agent.", + "minLength": 1 + }, + "symbol": { + "type": "string", + "description": "Symbol of the agent.", + "maxLength": 14, + "minLength": 3 + }, + "headquarters": { + "type": "string", + "description": "The headquarters of the agent.", + "minLength": 1 + }, + "credits": { + "type": "integer", + "description": "The number of credits the agent has available. Credits can be negative if funds have been overdrawn.", + "format": "int64" + }, + "startingFaction": { + "type": "string", + "description": "The faction the agent started with.", + "minLength": 1 + }, + "shipCount": { + "type": "integer", + "description": "How many ships are owned by the agent." + } + }, + "required": [ + "accountId", + "symbol", + "headquarters", + "credits", + "startingFaction", + "shipCount" + ], + "description": "Agent details." + }, + "AgentEvent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "message": { + "type": "string" + }, + "data": {}, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "type", + "message", + "createdAt" + ], + "description": "Agent event details." + }, + "Ship": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The globally unique identifier of the ship in the following format: `[AGENT_SYMBOL]-[HEX_ID]`" + }, + "registration": { + "$ref": "#/components/schemas/ShipRegistration" + }, + "nav": { + "$ref": "#/components/schemas/ShipNav" + }, + "crew": { + "$ref": "#/components/schemas/ShipCrew" + }, + "frame": { + "$ref": "#/components/schemas/ShipFrame" + }, + "reactor": { + "$ref": "#/components/schemas/ShipReactor" + }, + "engine": { + "$ref": "#/components/schemas/ShipEngine" + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipModule" + }, + "description": "Modules installed in this ship." + }, + "mounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipMount" + }, + "description": "Mounts installed in this ship." + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "fuel": { + "$ref": "#/components/schemas/ShipFuel" + }, + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + } + }, + "required": [ + "symbol", + "registration", + "nav", + "crew", + "frame", + "reactor", + "engine", + "modules", + "mounts", + "cargo", + "fuel", + "cooldown" + ], + "description": "Ship details." + }, + "ShipRegistration": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "The agent's registered name of the ship" + }, + "factionSymbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the faction the ship is registered with" + }, + "role": { + "$ref": "#/components/schemas/ShipRole" + } + }, + "required": [ + "name", + "factionSymbol", + "role" + ], + "description": "The public registration information of the ship" + }, + "ShipRole": { + "type": "string", + "enum": [ + "FABRICATOR", + "HARVESTER", + "HAULER", + "INTERCEPTOR", + "EXCAVATOR", + "TRANSPORT", + "REPAIR", + "SURVEYOR", + "COMMAND", + "CARRIER", + "PATROL", + "SATELLITE", + "EXPLORER", + "REFINERY" + ], + "description": "The registered role of the ship" + }, + "ShipNav": { + "type": "object", + "properties": { + "systemSymbol": { + "$ref": "#/components/schemas/SystemSymbol" + }, + "waypointSymbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "route": { + "$ref": "#/components/schemas/ShipNavRoute" + }, + "status": { + "$ref": "#/components/schemas/ShipNavStatus" + }, + "flightMode": { + "$ref": "#/components/schemas/ShipNavFlightMode" + } + }, + "required": [ + "systemSymbol", + "waypointSymbol", + "route", + "status", + "flightMode" + ], + "description": "The navigation information of the ship." + }, + "ShipNavRoute": { + "type": "object", + "properties": { + "destination": { + "$ref": "#/components/schemas/ShipNavRouteWaypoint" + }, + "origin": { + "$ref": "#/components/schemas/ShipNavRouteWaypoint" + }, + "departureTime": { + "type": "string", + "format": "date-time", + "description": "The date time of the ship's departure." + }, + "arrival": { + "type": "string", + "format": "date-time", + "description": "The date time of the ship's arrival. If the ship is in-transit, this is the expected time of arrival." + } + }, + "required": [ + "destination", + "origin", + "departureTime", + "arrival" + ], + "description": "The routing information for the ship's most recent transit or current location." + }, + "ShipNavRouteWaypoint": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the waypoint." + }, + "type": { + "$ref": "#/components/schemas/WaypointType" + }, + "systemSymbol": { + "$ref": "#/components/schemas/SystemSymbol" + }, + "x": { + "type": "integer", + "description": "Position in the universe in the x axis." + }, + "y": { + "type": "integer", + "description": "Position in the universe in the y axis." + } + }, + "required": [ + "symbol", + "type", + "systemSymbol", + "x", + "y" + ], + "description": "The destination or departure of a ships nav route." + }, + "ShipNavStatus": { + "type": "string", + "enum": [ + "IN_TRANSIT", + "IN_ORBIT", + "DOCKED" + ], + "description": "The current status of the ship" + }, + "ShipNavFlightMode": { + "type": "string", + "enum": [ + "DRIFT", + "STEALTH", + "CRUISE", + "BURN" + ], + "default": "CRUISE", + "description": "The ship's set speed when traveling between waypoints or systems." + }, + "ShipCrew": { + "type": "object", + "properties": { + "current": { + "type": "integer", + "description": "The current number of crew members on the ship." + }, + "required": { + "type": "integer", + "description": "The minimum number of crew members required to maintain the ship." + }, + "capacity": { + "type": "integer", + "description": "The maximum number of crew members the ship can support." + }, + "rotation": { + "type": "string", + "enum": [ + "STRICT", + "RELAXED" + ], + "default": "STRICT", + "description": "The rotation of crew shifts. A stricter shift improves the ship's performance. A more relaxed shift improves the crew's morale." + }, + "morale": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "description": "A rough measure of the crew's morale. A higher morale means the crew is happier and more productive. A lower morale means the ship is more prone to accidents." + }, + "wages": { + "type": "integer", + "minimum": 0, + "description": "The amount of credits per crew member paid per hour. Wages are paid when a ship docks at a civilized waypoint." + } + }, + "required": [ + "current", + "required", + "capacity", + "rotation", + "morale", + "wages" + ], + "description": "The ship's crew service and maintain the ship's systems and equipment." + }, + "ShipFuel": { + "type": "object", + "properties": { + "current": { + "type": "integer", + "minimum": 0, + "description": "The current amount of fuel in the ship's tanks." + }, + "capacity": { + "type": "integer", + "minimum": 0, + "description": "The maximum amount of fuel the ship's tanks can hold." + }, + "consumed": { + "type": "object", + "properties": { + "amount": { + "type": "integer", + "minimum": 0, + "description": "The amount of fuel consumed by the most recent transit or action." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The time at which the fuel was consumed." + } + }, + "required": [ + "amount", + "timestamp" + ], + "description": "An object that only shows up when an action has consumed fuel in the process. Shows the fuel consumption data." + } + }, + "required": [ + "current", + "capacity" + ], + "description": "Details of the ship's fuel tanks including how much fuel was consumed during the last transit or action." + }, + "Cooldown": { + "type": "object", + "properties": { + "shipSymbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the ship that is on cooldown" + }, + "totalSeconds": { + "type": "integer", + "minimum": 0, + "description": "The total duration of the cooldown in seconds" + }, + "remainingSeconds": { + "type": "integer", + "minimum": 0, + "description": "The remaining duration of the cooldown in seconds" + }, + "expiration": { + "type": "string", + "format": "date-time", + "description": "The date and time when the cooldown expires in ISO 8601 format" + } + }, + "required": [ + "shipSymbol", + "totalSeconds", + "remainingSeconds" + ], + "description": "A cooldown is a period of time in which a ship cannot perform certain actions." + }, + "ChartTransaction": { + "type": "object", + "properties": { + "waypointSymbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship." + }, + "totalPrice": { + "type": "integer", + "minimum": 0, + "description": "The total price of the transaction." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the transaction." + } + }, + "required": [ + "waypointSymbol", + "shipSymbol", + "totalPrice", + "timestamp" + ], + "description": "Result of a chart transaction." + }, + "Extraction": { + "type": "object", + "properties": { + "shipSymbol": { + "type": "string", + "minLength": 1, + "description": "Symbol of the ship that executed the extraction." + }, + "yield": { + "$ref": "#/components/schemas/ExtractionYield" + } + }, + "required": [ + "shipSymbol", + "yield" + ], + "description": "Extraction details." + }, + "ExtractionYield": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "units": { + "type": "integer", + "description": "The number of units extracted that were placed into the ship's cargo hold." + } + }, + "required": [ + "symbol", + "units" + ], + "description": "A yield from the extraction operation." + }, + "ShipConditionEvent": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "enum": [ + "REACTOR_OVERLOAD", + "ENERGY_SPIKE_FROM_MINERAL", + "SOLAR_FLARE_INTERFERENCE", + "COOLANT_LEAK", + "POWER_DISTRIBUTION_FLUCTUATION", + "MAGNETIC_FIELD_DISRUPTION", + "HULL_MICROMETEORITE_STRIKES", + "STRUCTURAL_STRESS_FRACTURES", + "CORROSIVE_MINERAL_CONTAMINATION", + "THERMAL_EXPANSION_MISMATCH", + "VIBRATION_DAMAGE_FROM_DRILLING", + "ELECTROMAGNETIC_FIELD_INTERFERENCE", + "IMPACT_WITH_EXTRACTED_DEBRIS", + "FUEL_EFFICIENCY_DEGRADATION", + "COOLANT_SYSTEM_AGEING", + "DUST_MICROABRASIONS", + "THRUSTER_NOZZLE_WEAR", + "EXHAUST_PORT_CLOGGING", + "BEARING_LUBRICATION_FADE", + "SENSOR_CALIBRATION_DRIFT", + "HULL_MICROMETEORITE_DAMAGE", + "SPACE_DEBRIS_COLLISION", + "THERMAL_STRESS", + "VIBRATION_OVERLOAD", + "PRESSURE_DIFFERENTIAL_STRESS", + "ELECTROMAGNETIC_SURGE_EFFECTS", + "ATMOSPHERIC_ENTRY_HEAT" + ], + "description": "The symbol of the event that occurred." + }, + "component": { + "type": "string", + "enum": [ + "FRAME", + "REACTOR", + "ENGINE" + ] + }, + "name": { + "type": "string", + "description": "The name of the event." + }, + "description": { + "type": "string", + "description": "A description of the event." + } + }, + "required": [ + "symbol", + "component", + "name", + "description" + ], + "description": "An event that represents damage or wear to a ship's reactor, frame, or engine, reducing the condition of the ship." + }, + "Survey": { + "type": "object", + "properties": { + "signature": { + "type": "string", + "minLength": 1, + "description": "A unique signature for the location of this survey. This signature is verified when attempting an extraction using this survey." + }, + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the waypoint that this survey is for." + }, + "deposits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SurveyDeposit" + }, + "description": "A list of deposits that can be found at this location. A ship will extract one of these deposits when using this survey in an extraction request. If multiple deposits of the same type are present, the chance of extracting that deposit is increased." + }, + "expiration": { + "type": "string", + "format": "date-time", + "description": "The date and time when the survey expires. After this date and time, the survey will no longer be available for extraction." + }, + "size": { + "$ref": "#/components/schemas/SurveySize" + } + }, + "required": [ + "signature", + "symbol", + "deposits", + "expiration", + "size" + ], + "description": "A resource survey of a waypoint, detailing a specific extraction location and the types of resources that can be found there." + }, + "SurveyDeposit": { + "type": "object", + "properties": { + "symbol": { + "description": "The symbol of the deposit.", + "allOf": [ + { + "$ref": "#/components/schemas/TradeSymbol" + } + ] + } + }, + "required": [ + "symbol" + ], + "description": "A surveyed deposit of a mineral or resource available for extraction." + }, + "SurveySize": { + "type": "string", + "enum": [ + "SMALL", + "MODERATE", + "LARGE" + ], + "description": "The size of the deposit. This value indicates how much can be extracted from the survey before it is exhausted." + }, + "ScannedSystem": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "Symbol of the system." + }, + "sectorSymbol": { + "type": "string", + "minLength": 1, + "description": "Symbol of the system's sector." + }, + "type": { + "$ref": "#/components/schemas/SystemType" + }, + "x": { + "type": "integer", + "description": "Position in the universe in the x axis." + }, + "y": { + "type": "integer", + "description": "Position in the universe in the y axis." + }, + "distance": { + "type": "integer", + "description": "The system's distance from the scanning ship." + } + }, + "required": [ + "symbol", + "sectorSymbol", + "type", + "x", + "y", + "distance" + ], + "description": "Details of a system was that scanned." + }, + "ScannedWaypoint": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "type": { + "$ref": "#/components/schemas/WaypointType" + }, + "systemSymbol": { + "$ref": "#/components/schemas/SystemSymbol" + }, + "x": { + "type": "integer", + "description": "Position in the universe in the x axis." + }, + "y": { + "type": "integer", + "description": "Position in the universe in the y axis." + }, + "orbitals": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointOrbital" + }, + "description": "List of waypoints that orbit this waypoint." + }, + "faction": { + "$ref": "#/components/schemas/WaypointFaction" + }, + "traits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointTrait" + }, + "description": "The traits of the waypoint." + }, + "chart": { + "$ref": "#/components/schemas/Chart" + } + }, + "required": [ + "symbol", + "type", + "systemSymbol", + "x", + "y", + "orbitals", + "traits" + ], + "description": "A waypoint that was scanned by a ship." + }, + "ScannedShip": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The globally unique identifier of the ship." + }, + "registration": { + "$ref": "#/components/schemas/ShipRegistration" + }, + "nav": { + "$ref": "#/components/schemas/ShipNav" + }, + "frame": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The symbol of the frame." + } + }, + "required": [ + "symbol" + ], + "description": "The frame of the ship." + }, + "reactor": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The symbol of the reactor." + } + }, + "required": [ + "symbol" + ], + "description": "The reactor of the ship." + }, + "engine": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The symbol of the engine." + } + }, + "required": [ + "symbol" + ], + "description": "The engine of the ship." + }, + "mounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "The symbol of the mount." + } + }, + "required": [ + "symbol" + ] + }, + "description": "List of mounts installed in the ship." + } + }, + "required": [ + "symbol", + "registration", + "nav", + "engine" + ], + "description": "The ship that was scanned. Details include information about the ship that could be detected by the scanner." + }, + "ScrapTransaction": { + "type": "object", + "properties": { + "waypointSymbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship." + }, + "totalPrice": { + "type": "integer", + "minimum": 0, + "description": "The total price of the transaction." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the transaction." + } + }, + "required": [ + "waypointSymbol", + "shipSymbol", + "totalPrice", + "timestamp" + ], + "description": "Result of a scrap transaction." + }, + "RepairTransaction": { + "type": "object", + "properties": { + "waypointSymbol": { + "$ref": "#/components/schemas/WaypointSymbol" + }, + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship." + }, + "totalPrice": { + "type": "integer", + "minimum": 0, + "description": "The total price of the transaction." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the transaction." + } + }, + "required": [ + "waypointSymbol", + "shipSymbol", + "totalPrice", + "timestamp" + ], + "description": "Result of a repair transaction." + }, + "Siphon": { + "type": "object", + "properties": { + "shipSymbol": { + "type": "string", + "minLength": 1, + "description": "Symbol of the ship that executed the siphon." + }, + "yield": { + "$ref": "#/components/schemas/SiphonYield" + } + }, + "required": [ + "shipSymbol", + "yield" + ], + "description": "Siphon details." + }, + "SiphonYield": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "units": { + "type": "integer", + "description": "The number of units siphoned that were placed into the ship's cargo hold." + } + }, + "required": [ + "symbol", + "units" + ], + "description": "A yield from the siphon operation." + }, + "ShipModificationTransaction": { + "type": "object", + "properties": { + "waypointSymbol": { + "type": "string", + "description": "The symbol of the waypoint where the transaction took place." + }, + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship that made the transaction." + }, + "tradeSymbol": { + "type": "string", + "description": "The symbol of the trade good." + }, + "totalPrice": { + "type": "integer", + "minimum": 0, + "description": "The total price of the transaction." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the transaction." + } + }, + "required": [ + "waypointSymbol", + "shipSymbol", + "tradeSymbol", + "totalPrice", + "timestamp" + ], + "description": "Result of a transaction for a ship modification, such as installing a mount or a module." + } + } + }, + "paths": { + "/factions": { + "get": { + "operationId": "get-factions", + "summary": "List factions", + "tags": [ + "Factions" + ], + "description": "Return a paginated list of all the factions in the game.", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + }, + "in": "query", + "name": "page", + "description": "What entry offset to request" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "example": 10 + }, + "in": "query", + "name": "limit", + "description": "How many entries to return per page" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched factions.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Faction" + } + }, + "meta": { + "$ref": "#/components/schemas/Meta" + } + }, + "required": [ + "data", + "meta" + ], + "description": "Successfully fetched factions." + } + } + } + } + } + } + }, + "/factions/{factionSymbol}": { + "get": { + "operationId": "get-faction", + "summary": "Faction details", + "tags": [ + "Factions" + ], + "description": "View the details of a faction.", + "parameters": [ + { + "schema": { + "type": "string", + "example": "COSMIC" + }, + "in": "path", + "name": "factionSymbol", + "required": true, + "description": "The faction symbol" + } + ], + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Faction" + } + }, + "required": [ + "data" + ] + } + } + } + } + } + } + }, + "/agents": { + "get": { + "operationId": "get-agents", + "summary": "List all public agent details.", + "tags": [ + "Agents" + ], + "description": "List all public agent details.", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + }, + "in": "query", + "name": "page", + "description": "What entry offset to request" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "example": 10 + }, + "in": "query", + "name": "limit", + "description": "How many entries to return per page" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched agents details.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicAgent" + } + }, + "meta": { + "$ref": "#/components/schemas/Meta" + } + }, + "required": [ + "data", + "meta" + ], + "description": "Successfully fetched agents details." + } + } + } + } + } + } + }, + "/agents/{agentSymbol}": { + "get": { + "operationId": "get-agent", + "summary": "Get public details for a specific agent.", + "tags": [ + "Agents" + ], + "description": "Get public details for a specific agent.", + "parameters": [ + { + "schema": { + "type": "string", + "example": "FEBA66" + }, + "in": "path", + "name": "agentSymbol", + "required": true, + "description": "The agent symbol" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/PublicAgent" + } + }, + "required": [ + "data" + ] + } + } + } + } + } + } + }, + "/market/supply-chain": { + "get": { + "operationId": "get-supply-chain", + "summary": "Describes trade relationships", + "tags": [ + "Data" + ], + "description": "Describes which import and exports map to each other.", + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully retrieved the supply chain information", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "exportToImportMap": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "required": [ + "exportToImportMap" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully retrieved the supply chain information" + } + } + } + } + } + } + }, + "/": { + "get": { + "operationId": "get-status", + "summary": "Server status", + "tags": [ + "Global" + ], + "description": "Return the status of the game server.\nThis also includes a few global elements, such as announcements, server reset dates and leaderboards.", + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Fetched status successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "The current status of the game server." + }, + "version": { + "type": "string", + "description": "The current version of the API." + }, + "resetDate": { + "type": "string", + "description": "The date when the game server was last reset." + }, + "description": { + "type": "string" + }, + "stats": { + "type": "object", + "properties": { + "accounts": { + "type": "integer", + "description": "Total number of accounts registered on the game server." + }, + "agents": { + "type": "integer", + "description": "Number of registered agents in the game." + }, + "ships": { + "type": "integer", + "description": "Total number of ships in the game." + }, + "systems": { + "type": "integer", + "description": "Total number of systems in the game." + }, + "waypoints": { + "type": "integer", + "description": "Total number of waypoints in the game." + } + }, + "required": [ + "agents", + "ships", + "systems", + "waypoints" + ] + }, + "health": { + "type": "object", + "properties": { + "lastMarketUpdate": { + "type": "string", + "description": "The date/time when the market was last updated." + } + } + }, + "leaderboards": { + "type": "object", + "properties": { + "mostCredits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "agentSymbol": { + "type": "string", + "description": "Symbol of the agent." + }, + "credits": { + "type": "integer", + "description": "Amount of credits.", + "format": "int64" + } + }, + "required": [ + "agentSymbol", + "credits" + ] + }, + "description": "Top agents with the most credits." + }, + "mostSubmittedCharts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "agentSymbol": { + "type": "string", + "description": "Symbol of the agent." + }, + "chartCount": { + "type": "integer", + "description": "Amount of charts done by the agent." + } + }, + "required": [ + "agentSymbol", + "chartCount" + ] + }, + "description": "Top agents with the most charted submitted." + } + }, + "required": [ + "mostCredits", + "mostSubmittedCharts" + ] + }, + "serverResets": { + "type": "object", + "properties": { + "next": { + "type": "string", + "description": "The date and time when the game server will reset." + }, + "frequency": { + "type": "string", + "description": "How often we intend to reset the game server." + } + }, + "required": [ + "next", + "frequency" + ] + }, + "announcements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "body": { + "type": "string" + } + }, + "required": [ + "title", + "body" + ] + } + }, + "links": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "name", + "url" + ] + } + } + }, + "required": [ + "status", + "version", + "resetDate", + "description", + "stats", + "health", + "leaderboards", + "serverResets", + "announcements", + "links" + ], + "description": "Fetched status successfully." + } + } + } + } + } + } + }, + "/error-codes": { + "get": { + "operationId": "get-error-codes", + "summary": "Error code list", + "tags": [ + "Global" + ], + "description": "Return a list of all possible error codes thrown by the game server.", + "security": [ + {} + ], + "responses": { + "200": { + "description": "Fetched error codes successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "errorCodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "number" + }, + "name": { + "type": "string" + } + }, + "required": [ + "code", + "name" + ] + } + } + }, + "required": [ + "errorCodes" + ], + "description": "Fetched error codes successfully." + } + } + } + } + } + } + }, + "/systems": { + "get": { + "operationId": "get-systems", + "summary": "List Systems", + "tags": [ + "Systems" + ], + "description": "Return a paginated list of all systems.", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + }, + "in": "query", + "name": "page", + "description": "What entry offset to request" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "example": 10 + }, + "in": "query", + "name": "limit", + "description": "How many entries to return per page" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully listed systems.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/System" + } + }, + "meta": { + "$ref": "#/components/schemas/Meta" + } + }, + "required": [ + "data", + "meta" + ], + "description": "Successfully listed systems." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}": { + "get": { + "operationId": "get-system", + "summary": "Get System", + "tags": [ + "Systems" + ], + "description": "Get the details of a system. Requires the system to have been visited or charted.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched the system.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/System" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched the system." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}/waypoints": { + "get": { + "operationId": "get-system-waypoints", + "summary": "List Waypoints in System", + "tags": [ + "Systems" + ], + "description": "Return a paginated list of all of the waypoints for a given system.\n\nIf a waypoint is uncharted, it will return the `Uncharted` trait instead of its actual traits.", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + }, + "in": "query", + "name": "page", + "description": "What entry offset to request" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "example": 10 + }, + "in": "query", + "name": "limit", + "description": "How many entries to return per page" + }, + { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/WaypointType" + } + ] + }, + "in": "query", + "name": "type", + "description": "Filter waypoints by type." + }, + { + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointTraitSymbol" + } + }, + { + "$ref": "#/components/schemas/WaypointTraitSymbol" + } + ] + }, + "in": "query", + "name": "traits", + "description": "Filter waypoints by one or more traits." + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully listed waypoints.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Waypoint" + } + }, + "meta": { + "$ref": "#/components/schemas/Meta" + } + }, + "required": [ + "data", + "meta" + ], + "description": "Successfully listed waypoints." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}/waypoints/{waypointSymbol}": { + "get": { + "operationId": "get-waypoint", + "summary": "Get Waypoint", + "tags": [ + "Systems" + ], + "description": "View the details of a waypoint.\n\nIf the waypoint is uncharted, it will return the 'Uncharted' trait instead of its actual traits.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true, + "description": "The system symbol" + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "waypointSymbol", + "required": true, + "description": "The waypoint symbol" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched waypoint details.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Waypoint" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched waypoint details." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}/waypoints/{waypointSymbol}/construction": { + "get": { + "operationId": "get-construction", + "summary": "Get Construction Site", + "tags": [ + "Systems" + ], + "description": "Get construction details for a waypoint. Requires a waypoint with a property of `isUnderConstruction` to be true.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true, + "description": "The system symbol" + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "waypointSymbol", + "required": true, + "description": "The waypoint symbol" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched construction site.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Construction" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched construction site." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}/waypoints/{waypointSymbol}/construction/supply": { + "post": { + "operationId": "supply-construction", + "summary": "Supply Construction Site", + "tags": [ + "Systems" + ], + "description": "Supply a construction site with the specified good. Requires a waypoint with a property of `isUnderConstruction` to be true.\n\nThe good must be in your ship's cargo. The good will be removed from your ship's cargo and added to the construction site's materials.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship supplying construction materials.", + "example": "DODO-1" + }, + "tradeSymbol": { + "allOf": [ + { + "$ref": "#/components/schemas/TradeSymbol" + } + ], + "description": "The symbol of the good to supply.", + "example": "IRON_ORE" + }, + "units": { + "type": "integer", + "minimum": 1, + "description": "Amount of units to supply.", + "example": 10 + } + }, + "required": [ + "shipSymbol", + "tradeSymbol", + "units" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true, + "description": "The system symbol" + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "waypointSymbol", + "required": true, + "description": "The waypoint symbol" + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully supplied construction site.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "construction": { + "$ref": "#/components/schemas/Construction" + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + } + }, + "required": [ + "construction", + "cargo" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully supplied construction site." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}/waypoints/{waypointSymbol}/market": { + "get": { + "operationId": "get-market", + "summary": "Get Market", + "tags": [ + "Systems" + ], + "description": "Retrieve imports, exports and exchange data from a marketplace. Requires a waypoint that has the `Marketplace` trait to use.\n\nSend a ship to the waypoint to access trade good prices and recent transactions. Refer to the [Market Overview page](https://docs.spacetraders.io/game-concepts/markets) to gain better a understanding of the market in the game.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true, + "description": "The system symbol" + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "waypointSymbol", + "required": true, + "description": "The waypoint symbol" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched the market.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Market" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched the market." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}/waypoints/{waypointSymbol}/jump-gate": { + "get": { + "operationId": "get-jump-gate", + "summary": "Get Jump Gate", + "tags": [ + "Systems" + ], + "description": "Get jump gate details for a waypoint. Requires a waypoint of type `JUMP_GATE` to use.\n\nWaypoints connected to this jump gate can be found by querying the waypoints in the system.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true, + "description": "The system symbol" + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "waypointSymbol", + "required": true, + "description": "The waypoint symbol" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Jump gate details retrieved successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/JumpGate" + } + }, + "required": [ + "data" + ], + "description": "Jump gate details retrieved successfully." + } + } + } + } + } + } + }, + "/systems/{systemSymbol}/waypoints/{waypointSymbol}/shipyard": { + "get": { + "operationId": "get-shipyard", + "summary": "Get Shipyard", + "tags": [ + "Systems" + ], + "description": "Get the shipyard for a waypoint. Requires a waypoint that has the `Shipyard` trait to use. Send a ship to the waypoint to access data on ships that are currently available for purchase and recent transactions.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "systemSymbol", + "required": true, + "description": "The system symbol" + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "waypointSymbol", + "required": true, + "description": "The waypoint symbol" + } + ], + "security": [ + {}, + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched the shipyard.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Shipyard" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched the shipyard." + } + } + } + } + } + } + }, + "/my/socket.io": { + "get": { + "operationId": "websocket-departure-events", + "summary": "Subscribe to events", + "tags": [ + "Data" + ], + "description": "Subscribe to departure events for a system.\n\n ## WebSocket Events\n\n The following events are available:\n\n - `systems.{systemSymbol}.departure`: A ship has departed from the system.\n\n ## Subscribe using a message with the following format:\n\n ```json\n {\n \"action\": \"subscribe\",\n \"systemSymbol\": \"{systemSymbol}\"\n }\n ```\n\n ## Unsubscribe using a message with the following format:\n\n ```json\n {\n \"action\": \"unsubscribe\",\n \"systemSymbol\": \"{systemSymbol}\"\n }\n ```", + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Default Response" + } + } + } + }, + "/my/contracts": { + "get": { + "operationId": "get-contracts", + "summary": "List Contracts", + "tags": [ + "Contracts" + ], + "description": "Return a paginated list of all your contracts.", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + }, + "in": "query", + "name": "page", + "description": "What entry offset to request" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "example": 10 + }, + "in": "query", + "name": "limit", + "description": "How many entries to return per page" + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully listed contracts.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Contract" + } + }, + "meta": { + "$ref": "#/components/schemas/Meta" + } + }, + "required": [ + "data", + "meta" + ], + "description": "Successfully listed contracts." + } + } + } + } + } + } + }, + "/my/contracts/{contractId}": { + "get": { + "operationId": "get-contract", + "summary": "Get Contract", + "tags": [ + "Contracts" + ], + "description": "Get the details of a specific contract.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "contractId", + "required": true, + "description": "The contract ID to accept." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched contract.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Contract" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched contract." + } + } + } + } + } + } + }, + "/my/contracts/{contractId}/accept": { + "post": { + "operationId": "accept-contract", + "summary": "Accept Contract", + "tags": [ + "Contracts" + ], + "description": "Accept a contract by ID. \n\nYou can only accept contracts that were offered to you, were not accepted yet, and whose deadlines has not passed yet.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "contractId", + "required": true, + "description": "The contract ID to accept." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully accepted contract.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "contract": { + "$ref": "#/components/schemas/Contract" + }, + "agent": { + "$ref": "#/components/schemas/Agent" + } + }, + "required": [ + "contract", + "agent" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully accepted contract." + } + } + } + } + } + } + }, + "/my/contracts/{contractId}/fulfill": { + "post": { + "operationId": "fulfill-contract", + "summary": "Fulfill Contract", + "tags": [ + "Contracts" + ], + "description": "Fulfill a contract. Can only be used on contracts that have all of their delivery terms fulfilled.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "contractId", + "required": true, + "description": "The ID of the contract to fulfill." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fulfilled a contract.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "contract": { + "$ref": "#/components/schemas/Contract" + }, + "agent": { + "$ref": "#/components/schemas/Agent" + } + }, + "required": [ + "contract", + "agent" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully fulfilled a contract." + } + } + } + } + } + } + }, + "/my/contracts/{contractId}/deliver": { + "post": { + "operationId": "deliver-contract", + "summary": "Deliver Cargo to Contract", + "tags": [ + "Contracts" + ], + "description": "Deliver cargo to a contract.\n\nIn order to use this API, a ship must be at the delivery location (denoted in the delivery terms as `destinationSymbol` of a contract) and must have a number of units of a good required by this contract in its cargo.\n\nCargo that was delivered will be removed from the ship's cargo.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "shipSymbol": { + "type": "string", + "description": "Symbol of a ship located in the destination to deliver a contract and that has a good to deliver in its cargo." + }, + "tradeSymbol": { + "type": "string", + "description": "The symbol of the good to deliver.", + "example": "IRON_ORE" + }, + "units": { + "type": "integer", + "minimum": 1, + "description": "Amount of units to deliver.", + "example": 10 + } + }, + "required": [ + "shipSymbol", + "tradeSymbol", + "units" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "contractId", + "required": true, + "description": "The ID of the contract." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully delivered cargo to contract.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "contract": { + "$ref": "#/components/schemas/Contract" + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + } + }, + "required": [ + "contract", + "cargo" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully delivered cargo to contract." + } + } + } + } + } + } + }, + "/my/factions": { + "get": { + "operationId": "get-my-factions", + "summary": "Get My Factions", + "tags": [ + "Factions" + ], + "description": "Retrieve factions with which the agent has reputation.", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + }, + "in": "query", + "name": "page", + "description": "What entry offset to request" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "example": 10 + }, + "in": "query", + "name": "limit", + "description": "How many entries to return per page" + } + ], + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "symbol": { + "type": "string" + }, + "reputation": { + "type": "integer" + } + }, + "required": [ + "symbol", + "reputation" + ] + } + }, + "meta": { + "$ref": "#/components/schemas/Meta" + } + }, + "required": [ + "data", + "meta" + ] + } + } + } + } + } + } + }, + "/my/agent": { + "get": { + "operationId": "get-my-agent", + "summary": "Get Agent", + "tags": [ + "Agents" + ], + "description": "Fetch your agent's details.", + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched agent details.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Agent" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched agent details." + } + } + } + } + } + } + }, + "/my/agent/events": { + "get": { + "operationId": "get-my-agent-events", + "summary": "Get Agent Events", + "tags": [ + "Agents" + ], + "description": "Get recent events for your agent.", + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentEvent" + } + } + }, + "required": [ + "data" + ] + } + } + } + } + } + } + }, + "/my/ships": { + "get": { + "operationId": "get-my-ships", + "summary": "List Ships", + "tags": [ + "Fleet" + ], + "description": "Return a paginated list of all of ships under your agent's ownership.", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + }, + "in": "query", + "name": "page", + "description": "What entry offset to request" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20, + "default": 10, + "example": 10 + }, + "in": "query", + "name": "limit", + "description": "How many entries to return per page" + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully listed ships.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Ship" + } + }, + "meta": { + "$ref": "#/components/schemas/Meta" + } + }, + "required": [ + "data", + "meta" + ], + "description": "Successfully listed ships." + } + } + } + } + } + }, + "post": { + "operationId": "purchase-ship", + "summary": "Purchase Ship", + "tags": [ + "Fleet" + ], + "description": "Purchase a ship from a Shipyard. In order to use this function, a ship under your agent's ownership must be in a waypoint that has the `Shipyard` trait, and the Shipyard must sell the type of the desired ship.\n\nShipyards typically offer ship types, which are predefined templates of ships that have dedicated roles. A template comes with a preset of an engine, a reactor, and a frame. It may also include a few modules and mounts.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "shipType": { + "$ref": "#/components/schemas/ShipType" + }, + "waypointSymbol": { + "type": "string", + "description": "The symbol of the waypoint you want to purchase the ship at." + } + }, + "required": [ + "shipType", + "waypointSymbol" + ] + } + } + }, + "required": true + }, + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Purchased ship successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "ship": { + "$ref": "#/components/schemas/Ship" + }, + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "transaction": { + "$ref": "#/components/schemas/ShipyardTransaction" + } + }, + "required": [ + "ship", + "agent", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Purchased ship successfully." + } + } + } + } + } + } + }, + "/my/account": { + "get": { + "operationId": "get-my-account", + "summary": "Get Account", + "tags": [ + "Accounts" + ], + "description": "Fetch your account details.", + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "account": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "email": { + "type": "string", + "nullable": true + }, + "token": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + "required": [ + "account" + ] + } + }, + "required": [ + "data" + ] + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}": { + "get": { + "operationId": "get-my-ship", + "summary": "Get Ship", + "tags": [ + "Fleet" + ], + "description": "Retrieve the details of a ship under your agent's ownership.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched ship.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Ship" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched ship." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/chart": { + "post": { + "operationId": "create-chart", + "summary": "Create Chart", + "tags": [ + "Fleet" + ], + "description": "Command a ship to chart the waypoint at its current location.\n\nMost waypoints in the universe are uncharted by default. These waypoints have their traits hidden until they have been charted by a ship.\n\nCharting a waypoint will record your agent as the one who created the chart, and all other agents would also be able to see the waypoint's traits. Charting a waypoint gives you a one time reward of credits based on the rarity of the waypoint's traits.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully charted waypoint.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "chart": { + "$ref": "#/components/schemas/Chart" + }, + "waypoint": { + "$ref": "#/components/schemas/Waypoint" + }, + "transaction": { + "$ref": "#/components/schemas/ChartTransaction" + }, + "agent": { + "$ref": "#/components/schemas/Agent" + } + }, + "required": [ + "chart", + "waypoint", + "transaction", + "agent" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully charted waypoint." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/negotiate/contract": { + "post": { + "operationId": "negotiate-contract", + "summary": "Negotiate Contract", + "tags": [ + "Fleet", + "Contracts" + ], + "description": "Negotiate a new contract with the HQ.\n\nIn order to negotiate a new contract, an agent must not have ongoing or offered contracts over the allowed maximum amount. Currently the maximum contracts an agent can have at a time is 1.\n\nOnce a contract is negotiated, it is added to the list of contracts offered to the agent, which the agent can then accept. \n\nThe ship must be present at any waypoint with a faction present to negotiate a contract with that faction.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully negotiated a new contract.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "contract": { + "$ref": "#/components/schemas/Contract" + } + }, + "required": [ + "contract" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully negotiated a new contract.", + "title": "Negotiate Contract 201 Response" + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/cooldown": { + "get": { + "operationId": "get-ship-cooldown", + "summary": "Get Ship Cooldown", + "tags": [ + "Fleet" + ], + "description": "Retrieve the details of your ship's reactor cooldown. Some actions such as activating your jump drive, scanning, or extracting resources taxes your reactor and results in a cooldown.\n\nYour ship cannot perform additional actions until your cooldown has expired. The duration of your cooldown is relative to the power consumption of the related modules or mounts for the action taken.\n\nResponse returns a 204 status code (no-content) when the ship has no cooldown.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched ship's cooldown.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/Cooldown" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched ship's cooldown." + } + } + } + }, + "204": { + "description": "No cooldown.", + "content": { + "application/json": { + "schema": { + "description": "No cooldown." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/dock": { + "post": { + "operationId": "dock-ship", + "summary": "Dock Ship", + "tags": [ + "Fleet" + ], + "description": "Attempt to dock your ship at its current location. Docking will only succeed if your ship is capable of docking at the time of the request.\n\nDocked ships can access elements in their current location, such as the market or a shipyard, but cannot do actions that require the ship to be above surface such as navigating or extracting.\n\nThe endpoint is idempotent - successive calls will succeed even if the ship is already docked.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "The ship has successfully docked at its current location.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "nav": { + "$ref": "#/components/schemas/ShipNav" + } + }, + "required": [ + "nav" + ] + } + }, + "required": [ + "data" + ], + "title": "Dock Ship 200 Response", + "description": "The ship has successfully docked at its current location." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/extract": { + "post": { + "operationId": "extract-resources", + "summary": "Extract Resources", + "tags": [ + "Fleet" + ], + "description": "Extract resources from a waypoint that can be extracted, such as asteroid fields, into your ship. Send an optional survey as the payload to target specific yields.\n\nThe ship must be in orbit to be able to extract and must have mining equipments installed that can extract goods, such as the `Gas Siphon` mount for gas-based goods or `Mining Laser` mount for ore-based goods.\n\nThe survey property is now deprecated. See the `extract/survey` endpoint for more details.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully extracted resources.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "extraction": { + "$ref": "#/components/schemas/Extraction" + }, + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "modifiers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointModifier" + } + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipConditionEvent" + } + } + }, + "required": [ + "extraction", + "cooldown", + "cargo", + "events" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully extracted resources." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/extract/survey": { + "post": { + "operationId": "extract-resources-with-survey", + "summary": "Extract Resources with Survey", + "tags": [ + "Fleet" + ], + "description": "Use a survey when extracting resources from a waypoint. This endpoint requires a survey as the payload, which allows your ship to extract specific yields.\n\nSend the full survey object as the payload which will be validated according to the signature. If the signature is invalid, or any properties of the survey are changed, the request will fail.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Survey" + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully extracted resources.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "extraction": { + "$ref": "#/components/schemas/Extraction" + }, + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "modifiers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WaypointModifier" + } + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipConditionEvent" + } + } + }, + "required": [ + "extraction", + "cooldown", + "cargo", + "events" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully extracted resources." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/jettison": { + "post": { + "operationId": "jettison", + "summary": "Jettison Cargo", + "tags": [ + "Fleet" + ], + "description": "Jettison cargo from your ship's cargo hold.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "units": { + "type": "integer", + "minimum": 1, + "description": "Amount of units to jettison of this good." + } + }, + "required": [ + "symbol", + "units" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Jettison successful.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + } + }, + "required": [ + "cargo" + ] + } + }, + "required": [ + "data" + ], + "description": "Jettison successful." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/jump": { + "post": { + "operationId": "jump-ship", + "summary": "Jump Ship", + "tags": [ + "Fleet" + ], + "description": "Jump your ship instantly to a target connected waypoint. The ship must be in orbit to execute a jump.\n\nA unit of antimatter is purchased and consumed from the market when jumping. The price of antimatter is determined by the market and is subject to change. A ship can only jump to connected waypoints", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "waypointSymbol": { + "type": "string", + "description": "The symbol of the waypoint to jump to. The destination must be a connected waypoint." + } + }, + "required": [ + "waypointSymbol" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Jump successful.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "nav": { + "$ref": "#/components/schemas/ShipNav" + }, + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "transaction": { + "$ref": "#/components/schemas/MarketTransaction" + }, + "agent": { + "$ref": "#/components/schemas/Agent" + } + }, + "required": [ + "nav", + "cooldown", + "transaction", + "agent" + ] + } + }, + "required": [ + "data" + ], + "description": "Jump successful." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/scan/systems": { + "post": { + "operationId": "create-ship-system-scan", + "summary": "Scan Systems", + "tags": [ + "Fleet" + ], + "description": "Scan for nearby systems, retrieving information on the systems' distance from the ship and their waypoints. Requires a ship to have the `Sensor Array` mount installed to use.\n\nThe ship will enter a cooldown after using this function, during which it cannot execute certain actions.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully scanned for nearby systems.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "systems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScannedSystem" + }, + "description": "List of scanned systems." + } + }, + "required": [ + "cooldown", + "systems" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully scanned for nearby systems." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/scan/waypoints": { + "post": { + "operationId": "create-ship-waypoint-scan", + "summary": "Scan Waypoints", + "tags": [ + "Fleet" + ], + "description": "Scan for nearby waypoints, retrieving detailed information on each waypoint in range. Scanning uncharted waypoints will allow you to ignore their uncharted state and will list the waypoints' traits.\n\nRequires a ship to have the `Sensor Array` mount installed to use.\n\nThe ship will enter a cooldown after using this function, during which it cannot execute certain actions.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully scanned for nearby waypoints.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "waypoints": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScannedWaypoint" + }, + "description": "List of scanned waypoints." + } + }, + "required": [ + "cooldown", + "waypoints" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully scanned for nearby waypoints." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/scan/ships": { + "post": { + "operationId": "create-ship-ship-scan", + "summary": "Scan Ships", + "tags": [ + "Fleet" + ], + "description": "Scan for nearby ships, retrieving information for all ships in range.\n\nRequires a ship to have the `Sensor Array` mount installed to use.\n\nThe ship will enter a cooldown after using this function, during which it cannot execute certain actions.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully scanned for nearby ships.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "ships": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScannedShip" + }, + "description": "List of scanned ships." + } + }, + "required": [ + "cooldown", + "ships" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully scanned for nearby ships." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/scrap": { + "post": { + "operationId": "scrap-ship", + "summary": "Scrap Ship", + "tags": [ + "Fleet" + ], + "description": "Scrap a ship, removing it from the game and receiving a portion of the ship's value back in credits. The ship must be docked in a waypoint that has the `Shipyard` trait to be scrapped.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Ship scrapped successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "transaction": { + "$ref": "#/components/schemas/ScrapTransaction" + } + }, + "required": [ + "agent", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Ship scrapped successfully." + } + } + } + } + } + }, + "get": { + "operationId": "get-scrap-ship", + "summary": "Get Scrap Ship", + "tags": [ + "Fleet" + ], + "description": "Get the value of scrapping a ship. Requires the ship to be docked at a waypoint that has the `Shipyard` trait.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully retrieved the amount of value that will be returned when scrapping a ship.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "transaction": { + "$ref": "#/components/schemas/ScrapTransaction" + } + }, + "required": [ + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully retrieved the amount of value that will be returned when scrapping a ship." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/navigate": { + "post": { + "operationId": "navigate-ship", + "summary": "Navigate Ship", + "tags": [ + "Fleet" + ], + "description": "Navigate to a target destination. The ship must be in orbit to use this function. The destination waypoint must be within the same system as the ship's current location. Navigating will consume the necessary fuel from the ship's manifest based on the distance to the target waypoint.\n\nThe returned response will detail the route information including the expected time of arrival. Most ship actions are unavailable until the ship has arrived at it's destination.\n\nTo travel between systems, see the ship's Warp or Jump actions.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "waypointSymbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the waypoint to navigate/warp to." + } + }, + "required": [ + "waypointSymbol" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "The successful transit information including the route details and changes to ship fuel. The route includes the expected time of arrival.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "nav": { + "$ref": "#/components/schemas/ShipNav" + }, + "fuel": { + "$ref": "#/components/schemas/ShipFuel" + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipConditionEvent" + } + } + }, + "required": [ + "nav", + "fuel", + "events" + ] + } + }, + "required": [ + "data" + ], + "description": "The successful transit information including the route details and changes to ship fuel. The route includes the expected time of arrival." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/warp": { + "post": { + "operationId": "warp-ship", + "summary": "Warp Ship", + "tags": [ + "Fleet" + ], + "description": "Warp your ship to a target destination in another system. The ship must be in orbit to use this function and must have the `Warp Drive` module installed. Warping will consume the necessary fuel from the ship's manifest.\n\nThe returned response will detail the route information including the expected time of arrival. Most ship actions are unavailable until the ship has arrived at its destination.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "waypointSymbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the waypoint to navigate/warp to." + } + }, + "required": [ + "waypointSymbol" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "The successful transit information including the route details and changes to ship fuel. The route includes the expected time of arrival.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "nav": { + "$ref": "#/components/schemas/ShipNav" + }, + "fuel": { + "$ref": "#/components/schemas/ShipFuel" + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipConditionEvent" + } + } + }, + "required": [ + "nav", + "fuel", + "events" + ] + } + }, + "required": [ + "data" + ], + "description": "The successful transit information including the route details and changes to ship fuel. The route includes the expected time of arrival." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/orbit": { + "post": { + "operationId": "orbit-ship", + "summary": "Orbit Ship", + "tags": [ + "Fleet" + ], + "description": "Attempt to move your ship into orbit at its current location. The request will only succeed if your ship is capable of moving into orbit at the time of the request.\n\nOrbiting ships are able to do actions that require the ship to be above surface such as navigating or extracting, but cannot access elements in their current waypoint, such as the market or a shipyard.\n\nThe endpoint is idempotent - successive calls will succeed even if the ship is already in orbit.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "The ship has successfully moved into orbit at its current location.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "nav": { + "$ref": "#/components/schemas/ShipNav" + } + }, + "required": [ + "nav" + ] + } + }, + "required": [ + "data" + ], + "title": "Orbit Ship 200 Response", + "description": "The ship has successfully moved into orbit at its current location." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/purchase": { + "post": { + "operationId": "purchase-cargo", + "summary": "Purchase Cargo", + "tags": [ + "Fleet" + ], + "description": "Purchase cargo from a market.\n\nThe ship must be docked in a waypoint that has `Marketplace` trait, and the market must be selling a good to be able to purchase it.\n\nThe maximum amount of units of a good that can be purchased in each transaction are denoted by the `tradeVolume` value of the good, which can be viewed by using the Get Market action.\n\nPurchased goods are added to the ship's cargo hold.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "units": { + "type": "integer", + "minimum": 1, + "description": "The number of units of the good to purchase." + } + }, + "required": [ + "symbol", + "units" + ], + "title": "Purchase Cargo Request" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Purchased goods successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "transaction": { + "$ref": "#/components/schemas/MarketTransaction" + }, + "agent": { + "$ref": "#/components/schemas/Agent" + } + }, + "required": [ + "cargo", + "transaction", + "agent" + ] + } + }, + "required": [ + "data" + ], + "title": "Purchase Cargo 201 Response", + "description": "Purchased goods successfully." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/refine": { + "post": { + "operationId": "ship-refine", + "summary": "Ship Refine", + "tags": [ + "Fleet" + ], + "description": "Attempt to refine the raw materials on your ship. The request will only succeed if your ship is capable of refining at the time of the request. In order to be able to refine, a ship must have goods that can be refined and have installed a `Refinery` module that can refine it.\n\nWhen refining, 100 basic goods will be converted into 10 processed goods.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "produce": { + "type": "string", + "enum": [ + "IRON", + "COPPER", + "SILVER", + "GOLD", + "ALUMINUM", + "PLATINUM", + "URANITE", + "MERITIUM", + "FUEL" + ], + "description": "The type of good to produce out of the refining process." + } + }, + "required": [ + "produce" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "The ship has successfully refined goods.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "produced": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tradeSymbol": { + "description": "Symbol of the good.", + "allOf": [ + { + "$ref": "#/components/schemas/TradeSymbol" + } + ] + }, + "units": { + "type": "integer", + "description": "Amount of units of the good." + } + }, + "required": [ + "tradeSymbol", + "units" + ] + }, + "description": "Goods that were produced by this refining process." + }, + "consumed": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tradeSymbol": { + "description": "Symbol of the good.", + "allOf": [ + { + "$ref": "#/components/schemas/TradeSymbol" + } + ] + }, + "units": { + "type": "integer", + "description": "Amount of units of the good." + } + }, + "required": [ + "tradeSymbol", + "units" + ] + }, + "description": "Goods that were consumed during this refining process." + } + }, + "required": [ + "cargo", + "cooldown", + "produced", + "consumed" + ] + } + }, + "required": [ + "data" + ], + "title": "Ship Refine 201 Response", + "description": "The ship has successfully refined goods." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/refuel": { + "post": { + "operationId": "refuel-ship", + "summary": "Refuel Ship", + "tags": [ + "Fleet" + ], + "description": "Refuel your ship by buying fuel from the local market.\n\nRequires the ship to be docked in a waypoint that has the `Marketplace` trait, and the market must be selling fuel in order to refuel.\n\nEach fuel bought from the market replenishes 100 units in your ship's fuel.\n\nShips will always be refuel to their frame's maximum fuel capacity when using this action.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "units": { + "type": "integer", + "minimum": 1, + "description": "The amount of fuel to fill in the ship's tanks. When not specified, the ship will be refueled to its maximum fuel capacity. If the amount specified is greater than the ship's remaining capacity, the ship will only be refueled to its maximum fuel capacity. The amount specified is not in market units but in ship fuel units.", + "example": 100 + }, + "fromCargo": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Wether to use the FUEL thats in your cargo or not.", + "example": false + } + } + } + }, + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Refueled successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "fuel": { + "$ref": "#/components/schemas/ShipFuel" + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "transaction": { + "$ref": "#/components/schemas/MarketTransaction" + } + }, + "required": [ + "agent", + "fuel", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Refueled successfully." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/repair": { + "post": { + "operationId": "repair-ship", + "summary": "Repair Ship", + "tags": [ + "Fleet" + ], + "description": "Repair a ship, restoring the ship to maximum condition. The ship must be docked at a waypoint that has the `Shipyard` trait in order to use this function. To preview the cost of repairing the ship, use the Get action.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Ship repaired successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "ship": { + "$ref": "#/components/schemas/Ship" + }, + "transaction": { + "$ref": "#/components/schemas/RepairTransaction" + } + }, + "required": [ + "agent", + "ship", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Ship repaired successfully." + } + } + } + } + } + }, + "get": { + "operationId": "get-repair-ship", + "summary": "Get Repair Ship", + "tags": [ + "Fleet" + ], + "description": "Get the cost of repairing a ship. Requires the ship to be docked at a waypoint that has the `Shipyard` trait.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully retrieved the cost of repairing a ship.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "transaction": { + "$ref": "#/components/schemas/RepairTransaction" + } + }, + "required": [ + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully retrieved the cost of repairing a ship." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/sell": { + "post": { + "operationId": "sell-cargo", + "summary": "Sell Cargo", + "tags": [ + "Fleet" + ], + "description": "Sell cargo in your ship to a market that trades this cargo. The ship must be docked in a waypoint that has the `Marketplace` trait in order to use this function.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "units": { + "type": "integer", + "minimum": 1, + "description": "Amounts of units to sell of the selected good.", + "example": 100 + } + }, + "required": [ + "symbol", + "units" + ], + "title": "SellCargoRequest" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Cargo was successfully sold.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "transaction": { + "$ref": "#/components/schemas/MarketTransaction" + }, + "agent": { + "$ref": "#/components/schemas/Agent" + } + }, + "required": [ + "cargo", + "transaction", + "agent" + ] + } + }, + "required": [ + "data" + ], + "title": "Sell Cargo 201 Response", + "description": "Cargo was successfully sold." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/siphon": { + "post": { + "operationId": "siphon-resources", + "summary": "Siphon Resources", + "tags": [ + "Fleet" + ], + "description": "Siphon gases or other resources from gas giants.\n\nThe ship must be in orbit to be able to siphon and must have siphon mounts and a gas processor installed.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Siphon successful.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "siphon": { + "$ref": "#/components/schemas/Siphon" + }, + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipConditionEvent" + } + } + }, + "required": [ + "siphon", + "cooldown", + "cargo", + "events" + ] + } + }, + "required": [ + "data" + ], + "description": "Siphon successful." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/survey": { + "post": { + "operationId": "create-survey", + "summary": "Create Survey", + "tags": [ + "Fleet" + ], + "description": "Create surveys on a waypoint that can be extracted such as asteroid fields. A survey focuses on specific types of deposits from the extracted location. When ships extract using this survey, they are guaranteed to procure a high amount of one of the goods in the survey.\n\nIn order to use a survey, send the entire survey details in the body of the extract request.\n\nEach survey may have multiple deposits, and if a symbol shows up more than once, that indicates a higher chance of extracting that resource.\n\nYour ship will enter a cooldown after surveying in which it is unable to perform certain actions. Surveys will eventually expire after a period of time or will be exhausted after being extracted several times based on the survey's size. Multiple ships can use the same survey for extraction.\n\nA ship must have the `Surveyor` mount installed in order to use this function.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Surveys has been created.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cooldown": { + "$ref": "#/components/schemas/Cooldown" + }, + "surveys": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Survey" + }, + "description": "Surveys created by this action." + } + }, + "required": [ + "cooldown", + "surveys" + ] + } + }, + "required": [ + "data" + ], + "description": "Surveys has been created." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/transfer": { + "post": { + "operationId": "transfer-cargo", + "summary": "Transfer Cargo", + "tags": [ + "Fleet" + ], + "description": "Transfer cargo between ships.\n\nThe receiving ship must be in the same waypoint as the transferring ship, and it must able to hold the additional cargo after the transfer is complete. Both ships also must be in the same state, either both are docked or both are orbiting.\n\nThe response body's cargo shows the cargo of the transferring ship after the transfer is complete.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tradeSymbol": { + "$ref": "#/components/schemas/TradeSymbol" + }, + "units": { + "type": "integer", + "minimum": 1, + "description": "Amount of units to transfer." + }, + "shipSymbol": { + "type": "string", + "description": "The symbol of the ship to transfer to." + } + }, + "required": [ + "tradeSymbol", + "units", + "shipSymbol" + ], + "title": "Transfer Cargo Request" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Cargo transferred successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "targetCargo": { + "$ref": "#/components/schemas/ShipCargo" + } + }, + "required": [ + "cargo", + "targetCargo" + ] + } + }, + "required": [ + "data" + ], + "title": "Transfer Cargo 200 Response", + "description": "Cargo transferred successfully." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/cargo": { + "get": { + "operationId": "get-my-ship-cargo", + "summary": "Get Ship Cargo", + "tags": [ + "Fleet" + ], + "description": "Retrieve the cargo of a ship under your agent's ownership.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully fetched ship's cargo.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ShipCargo" + } + }, + "required": [ + "data" + ], + "description": "Successfully fetched ship's cargo." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/modules": { + "get": { + "operationId": "get-ship-modules", + "summary": "Get Ship Modules", + "tags": [ + "Fleet" + ], + "description": "Get the modules installed on a ship.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully retrieved ship modules.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipModule" + } + } + }, + "required": [ + "data" + ], + "description": "Successfully retrieved ship modules." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/modules/install": { + "post": { + "operationId": "install-ship-module", + "summary": "Install Ship Module", + "tags": [ + "Fleet" + ], + "description": "Install a module on a ship. The module must be in your cargo.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the module to install." + } + }, + "required": [ + "symbol" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully installed the module on the ship.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipModule" + } + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "transaction": { + "$ref": "#/components/schemas/ShipModificationTransaction" + } + }, + "required": [ + "agent", + "modules", + "cargo", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully installed the module on the ship." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/modules/remove": { + "post": { + "operationId": "remove-ship-module", + "summary": "Remove Ship Module", + "tags": [ + "Fleet" + ], + "description": "Remove a module from a ship. The module will be placed in cargo.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the module to remove." + } + }, + "required": [ + "symbol" + ] + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully removed the module from the ship.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipModule" + } + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "transaction": { + "$ref": "#/components/schemas/ShipModificationTransaction" + } + }, + "required": [ + "agent", + "modules", + "cargo", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully removed the module from the ship." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/mounts": { + "get": { + "operationId": "get-mounts", + "summary": "Get Mounts", + "tags": [ + "Fleet" + ], + "description": "Get the mounts installed on a ship.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Successfully retrieved ship mounts.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipMount" + } + } + }, + "required": [ + "data" + ], + "title": "Get Mounts 200 Response", + "description": "Successfully retrieved ship mounts." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/mounts/install": { + "post": { + "operationId": "install-mount", + "summary": "Install Mount", + "tags": [ + "Fleet" + ], + "description": "Install a mount on a ship.\n\nIn order to install a mount, the ship must be docked and located in a waypoint that has a `Shipyard` trait. The ship also must have the mount to install in its cargo hold.\n\nAn installation fee will be deduced by the Shipyard for installing the mount on the ship.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the mount to install." + } + }, + "required": [ + "symbol" + ], + "title": "Install Mount Request" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully installed the mount.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "mounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipMount" + }, + "description": "List of installed mounts after the installation of the new mount." + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "transaction": { + "$ref": "#/components/schemas/ShipModificationTransaction" + } + }, + "required": [ + "agent", + "mounts", + "cargo", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "title": "Install Mount 201 Response", + "description": "Successfully installed the mount." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/mounts/remove": { + "post": { + "operationId": "remove-mount", + "summary": "Remove Mount", + "tags": [ + "Fleet" + ], + "description": "Remove a mount from a ship.\n\nThe ship must be docked in a waypoint that has the `Shipyard` trait, and must have the desired mount that it wish to remove installed.\n\nA removal fee will be deduced from the agent by the Shipyard.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "minLength": 1, + "description": "The symbol of the mount to remove." + } + }, + "required": [ + "symbol" + ], + "title": "Remove Mount Request" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully removed the mount.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "mounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipMount" + }, + "description": "List of installed mounts after the removal of the selected mount." + }, + "cargo": { + "$ref": "#/components/schemas/ShipCargo" + }, + "transaction": { + "$ref": "#/components/schemas/ShipModificationTransaction" + } + }, + "required": [ + "agent", + "mounts", + "cargo", + "transaction" + ] + } + }, + "required": [ + "data" + ], + "title": "Remove Mount 201 Response", + "description": "Successfully removed the mount." + } + } + } + } + } + } + }, + "/my/ships/{shipSymbol}/nav": { + "get": { + "operationId": "get-ship-nav", + "summary": "Get Ship Nav", + "tags": [ + "Fleet" + ], + "description": "Get the current nav status of a ship.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "The current nav status of the ship.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ShipNav" + } + }, + "required": [ + "data" + ], + "description": "The current nav status of the ship." + } + } + } + } + } + }, + "patch": { + "operationId": "patch-ship-nav", + "summary": "Patch Ship Nav", + "tags": [ + "Fleet" + ], + "description": "Update the nav configuration of a ship.\n\nCurrently only supports configuring the Flight Mode of the ship, which affects its speed and fuel consumption.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "flightMode": { + "$ref": "#/components/schemas/ShipNavFlightMode" + } + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "shipSymbol", + "required": true, + "description": "The symbol of the ship." + } + ], + "security": [ + { + "AgentToken": [] + } + ], + "responses": { + "200": { + "description": "Success response for updating the nav configuration of a ship.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "nav": { + "$ref": "#/components/schemas/ShipNav" + }, + "fuel": { + "$ref": "#/components/schemas/ShipFuel" + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipConditionEvent" + } + } + }, + "required": [ + "nav", + "fuel", + "events" + ] + } + }, + "required": [ + "data" + ], + "description": "Success response for updating the nav configuration of a ship." + } + } + } + } + } + } + }, + "/register": { + "post": { + "operationId": "register", + "summary": "Register New Agent", + "tags": [ + "Accounts" + ], + "description": "Creates a new agent and ties it to an account. \nThe agent symbol must consist of a 3-14 character string, and will be used to represent your agent. This symbol will prefix the symbol of every ship you own. Agent symbols will be cast to all uppercase characters.\n\nThis new agent will be tied to a starting faction of your choice, which determines your starting location, and will be granted an authorization token, a contract with their starting faction, a command ship that can fly across space with advanced capabilities, a small probe ship that can be used for reconnaissance, and 175,000 credits.\n\n> #### Keep your token safe and secure\n>\n> Keep careful track of where you store your token. You can generate a new token from our account dashboard, but if someone else gains access to your token they will be able to use it to make API requests on your behalf until the end of the reset.\n\nIf you are new to SpaceTraders, It is recommended to register with the COSMIC faction, a faction that is well connected to the rest of the universe. After registering, you should try our interactive [quickstart guide](https://docs.spacetraders.io/quickstart/new-game) which will walk you through a few basic API requests in just a few minutes.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "pattern": "^[a-zA-Z0-9-_]+$", + "minLength": 3, + "maxLength": 14, + "description": "Your desired agent symbol. This will be a unique name used to represent your agent, and will be the prefix for your ships.", + "example": "BADGER" + }, + "faction": { + "$ref": "#/components/schemas/FactionSymbol" + } + }, + "required": [ + "symbol", + "faction" + ] + } + } + }, + "required": true + }, + "security": [ + { + "AccountToken": [] + } + ], + "responses": { + "201": { + "description": "Successfully registered.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "A Bearer token for accessing secured API endpoints." + }, + "agent": { + "$ref": "#/components/schemas/Agent" + }, + "faction": { + "$ref": "#/components/schemas/Faction" + }, + "contract": { + "$ref": "#/components/schemas/Contract" + }, + "ships": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Ship" + } + } + }, + "required": [ + "token", + "agent", + "faction", + "contract", + "ships" + ] + } + }, + "required": [ + "data" + ], + "description": "Successfully registered." + } + } + } + } + } + } + } + }, + "servers": [ + { + "description": "v2", + "url": "https://api.spacetraders.io/v2" + } + ], + "security": [ + { + "AgentToken": [], + "AccountToken": [] + } + ], + "tags": [ + { + "description": "The accounts endpoints contain actions that relate to your spacetraders account.", + "name": "Accounts" + }, + { + "description": "The agents endpoints contain actions that relate to agents. Both your own and other agents.", + "name": "Agents" + }, + { + "description": "The contracts endpoints contain actions that relate to contracts. Contracts are agreements between agents and factions to perform certain services in exchange for a reward.", + "name": "Contracts" + }, + { + "description": "The factions endpoints contain actions that relate to factions. Factions are organizations or sentient beings that are actively competing for control of the universe.", + "name": "Factions" + }, + { + "description": "The fleet endpoints contain actions that relate to the fleet of ships owned by agents, and the actions those ships can perform.", + "name": "Fleet" + }, + { + "description": "The systems endpoints contain actions that relate to systems and waypoints. Systems are the individual stars in the universe, and waypoints are the locations within a system.", + "name": "Systems" + }, + { + "name": "Data", + "description": "The data endpoints contain actions that relate to the data that is stored in the game. This is all the data that doesn't change over the course of a reset (but might change between resets)." + }, + { + "description": "The global endpoints contain actions that relate to the game server itself. This includes announcements, leaderboards, and server resets. It also includes endpoints that don't fit into the other categories.", + "name": "Global" + } + ] +} \ No newline at end of file diff --git a/dev/spacetraders_sdk_dev.gleam b/dev/spacetraders_sdk_dev.gleam new file mode 100644 index 0000000..a597d7e --- /dev/null +++ b/dev/spacetraders_sdk_dev.gleam @@ -0,0 +1,17 @@ +import gleam/io +import oas/generator +import snag + +pub fn main() { + case + generator.build( + "dev/spacetraders.openapi.json", + ".", + "spacetraders_sdk", + [], + ) + { + Ok(_) -> Nil + Error(reason) -> io.print(snag.pretty_print(reason)) + } +} diff --git a/gleam.toml b/gleam.toml index ffabf45..98680ad 100644 --- a/gleam.toml +++ b/gleam.toml @@ -7,6 +7,16 @@ repository = { type = "forgejo", host = "7cs.dev", user = "lily", repo = "gleam- [dependencies] gleam_stdlib = ">= 0.44.0 and < 2.0.0" +snag = ">= 1.1.0 and < 2.0.0" +gleam_http = ">= 4.0.0 and < 5.0.0" +dot_env = ">= 1.2.0 and < 2.0.0" +stratus = ">= 0.9.7 and < 1.0.0" +gleam_httpc = ">= 4.2.0 and < 5.0.0" +gleam_otp = ">= 0.16.1 and < 1.0.0" +gleam_erlang = ">= 0.34.0 and < 1.0.0" +gleam_json = ">= 3.0.1 and < 4.0.0" +birl = ">= 1.8.0 and < 2.0.0" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" +oas_generator = ">= 1.3.3 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index 6430ad1..c9263cd 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,10 +2,44 @@ # You typically do not need to edit this file packages = [ + { name = "birl", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_regexp", "gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "2AC7BA26F998E3DFADDB657148BD5DDFE966958AD4D6D6957DD0D22E5B56C400" }, + { name = "dot_env", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "simplifile"], otp_app = "dot_env", source = "hex", outer_checksum = "F2B4815F1B5AF8F20A6EADBB393E715C4C35203EBD5BE8200F766EA83A0B18DE" }, + { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, + { name = "glam", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "4932A2D139AB0389E149396407F89654928D7B815E212BB02F13C66F53B1BBA1" }, + { name = "glance", version = "3.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "F3458292AFB4136CEE23142A8727C1270494E7A96978B9B9F9D2C1618583EF3D" }, + { name = "glance_printer", version = "3.0.0", build_tools = ["gleam"], requirements = ["glam", "glance", "gleam_stdlib"], otp_app = "glance_printer", source = "hex", outer_checksum = "8386C156B413B90828884577F89AADD4C131AA1C3DAFC826607BAEE40E636ACE" }, + { name = "gleam_crypto", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "917BC8B87DBD584830E3B389CBCAB140FFE7CB27866D27C6D0FB87A9ECF35602" }, + { name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" }, + { name = "gleam_http", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "0A62451FC85B98062E0907659D92E6A89F5F3C0FBE4AB8046C99936BF6F91DBC" }, + { name = "gleam_httpc", version = "4.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "5EE88F7AF296C09B578BAB4D5383F24AB3A9A7E9D4B4772D112A00405D1DC516" }, + { name = "gleam_json", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "5BA154440B22D9800955B1AB854282FA37B97F30F409D76B0824D0A60C934188" }, + { name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" }, + { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" }, { name = "gleam_stdlib", version = "0.60.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "621D600BB134BC239CB2537630899817B1A42E60A1D46C5E9F3FAE39F88C800B" }, + { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, { name = "gleeunit", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D33B7736CF0766ED3065F64A1EBB351E72B2E8DE39BAFC8ADA0E35E92A6A934F" }, + { name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" }, + { name = "gramps", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "59194B3980110B403EE6B75330DB82CDE05FC8138491C2EAEACBC7AAEF30B2E8" }, + { name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" }, + { name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" }, + { name = "oas", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "oas", source = "hex", outer_checksum = "01FF7BEDB4389084D96D11FB26902F14F75256FDAD812E3AE65C1E29B7BCA80E" }, + { name = "oas_generator", version = "1.3.3", build_tools = ["gleam"], requirements = ["glance", "glance_printer", "gleam_http", "gleam_json", "gleam_stdlib", "justin", "oas", "simplifile", "snag"], otp_app = "oas_generator", source = "hex", outer_checksum = "9E2AD137E6883D99F0D7C515B42D4CFBA60A8B00DD3ED62ADE0DED29B84D8328" }, + { name = "ranger", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_yielder"], otp_app = "ranger", source = "hex", outer_checksum = "C8988E8F8CDBD3E7F4D8F2E663EF76490390899C2B2885A6432E942495B3E854" }, + { name = "simplifile", version = "2.2.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C88E0EE2D509F6D86EB55161D631657675AA7684DAB83822F7E59EB93D9A60E3" }, + { name = "snag", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "7E9F06390040EB5FAB392CE642771484136F2EC103A92AE11BA898C8167E6E17" }, + { name = "stratus", version = "0.9.7", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gramps", "logging"], otp_app = "stratus", source = "hex", outer_checksum = "4B3344B24B0808AF5828EFE3BEB824D3298E0ECAC8069D85D14A6A33BAD85CBD" }, ] [requirements] +birl = { version = ">= 1.8.0 and < 2.0.0" } +dot_env = { version = ">= 1.2.0 and < 2.0.0" } +gleam_erlang = { version = ">= 0.34.0 and < 1.0.0" } +gleam_http = { version = ">= 4.0.0 and < 5.0.0" } +gleam_httpc = { version = ">= 4.2.0 and < 5.0.0" } +gleam_json = { version = ">= 3.0.1 and < 4.0.0" } +gleam_otp = { version = ">= 0.16.1 and < 1.0.0" } gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } +oas_generator = { version = ">= 1.3.3 and < 2.0.0" } +snag = { version = ">= 1.1.0 and < 2.0.0" } +stratus = { version = ">= 0.9.7 and < 1.0.0" } diff --git a/src/endpoints/accounts.gleam b/src/endpoints/accounts.gleam new file mode 100644 index 0000000..df58383 --- /dev/null +++ b/src/endpoints/accounts.gleam @@ -0,0 +1,82 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json +import models/account.{type Account} +import models/agent.{type Agent} +import models/agent_symbol.{type AgentSymbol} +import models/contract.{type Contract} +import models/faction.{type Faction} +import models/faction_symbol.{type FactionSymbol} +import models/ship.{type Ship} +import utils/auth.{type AccountToken, type AgentToken, AccountAuth, AgentAuth} +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse} + +pub type GetAccountResponse { + GetAccountResponse(account: Account) +} + +fn get_account_response_decoder() -> Decoder(GetAccountResponse) { + use account <- decode.field("account", account.decoder()) + decode.success(GetAccountResponse(account:)) +} + +pub fn get_account(token: AgentToken) -> ApiResponse(GetAccountResponse) { + let request = request_utils.get(AgentAuth(token), "/my/account") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_account_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type RegisterNewAgentResponse { + RegisterNewAgentResponse( + token: AgentToken, + agent: Agent, + faction: Faction, + contract: Contract, + ships: List(Ship), + ) +} + +fn register_new_agent_response_decoder() -> Decoder(RegisterNewAgentResponse) { + use token <- decode.field("token", auth.agent_token_decoder()) + use agent <- decode.field("agent", agent.decoder()) + use faction <- decode.field("faction", faction.decoder()) + use contract <- decode.field("contract", contract.decoder()) + use ships <- decode.field("ships", decode.list(ship.decoder())) + decode.success(RegisterNewAgentResponse( + token:, + agent:, + faction:, + contract:, + ships:, + )) +} + +pub fn register_new_agent( + token: AccountToken, + agent_symbol: AgentSymbol, + faction_symbol: FactionSymbol, +) -> ApiResponse(RegisterNewAgentResponse) { + let request = + request_utils.post_json( + AccountAuth(token), + "/register", + json.object([ + #("symbol", json.string(agent_symbol)), + #("faction", json.string(faction_symbol.to_string(faction_symbol))), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + register_new_agent_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} diff --git a/src/endpoints/agents.gleam b/src/endpoints/agents.gleam new file mode 100644 index 0000000..dab1b81 --- /dev/null +++ b/src/endpoints/agents.gleam @@ -0,0 +1,102 @@ +import gleam/dynamic/decode.{type Decoder} +import models/agent.{type Agent} +import models/agent_event.{type AgentEvent} +import models/public_agent.{type PublicAgent} +import utils/auth.{type AgentToken, AgentAuth} +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse, type PagedData} + +pub type ListPublicAgentsResponse { + ListPublicAgentsResponse(agents: List(PublicAgent)) +} + +fn list_public_agents_response_decoder() -> Decoder(ListPublicAgentsResponse) { + use agents <- decode.then(decode.list(public_agent.decoder())) + decode.success(ListPublicAgentsResponse(agents:)) +} + +pub fn list_public_agents( + token: AgentToken, + page: Int, + limit: Int, +) -> ApiResponse(PagedData(ListPublicAgentsResponse)) { + let request = request_utils.get_page(AgentAuth(token), "/agents", page, limit) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.paged_data_parser( + response.body, + list_public_agents_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetPublicAgentResponse { + GetPublicAgentResponse(agent: PublicAgent) +} + +fn get_public_agent_response_decoder() -> Decoder(GetPublicAgentResponse) { + use agent <- decode.then(public_agent.decoder()) + decode.success(GetPublicAgentResponse(agent:)) +} + +pub fn get_public_agent( + token: AgentToken, + agent_symbol: String, +) -> ApiResponse(GetPublicAgentResponse) { + let request = request_utils.get(AgentAuth(token), "/agents/" <> agent_symbol) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_public_agent_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetAgentResponse { + GetAgentResponse(agent: Agent) +} + +fn get_agent_response_decoder() -> decode.Decoder(GetAgentResponse) { + use agent <- decode.then(agent.decoder()) + decode.success(GetAgentResponse(agent:)) +} + +pub fn get_agent(token: AgentToken) -> ApiResponse(GetAgentResponse) { + let request = request_utils.get(AgentAuth(token), "/my/account") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_agent_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetAgentEventsResponse { + GetAgentEventsResponse(events: List(AgentEvent)) +} + +fn get_agent_events_response_decoder() -> Decoder(GetAgentEventsResponse) { + use events <- decode.then(decode.list(agent_event.decoder())) + decode.success(GetAgentEventsResponse(events:)) +} + +pub fn get_agent_events( + token: AgentToken, +) -> ApiResponse(GetAgentEventsResponse) { + let request = request_utils.get(AgentAuth(token), "/my/agent/events") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_agent_events_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} diff --git a/src/endpoints/contracts.gleam b/src/endpoints/contracts.gleam new file mode 100644 index 0000000..0c62866 --- /dev/null +++ b/src/endpoints/contracts.gleam @@ -0,0 +1,161 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json +import models/agent.{type Agent} +import models/contract.{type Contract} +import models/ship_cargo.{type ShipCargo} +import models/ship_symbol.{type ShipSymbol} +import models/trade_symbol.{type TradeSymbol} +import utils/auth.{type AgentToken, AgentAuth} +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse, type PagedData} + +pub type ListContractsResponse { + ListContractsResponse(contracts: List(Contract)) +} + +fn list_contracts_response_decoder() -> Decoder(ListContractsResponse) { + use contracts <- decode.then(decode.list(contract.decoder())) + decode.success(ListContractsResponse(contracts:)) +} + +pub fn list_contracts( + token: AgentToken, + page: Int, + limit: Int, +) -> ApiResponse(PagedData(ListContractsResponse)) { + let request = + request_utils.get_page(AgentAuth(token), "/my/contracts", page, limit) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.paged_data_parser( + response.body, + list_contracts_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetContractResponse { + GetContractResponse(contract: Contract) +} + +fn get_contract_response_decoder() -> Decoder(GetContractResponse) { + use contract <- decode.then(contract.decoder()) + decode.success(GetContractResponse(contract:)) +} + +pub fn get_contract( + token: AgentToken, + contract_id: String, +) -> ApiResponse(GetContractResponse) { + let request = + request_utils.get(AgentAuth(token), "/my/contracts/" <> contract_id) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_contract_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type AcceptContractResponse { + AcceptContractResponse(contract: Contract, agent: Agent) +} + +fn accept_contract_response_decoder() -> Decoder(AcceptContractResponse) { + use contract <- decode.field("contract", contract.decoder()) + use agent <- decode.field("agent", agent.decoder()) + decode.success(AcceptContractResponse(contract:, agent:)) +} + +pub fn accept_contract( + token: AgentToken, + contract_id: String, +) -> ApiResponse(AcceptContractResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/contracts/" <> contract_id <> "/accept", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + accept_contract_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type FulfillContractResponse { + FulfillContractResponse(contract: Contract, agent: Agent) +} + +fn fulfill_contract_response_decoder() -> Decoder(FulfillContractResponse) { + use contract <- decode.field("contract", contract.decoder()) + use agent <- decode.field("agent", agent.decoder()) + decode.success(FulfillContractResponse(contract:, agent:)) +} + +pub fn fulfill_contract( + token: AgentToken, + contract_id, +) -> ApiResponse(FulfillContractResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/contracts/" <> contract_id <> "/fulfill", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + fulfill_contract_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type DeliverContractCargoResponse { + DeliverContractCargoResponse(contract: Contract, cargo: ShipCargo) +} + +fn deliver_contract_cargo_response_decoder() -> Decoder( + DeliverContractCargoResponse, +) { + use contract <- decode.field("contract", contract.decoder()) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + decode.success(DeliverContractCargoResponse(contract:, cargo:)) +} + +pub fn deliver_contract_cargo( + token: AgentToken, + contract_id: String, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, + units: Int, +) -> ApiResponse(DeliverContractCargoResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/contracts/" <> contract_id <> "/deliver", + json.object([ + #("shipSymbol", json.string(ship_symbol)), + #("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))), + #("units", json.int(units)), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + deliver_contract_cargo_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} diff --git a/src/endpoints/data.gleam b/src/endpoints/data.gleam new file mode 100644 index 0000000..5d245a7 --- /dev/null +++ b/src/endpoints/data.gleam @@ -0,0 +1,63 @@ +import gleam/dict.{type Dict} +import gleam/dynamic/decode.{type Decoder} +import gleam/erlang/process.{type Subject} +import gleam/http/request +import gleam/option +import gleam/otp/actor +import stratus +import utils/auth.{type AgentToken, AgentAuth} +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse} + +pub type GetSupplyChainResponse { + GetSupplyChainResponse(export_to_import_map: Dict(String, String)) +} + +fn get_supply_chain_response_decoder() -> Decoder(GetSupplyChainResponse) { + use export_to_import_map <- decode.field( + "exportToImportMap", + decode.dict(decode.string, decode.string), + ) + decode.success(GetSupplyChainResponse(export_to_import_map:)) +} + +pub fn get_supply_chain( + token: AgentToken, +) -> ApiResponse(GetSupplyChainResponse) { + let request = request_utils.get(AgentAuth(token), "/market/supply-chain") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_supply_chain_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub fn get_departure_events( + token: AgentToken, + initial_state: state, + on_message: fn(state, stratus.Message(user)) -> + Result(state, process.ExitReason), + on_close: fn(state) -> Nil, +) -> Result(Subject(stratus.InternalMessage(user)), actor.StartError) { + stratus.websocket( + request: request_utils.get(AgentAuth(token), "/my/socket.io") + |> request.set_body(""), + init: fn() { #(initial_state, option.None) }, + loop: fn(msg, state, conn) { + case on_message(state, msg) { + Ok(state) -> actor.continue(state) + Error(reason) -> { + let _ = stratus.close(conn) + actor.Stop(reason) + } + } + }, + ) + |> stratus.on_close(on_close) + |> stratus.initialize +} diff --git a/src/endpoints/factions.gleam b/src/endpoints/factions.gleam new file mode 100644 index 0000000..6f51d92 --- /dev/null +++ b/src/endpoints/factions.gleam @@ -0,0 +1,99 @@ +import gleam/dynamic/decode.{type Decoder} +import models/faction.{type Faction} +import models/faction_symbol.{type FactionSymbol} +import utils/auth.{type AgentToken, AgentAuth} +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse, type PagedData} + +pub type ListFactionsResponse { + ListFactionsResponse(factions: List(Faction)) +} + +fn list_factions_response_decoder() -> Decoder(ListFactionsResponse) { + use factions <- decode.then(decode.list(faction.decoder())) + decode.success(ListFactionsResponse(factions:)) +} + +pub fn list_factions( + token: AgentToken, + page: Int, + limit: Int, +) -> ApiResponse(PagedData(ListFactionsResponse)) { + let request = + request_utils.get_page(AgentAuth(token), "/factions", page, limit) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.paged_data_parser( + response.body, + list_factions_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetFactionResponse { + GetFactionResponse(faction: Faction) +} + +fn get_faction_response_decoder() -> Decoder(GetFactionResponse) { + use faction <- decode.then(faction.decoder()) + decode.success(GetFactionResponse(faction:)) +} + +pub fn get_faction( + token: AgentToken, + symbol: FactionSymbol, +) -> ApiResponse(GetFactionResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/factions/" <> faction_symbol.to_string(symbol), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_faction_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type FactionReputation { + FactionReputation(symbol: FactionSymbol, reputation: Int) +} + +fn faction_reputation_decoder() { + use symbol <- decode.field("symbol", faction_symbol.decoder()) + use reputation <- decode.field("reputation", decode.int) + decode.success(FactionReputation(symbol:, reputation:)) +} + +pub type GetMyFactionsResponse { + GetMyFactionsResponse(faction_reputations: List(FactionReputation)) +} + +fn get_my_factions_response_decoder() -> Decoder(GetMyFactionsResponse) { + use faction_reputations <- decode.then( + decode.list(faction_reputation_decoder()), + ) + decode.success(GetMyFactionsResponse(faction_reputations:)) +} + +pub fn get_my_factions( + token: AgentToken, + page: Int, + limit: Int, +) -> ApiResponse(PagedData(GetMyFactionsResponse)) { + let request = + request_utils.get_page(AgentAuth(token), "/my/factions", page, limit) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.paged_data_parser( + response.body, + get_my_factions_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} diff --git a/src/endpoints/fleet.gleam b/src/endpoints/fleet.gleam new file mode 100644 index 0000000..0a48033 --- /dev/null +++ b/src/endpoints/fleet.gleam @@ -0,0 +1,1327 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json +import gleam/option.{type Option} +import models/agent.{type Agent} +import models/chart.{type Chart} +import models/chart_transaction.{type ChartTransaction} +import models/contract.{type Contract} +import models/cooldown.{type Cooldown} +import models/extraction.{type Extraction} +import models/market_transaction.{type MarketTransaction} +import models/module_symbol.{type ModuleSymbol} +import models/mount_symbol.{type MountSymbol} +import models/refinement_produce.{type RefinementProduce} +import models/refinement_yield.{type RefinementYield} +import models/repair_transaction.{type RepairTransaction} +import models/scanned_ship.{type ScannedShip} +import models/scanned_system.{type ScannedSystem} +import models/scanned_waypoint.{type ScannedWaypoint} +import models/scrap_transaction.{type ScrapTransaction} +import models/ship.{type Ship} +import models/ship_cargo.{type ShipCargo} +import models/ship_condition_event.{type ShipConditionEvent} +import models/ship_fuel.{type ShipFuel} +import models/ship_modification_transaction.{type ShipModificationTransaction} +import models/ship_module.{type ShipModule} +import models/ship_mount.{type ShipMount} +import models/ship_nav.{type ShipNav} +import models/ship_nav_flight_mode.{type ShipNavFlightMode} +import models/ship_symbol.{type ShipSymbol} +import models/ship_type.{type ShipType} +import models/shipyard_transaction.{type ShipyardTransaction} +import models/siphon.{type Siphon} +import models/survey.{type Survey} +import models/trade_symbol.{type TradeSymbol} +import models/waypoint.{type Waypoint} +import models/waypoint_modifier.{type WaypointModifier} +import models/waypoint_symbol.{type WaypointSymbol} +import utils/auth.{type AgentToken, AgentAuth} +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse, type PagedData} + +pub type ListShipsResponse { + ListShipsResponse(ships: List(Ship)) +} + +pub fn list_ships_decoder() -> Decoder(ListShipsResponse) { + use ships <- decode.then(decode.list(ship.decoder())) + decode.success(ListShipsResponse(ships:)) +} + +pub fn list_ships( + token: AgentToken, + page: Int, + limit: Int, +) -> ApiResponse(PagedData(ListShipsResponse)) { + let request = + request_utils.get_page(AgentAuth(token), "/my/ships", page, limit) + use response <- request_utils.try_send(request) + case response.status { + 200 -> response_utils.paged_data_parser(response.body, list_ships_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type PurchaseShipResponse { + PurchaseShipResponse( + ship: Ship, + agent: Agent, + transaction: ShipyardTransaction, + ) +} + +pub fn purchase_ship_decoder() -> Decoder(PurchaseShipResponse) { + use ship <- decode.field("ship", ship.decoder()) + use agent <- decode.field("agent", agent.decoder()) + use transaction <- decode.field("transaction", shipyard_transaction.decoder()) + decode.success(PurchaseShipResponse(ship:, agent:, transaction:)) +} + +pub fn purchase_ship( + token: AgentToken, + ship_type: ShipType, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(PurchaseShipResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships", + json.object([ + #("shipType", json.string(ship_type.to_string(ship_type))), + #("waypointSymbol", json.string(waypoint_symbol)), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> response_utils.data_parser(response.body, purchase_ship_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetShipResponse { + GetShipResponse(ship: Ship) +} + +pub fn get_ship_decoder() -> Decoder(GetShipResponse) { + use ship <- decode.then(ship.decoder()) + decode.success(GetShipResponse(ship:)) +} + +pub fn get_ship( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetShipResponse) { + let request = request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol) + use response <- request_utils.try_send(request) + case response.status { + 200 -> response_utils.data_parser(response.body, get_ship_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type CreateChartResponse { + CreateChartResponse( + chart: Chart, + waypoint: Waypoint, + transaction: ChartTransaction, + agent: Agent, + ) +} + +pub fn create_chart_response_decoder() -> Decoder(CreateChartResponse) { + use chart <- decode.field("chart", chart.decoder()) + use waypoint <- decode.field("waypoint", waypoint.decoder()) + use transaction <- decode.field("transaction", chart_transaction.decoder()) + use agent <- decode.field("agent", agent.decoder()) + decode.success(CreateChartResponse(chart:, waypoint:, transaction:, agent:)) +} + +pub fn create_chart( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(CreateChartResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/chart", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser(response.body, create_chart_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type NegotiateContractResponse { + NegotiateContractResponse(contract: Contract) +} + +fn negotiate_contract_response_decoder() -> Decoder(NegotiateContractResponse) { + use contract <- decode.field("contract", contract.decoder()) + decode.success(NegotiateContractResponse(contract:)) +} + +pub fn negotiate_contract( + token: AgentToken, + ship_symbol: String, +) -> ApiResponse(NegotiateContractResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/negotiate/contract", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + negotiate_contract_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetShipCooldownResponse { + GetShipCooldownResponse(cooldown: Option(Cooldown)) +} + +fn get_ship_cooldown_response_decoder() -> Decoder(GetShipCooldownResponse) { + use cooldown <- decode.field("cooldown", cooldown.decoder()) + decode.success(GetShipCooldownResponse(cooldown: option.Some(cooldown))) +} + +pub fn get_ship_cooldown( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetShipCooldownResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/cooldown", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_ship_cooldown_response_decoder(), + ) + 204 -> Ok(GetShipCooldownResponse(option.None)) + _ -> response_utils.error_parser(response.body) + } +} + +pub type DockShipResponse { + DockShipResponse(nav: ShipNav) +} + +fn dock_ship_response_decoder() -> Decoder(DockShipResponse) { + use nav <- decode.field("nav", ship_nav.decoder()) + decode.success(DockShipResponse(nav:)) +} + +pub fn dock_ship( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(DockShipResponse) { + let request = + request_utils.post(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/dock") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, dock_ship_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type ExtractResourcesResponse { + ExtractResourcesResponse( + extraction: Extraction, + cooldown: Cooldown, + cargo: ShipCargo, + modifiers: List(WaypointModifier), + events: List(ShipConditionEvent), + ) +} + +fn extract_resources_response_decoder() -> Decoder(ExtractResourcesResponse) { + use extraction <- decode.field("extraction", extraction.decoder()) + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use modifiers <- decode.field( + "modifiers", + decode.list(waypoint_modifier.decoder()), + ) + use events <- decode.field( + "events", + decode.list(ship_condition_event.decoder()), + ) + decode.success(ExtractResourcesResponse( + extraction:, + cooldown:, + cargo:, + modifiers:, + events:, + )) +} + +pub fn extract_resources( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(ExtractResourcesResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/extract", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + extract_resources_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type ExtractResourcesWithSurveyResponse { + ExtractResourcesWithSurveyResponse( + extraction: Extraction, + cooldown: Cooldown, + cargo: ShipCargo, + modifiers: List(WaypointModifier), + events: List(ShipConditionEvent), + ) +} + +fn extract_resources_with_survey_response_decoder() -> Decoder( + ExtractResourcesWithSurveyResponse, +) { + use extraction <- decode.field("extraction", extraction.decoder()) + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use modifiers <- decode.field( + "modifiers", + decode.list(waypoint_modifier.decoder()), + ) + use events <- decode.field( + "events", + decode.list(ship_condition_event.decoder()), + ) + decode.success(ExtractResourcesWithSurveyResponse( + extraction:, + cooldown:, + cargo:, + modifiers:, + events:, + )) +} + +pub fn extract_resources_with_survey( + token: AgentToken, + ship_symbol: ShipSymbol, + survey: Survey, +) -> ApiResponse(ExtractResourcesWithSurveyResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/extract/survey", + survey.encode(survey), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + extract_resources_with_survey_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type JettisonCargoResponse { + JettisonCargoResponse(cargo: ShipCargo) +} + +fn jettison_cargo_response_decoder() -> Decoder(JettisonCargoResponse) { + use cargo <- decode.field("cargo", ship_cargo.decoder()) + decode.success(JettisonCargoResponse(cargo:)) +} + +pub fn jettison_cargo( + token: AgentToken, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, + units: Int, +) -> ApiResponse(JettisonCargoResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/jettison", + json.object([ + #("symbol", json.string(trade_symbol.to_string(trade_symbol))), + #("units", json.int(units)), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + jettison_cargo_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type JumpShipResponse { + JumpShipResponse( + nav: ShipNav, + cooldown: Cooldown, + transaction: MarketTransaction, + agent: Agent, + ) +} + +fn jump_ship_response_decoder() -> Decoder(JumpShipResponse) { + use nav <- decode.field("nav", ship_nav.decoder()) + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use transaction <- decode.field("transaction", market_transaction.decoder()) + use agent <- decode.field("agent", agent.decoder()) + decode.success(JumpShipResponse(nav:, cooldown:, transaction:, agent:)) +} + +pub fn jump_ship( + token: AgentToken, + ship_symbol: ShipSymbol, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(JumpShipResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/jump", + json.object([#("waypointSymbol", json.string(waypoint_symbol))]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, jump_ship_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type SystemScanResponse { + SystemScanResponse(cooldown: Cooldown, systems: List(ScannedSystem)) +} + +fn system_scan_response_decoder() -> Decoder(SystemScanResponse) { + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use systems <- decode.field("systems", decode.list(scanned_system.decoder())) + decode.success(SystemScanResponse(cooldown:, systems:)) +} + +pub fn system_scan( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(SystemScanResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/scan/systems", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser(response.body, system_scan_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type WaypointScanResponse { + WaypointScanResponse(cooldown: Cooldown, waypoints: List(ScannedWaypoint)) +} + +fn waypoint_scan_response_decoder() -> Decoder(WaypointScanResponse) { + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use waypoints <- decode.field( + "waypoints", + decode.list(scanned_waypoint.decoder()), + ) + decode.success(WaypointScanResponse(cooldown:, waypoints:)) +} + +pub fn waypoint_scan( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(WaypointScanResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/scan/waypoints", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + waypoint_scan_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type ShipScanResponse { + ShipScanResponse(cooldown: Cooldown, ships: List(ScannedShip)) +} + +fn ship_scan_response_decoder() -> Decoder(ShipScanResponse) { + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use ships <- decode.field("ships", decode.list(scanned_ship.decoder())) + decode.success(ShipScanResponse(cooldown:, ships:)) +} + +pub fn scan_ships( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(ShipScanResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/scan/ships", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser(response.body, ship_scan_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type ScrapShipResponse { + ScrapShipResponse(agent: Agent, transaction: ScrapTransaction) +} + +fn scrap_ship_response_decoder() -> Decoder(ScrapShipResponse) { + use agent <- decode.field("agent", agent.decoder()) + use transaction <- decode.field("transaction", scrap_transaction.decoder()) + decode.success(ScrapShipResponse(agent:, transaction:)) +} + +pub fn scrap_ship( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(ScrapShipResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/scrap", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, scrap_ship_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetScrapShipResponse { + GetScrapShipResponse(transaction: ScrapTransaction) +} + +fn get_scrap_ship_response_decoder() -> Decoder(GetScrapShipResponse) { + use transaction <- decode.field("transaction", scrap_transaction.decoder()) + decode.success(GetScrapShipResponse(transaction:)) +} + +pub fn get_scrap_ship( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetScrapShipResponse) { + let request = + request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/scrap") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_scrap_ship_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type NavigateShipResponse { + NavigateShipResponse( + nav: ShipNav, + fuel: ShipFuel, + events: List(ShipConditionEvent), + ) +} + +fn navigate_ship_response_decoder() -> Decoder(NavigateShipResponse) { + use nav <- decode.field("nav", ship_nav.decoder()) + use fuel <- decode.field("fuel", ship_fuel.decoder()) + use events <- decode.field( + "events", + decode.list(ship_condition_event.decoder()), + ) + decode.success(NavigateShipResponse(nav:, fuel:, events:)) +} + +pub fn navigate_ship( + token: AgentToken, + ship_symbol: ShipSymbol, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(NavigateShipResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/navigate", + json.object([#("waypointSymbol", json.string(waypoint_symbol))]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + navigate_ship_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type WarpShipResponse { + WarpShipResponse( + nav: ShipNav, + fuel: ShipFuel, + events: List(ShipConditionEvent), + ) +} + +fn warp_ship_response_decoder() -> Decoder(WarpShipResponse) { + use nav <- decode.field("nav", ship_nav.decoder()) + use fuel <- decode.field("fuel", ship_fuel.decoder()) + use events <- decode.field( + "events", + decode.list(ship_condition_event.decoder()), + ) + decode.success(WarpShipResponse(nav:, fuel:, events:)) +} + +pub fn warp_ship( + token: AgentToken, + ship_symbol: ShipSymbol, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(WarpShipResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/warp", + json.object([#("waypointSymbol", json.string(waypoint_symbol))]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, warp_ship_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type OrbitShipResponse { + OrbitShipResponse(nav: ShipNav) +} + +fn orbit_ship_response_decoder() -> Decoder(OrbitShipResponse) { + use nav <- decode.field("nav", ship_nav.decoder()) + decode.success(OrbitShipResponse(nav:)) +} + +pub fn orbit_ship( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(OrbitShipResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/orbit", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, orbit_ship_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type PurchaseCargoResponse { + PurchaseCargoResponse( + cargo: ShipCargo, + transaction: MarketTransaction, + agent: Agent, + ) +} + +fn purchase_cargo_response_decoder() -> Decoder(PurchaseCargoResponse) { + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use transaction <- decode.field("transaction", market_transaction.decoder()) + use agent <- decode.field("agent", agent.decoder()) + decode.success(PurchaseCargoResponse(cargo:, transaction:, agent:)) +} + +pub fn purchase_cargo( + token: AgentToken, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, +) -> ApiResponse(PurchaseCargoResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/purchase", + json.object([ + #("symbol", json.string(trade_symbol.to_string(trade_symbol))), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + purchase_cargo_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type ShipRefineResponse { + ShipRefineResponse( + cargo: ShipCargo, + cooldown: Cooldown, + produced: List(RefinementYield), + consumed: List(RefinementYield), + ) +} + +fn ship_refine_response_decoder() -> Decoder(ShipRefineResponse) { + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use produced <- decode.field( + "produced", + decode.list(refinement_yield.decoder()), + ) + use consumed <- decode.field( + "consumed", + decode.list(refinement_yield.decoder()), + ) + decode.success(ShipRefineResponse(cargo:, cooldown:, produced:, consumed:)) +} + +pub fn ship_refine( + token: AgentToken, + ship_symbol: ShipSymbol, + produce: RefinementProduce, +) -> ApiResponse(ShipRefineResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/refine", + json.object([ + #("produce", json.string(refinement_produce.to_string(produce))), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser(response.body, ship_refine_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type RefuelShipResponse { + RefuelShipResponse( + agent: Agent, + fuel: ShipFuel, + cargo: ShipCargo, + transaction: MarketTransaction, + ) +} + +pub fn refuel_ship_response_decoder() -> Decoder(RefuelShipResponse) { + use agent <- decode.field("agent", agent.decoder()) + use fuel <- decode.field("fuel", ship_fuel.decoder()) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use transaction <- decode.field("transaction", market_transaction.decoder()) + decode.success(RefuelShipResponse(agent:, fuel:, cargo:, transaction:)) +} + +pub fn refuel_ship( + token: AgentToken, + ship_symbol: ShipSymbol, + units: Option(Int), + from_cargo: Option(Bool), +) -> ApiResponse(RefuelShipResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/refuel", + json.object([ + #("units", json.nullable(units, json.int)), + #("fromCargo", json.nullable(from_cargo, json.bool)), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, refuel_ship_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type RepairShipResponse { + RepairShipResponse(agent: Agent, ship: Ship, transaction: RepairTransaction) +} + +pub fn repair_ship_response_decoder() -> Decoder(RepairShipResponse) { + use agent <- decode.field("agent", agent.decoder()) + use ship <- decode.field("ship", ship.decoder()) + use transaction <- decode.field("transaction", repair_transaction.decoder()) + decode.success(RepairShipResponse(agent:, ship:, transaction:)) +} + +pub fn repair_ship( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(RepairShipResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/repair", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, repair_ship_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetRepairShipResponse { + GetRepairShipResponse(transaction: RepairTransaction) +} + +pub fn get_repair_ship_response_decoder() -> Decoder(GetRepairShipResponse) { + use transaction <- decode.field("transaction", repair_transaction.decoder()) + decode.success(GetRepairShipResponse(transaction:)) +} + +pub fn get_repair_ship( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetRepairShipResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/repair", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_repair_ship_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type SellCargoResponse { + SellCargoResponse( + cargo: ShipCargo, + transaction: MarketTransaction, + agent: Agent, + ) +} + +pub fn sell_cargo_response_decoder() -> Decoder(SellCargoResponse) { + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use transaction <- decode.field("transaction", market_transaction.decoder()) + use agent <- decode.field("agent", agent.decoder()) + decode.success(SellCargoResponse(cargo:, transaction:, agent:)) +} + +pub fn sell_cargo( + token: AgentToken, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, + units: Int, +) -> ApiResponse(SellCargoResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/sell", + json.object([ + #("symbol", json.string(trade_symbol.to_string(trade_symbol))), + #("units", json.int(units)), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser(response.body, sell_cargo_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type SiphonResourcesResponse { + SiphonResourcesResponse( + siphon: Siphon, + cooldown: Cooldown, + cargo: ShipCargo, + events: List(ShipConditionEvent), + ) +} + +pub fn siphon_resources_response_decoder() -> Decoder(SiphonResourcesResponse) { + use siphon <- decode.field("siphon", siphon.decoder()) + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use events <- decode.field( + "events", + decode.list(ship_condition_event.decoder()), + ) + decode.success(SiphonResourcesResponse(siphon:, cooldown:, cargo:, events:)) +} + +pub fn siphon_resources( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(SiphonResourcesResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/siphon", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + siphon_resources_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type CreateSurveyResponse { + CreateSurveyResponse(cooldown: Cooldown, surveys: List(Survey)) +} + +pub fn create_survey_response_decoder() -> Decoder(CreateSurveyResponse) { + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use surveys <- decode.field("surveys", decode.list(survey.decoder())) + decode.success(CreateSurveyResponse(cooldown:, surveys:)) +} + +pub fn create_survey( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(CreateSurveyResponse) { + let request = + request_utils.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/survey", + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + create_survey_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type TransferCargoResponse { + TransferCargoResponse(cargo: ShipCargo, target_cargo: ShipCargo) +} + +pub fn transfer_cargo_response_decoder() -> Decoder(TransferCargoResponse) { + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use target_cargo <- decode.field("targetCargo", ship_cargo.decoder()) + decode.success(TransferCargoResponse(cargo:, target_cargo:)) +} + +pub fn transfer_cargo( + token: AgentToken, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, + units: Int, + target_ship_symbol: ShipSymbol, +) -> ApiResponse(TransferCargoResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/transfer", + json.object([ + #("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))), + #("units", json.int(units)), + #("shipSymbol", json.string(target_ship_symbol)), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + transfer_cargo_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetShipCargoResponse { + GetShipCargoResponse(cargo: ShipCargo) +} + +pub fn get_ship_cargo_response_decoder() -> Decoder(GetShipCargoResponse) { + use cargo <- decode.then(ship_cargo.decoder()) + decode.success(GetShipCargoResponse(cargo:)) +} + +pub fn get_my_ship_cargo( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetShipCargoResponse) { + let request = + request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/cargo") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_ship_cargo_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetShipModulesResponse { + GetShipModulesResponse(modules: List(ShipModule)) +} + +pub fn get_ship_modules_response_decoder() -> Decoder(GetShipModulesResponse) { + use modules <- decode.then(decode.list(ship_module.decoder())) + decode.success(GetShipModulesResponse(modules:)) +} + +pub fn get_ship_modules( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetShipModulesResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/modules", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_ship_modules_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type InstallShipModuleResponse { + InstallShipModuleResponse( + agent: Agent, + modules: List(ShipModule), + cargo: ShipCargo, + transaction: ShipModificationTransaction, + ) +} + +pub fn install_ship_module_response_decoder() -> Decoder( + InstallShipModuleResponse, +) { + use agent <- decode.field("agent", agent.decoder()) + use modules <- decode.field("modules", decode.list(ship_module.decoder())) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use transaction <- decode.field( + "transaction", + ship_modification_transaction.decoder(), + ) + decode.success(InstallShipModuleResponse( + agent:, + modules:, + cargo:, + transaction:, + )) +} + +pub fn install_ship_module( + token: AgentToken, + ship_symbol: ShipSymbol, + module_symbol: ModuleSymbol, +) -> ApiResponse(InstallShipModuleResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/modules/install", + json.object([ + #("symbol", json.string(module_symbol.to_string(module_symbol))), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + install_ship_module_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type RemoveShipModuleResponse { + RemoveShipModuleResponse( + agent: Agent, + modules: List(ShipModule), + cargo: ShipCargo, + transaction: ShipModificationTransaction, + ) +} + +pub fn remove_ship_module_response_decoder() -> Decoder( + RemoveShipModuleResponse, +) { + use agent <- decode.field("agent", agent.decoder()) + use modules <- decode.field("modules", decode.list(ship_module.decoder())) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use transaction <- decode.field( + "transaction", + ship_modification_transaction.decoder(), + ) + decode.success(RemoveShipModuleResponse( + agent:, + modules:, + cargo:, + transaction:, + )) +} + +pub fn remove_ship_module( + token: AgentToken, + ship_symbol: ShipSymbol, + module_symbol: ModuleSymbol, +) -> ApiResponse(RemoveShipModuleResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/modules/remove", + json.object([ + #("symbol", json.string(module_symbol.to_string(module_symbol))), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + remove_ship_module_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetShipMountsResponse { + GetShipMountsResponse(mounts: List(ShipMount)) +} + +pub fn get_ship_mounts_response_decoder() -> Decoder(GetShipMountsResponse) { + use mounts <- decode.then(decode.list(ship_mount.decoder())) + decode.success(GetShipMountsResponse(mounts:)) +} + +pub fn get_ship_mounts( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetShipMountsResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/mounts", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_ship_mounts_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type InstallShipMountResponse { + InstallShipMountResponse( + agent: Agent, + mounts: List(ShipMount), + cargo: ShipCargo, + transaction: ShipModificationTransaction, + ) +} + +pub fn install_ship_mount_response_decoder() -> Decoder( + InstallShipMountResponse, +) { + use agent <- decode.field("agent", agent.decoder()) + use mounts <- decode.field("mounts", decode.list(ship_mount.decoder())) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use transaction <- decode.field( + "transaction", + ship_modification_transaction.decoder(), + ) + decode.success(InstallShipMountResponse(agent:, mounts:, cargo:, transaction:)) +} + +pub fn install_ship_mount( + token: AgentToken, + ship_symbol: ShipSymbol, + mount_symbol: MountSymbol, +) -> ApiResponse(InstallShipMountResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/mounts/install", + json.object([ + #("symbol", json.string(mount_symbol.to_string(mount_symbol))), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + install_ship_mount_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type RemoveShipMountResponse { + RemoveShipMountResponse( + agent: Agent, + mounts: List(ShipMount), + cargo: ShipCargo, + transaction: ShipModificationTransaction, + ) +} + +pub fn remove_ship_mount_response_decoder() -> Decoder(RemoveShipMountResponse) { + use agent <- decode.field("agent", agent.decoder()) + use mounts <- decode.field("mounts", decode.list(ship_mount.decoder())) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use transaction <- decode.field( + "transaction", + ship_modification_transaction.decoder(), + ) + decode.success(RemoveShipMountResponse(agent:, mounts:, cargo:, transaction:)) +} + +pub fn remove_ship_mount( + token: AgentToken, + ship_symbol: ShipSymbol, + mount_symbol: MountSymbol, +) -> ApiResponse(RemoveShipMountResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/mounts/remove", + json.object([ + #("symbol", json.string(mount_symbol.to_string(mount_symbol))), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + remove_ship_mount_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetShipNavResponse { + GetShipNavResponse(nav: ShipNav) +} + +pub fn get_ship_nav_response_decoder() -> Decoder(GetShipNavResponse) { + use nav <- decode.then(ship_nav.decoder()) + decode.success(GetShipNavResponse(nav:)) +} + +pub fn get_ship_nav( + token: AgentToken, + ship_symbol: ShipSymbol, +) -> ApiResponse(GetShipNavResponse) { + let request = + request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/nav") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_ship_nav_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type PatchShipNavResponse { + PatchShipNavResponse( + nav: ShipNav, + fuel: ShipFuel, + events: List(ShipConditionEvent), + ) +} + +pub fn patch_ship_nav_response_decoder() -> Decoder(PatchShipNavResponse) { + use nav <- decode.field("nav", ship_nav.decoder()) + use fuel <- decode.field("fuel", ship_fuel.decoder()) + use events <- decode.field( + "events", + decode.list(ship_condition_event.decoder()), + ) + decode.success(PatchShipNavResponse(nav:, fuel:, events:)) +} + +pub fn patch_ship_nav( + token: AgentToken, + ship_symbol: ShipSymbol, + flight_mode: ShipNavFlightMode, +) -> ApiResponse(PatchShipNavResponse) { + let request = + request_utils.patch_json( + AgentAuth(token), + "/my/ships/" <> ship_symbol <> "/nav", + json.object([ + #( + "flightMode", + json.string(ship_nav_flight_mode.to_string(flight_mode)), + ), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + patch_ship_nav_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} diff --git a/src/endpoints/global.gleam b/src/endpoints/global.gleam new file mode 100644 index 0000000..5a17d37 --- /dev/null +++ b/src/endpoints/global.gleam @@ -0,0 +1,192 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import utils/auth.{NoAuth} +import utils/decode as decode_utils +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse} + +pub type Stats { + Stats( + accounts: Option(Int), + agents: Int, + ships: Int, + systems: Int, + waypoints: Int, + ) +} + +fn stats_decoder() -> Decoder(Stats) { + use accounts <- decode_utils.field_key_value_optional("accounts", decode.int) + use agents <- decode.field("agents", decode.int) + use ships <- decode.field("ships", decode.int) + use systems <- decode.field("systems", decode.int) + use waypoints <- decode.field("waypoints", decode.int) + decode.success(Stats(accounts:, agents:, ships:, systems:, waypoints:)) +} + +pub type Health { + Health(last_market_update: Option(String)) +} + +fn health_decoder() -> Decoder(Health) { + use last_market_update <- decode_utils.field_key_value_optional( + "lastMarketUpdate", + decode.string, + ) + decode.success(Health(last_market_update:)) +} + +pub type CreditLeaderboardEntry { + CreditLeaderboardEntry(agent_symbol: String, credits: Int) +} + +fn credit_leaderboard_entry_decoder() -> Decoder(CreditLeaderboardEntry) { + use agent_symbol <- decode.field("agentSymbol", decode.string) + use credits <- decode.field("credits", decode.int) + decode.success(CreditLeaderboardEntry(agent_symbol:, credits:)) +} + +pub type ChartLeaderboardEntry { + ChartLeaderboardEntry(agent_symbol: String, chart_count: Int) +} + +fn chart_leaderboard_entry_decoder() -> Decoder(ChartLeaderboardEntry) { + use agent_symbol <- decode.field("agentSymbol", decode.string) + use chart_count <- decode.field("chartCount", decode.int) + decode.success(ChartLeaderboardEntry(agent_symbol:, chart_count:)) +} + +pub type Leaderboards { + Leaderboards( + most_credits: List(CreditLeaderboardEntry), + most_submitted_charts: List(ChartLeaderboardEntry), + ) +} + +fn leaderboards_decoder() -> Decoder(Leaderboards) { + use most_credits <- decode.field( + "mostCredits", + decode.list(credit_leaderboard_entry_decoder()), + ) + use most_submitted_charts <- decode.field( + "mostSubmittedCharts", + decode.list(chart_leaderboard_entry_decoder()), + ) + decode.success(Leaderboards(most_credits:, most_submitted_charts:)) +} + +pub type ServerResets { + ServerResets(next: String, frequency: String) +} + +fn server_resets_decoder() -> Decoder(ServerResets) { + use next <- decode.field("next", decode.string) + use frequency <- decode.field("frequency", decode.string) + decode.success(ServerResets(next:, frequency:)) +} + +pub type Announcement { + Announcement(title: String, body: String) +} + +fn announcement_decoder() -> Decoder(Announcement) { + use title <- decode.field("title", decode.string) + use body <- decode.field("body", decode.string) + decode.success(Announcement(title:, body:)) +} + +pub type Link { + Link(name: String, url: String) +} + +fn link_decoder() -> Decoder(Link) { + use name <- decode.field("name", decode.string) + use url <- decode.field("url", decode.string) + decode.success(Link(name:, url:)) +} + +pub type GetServerStatusResponse { + GetServerStatusResponse( + status: String, + version: String, + reset_date: String, + description: String, + stats: Stats, + health: Health, + leaderboards: Leaderboards, + server_resets: ServerResets, + announcements: List(Announcement), + links: List(Link), + ) +} + +fn get_server_status_response_decoder() -> Decoder(GetServerStatusResponse) { + use status <- decode.field("status", decode.string) + use version <- decode.field("version", decode.string) + use reset_date <- decode.field("resetDate", decode.string) + use description <- decode.field("description", decode.string) + use stats <- decode.field("stats", stats_decoder()) + use health <- decode.field("health", health_decoder()) + use leaderboards <- decode.field("leaderboards", leaderboards_decoder()) + use server_resets <- decode.field("serverResets", server_resets_decoder()) + use announcements <- decode.field( + "announcements", + decode.list(announcement_decoder()), + ) + use links <- decode.field("links", decode.list(link_decoder())) + decode.success(GetServerStatusResponse( + status:, + version:, + reset_date:, + description:, + stats:, + health:, + leaderboards:, + server_resets:, + announcements:, + links:, + )) +} + +pub fn get_server_status() -> ApiResponse(GetServerStatusResponse) { + let request = request_utils.get(NoAuth, "/") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.parser(response.body, get_server_status_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type ErrorCode { + ErrorCode(code: Int, name: String) +} + +fn error_code_decoder() -> Decoder(ErrorCode) { + use code <- decode.field("code", decode.int) + use name <- decode.field("name", decode.string) + decode.success(ErrorCode(code:, name:)) +} + +pub type ListErrorCodesResponse { + ListErrorCodesResponse(error_codes: List(ErrorCode)) +} + +fn list_error_codes_response_decoder() -> Decoder(ListErrorCodesResponse) { + use error_codes <- decode.field( + "errorCodes", + decode.list(error_code_decoder()), + ) + decode.success(ListErrorCodesResponse(error_codes:)) +} + +pub fn list_error_codes() -> ApiResponse(ListErrorCodesResponse) { + let request = request_utils.get(NoAuth, "/error-codes") + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.parser(response.body, list_error_codes_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} diff --git a/src/endpoints/systems.gleam b/src/endpoints/systems.gleam new file mode 100644 index 0000000..fe346d4 --- /dev/null +++ b/src/endpoints/systems.gleam @@ -0,0 +1,321 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json +import gleam/list +import gleam/option.{type Option} +import models/construction.{type Construction} +import models/jump_gate.{type JumpGate} +import models/market.{type Market} +import models/ship_cargo.{type ShipCargo} +import models/ship_symbol.{type ShipSymbol} +import models/shipyard.{type Shipyard} +import models/system.{type System} +import models/system_symbol.{type SystemSymbol} +import models/trade_symbol.{type TradeSymbol} +import models/waypoint.{type Waypoint} +import models/waypoint_symbol.{type WaypointSymbol} +import models/waypoint_trait_symbol.{type WaypointTraitSymbol} +import models/waypoint_type.{type WaypointType} +import utils/auth.{type AgentToken, AgentAuth} +import utils/request as request_utils +import utils/response as response_utils +import utils/types.{type ApiResponse, type PagedData} + +pub type ListSystemsResponse { + ListSystemsResponse(systems: List(System)) +} + +fn list_systems_response_decoder() -> Decoder(ListSystemsResponse) { + use systems <- decode.then(decode.list(system.decoder())) + decode.success(ListSystemsResponse(systems:)) +} + +pub fn list_systems( + token: AgentToken, + page: Int, + limit: Int, +) -> ApiResponse(PagedData(ListSystemsResponse)) { + let request = + request_utils.get_page(AgentAuth(token), "/systems", page, limit) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.paged_data_parser( + response.body, + list_systems_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetSystemResponse { + GetSystemResponse(system: System) +} + +fn get_system_response_decoder() -> Decoder(GetSystemResponse) { + use system <- decode.then(system.decoder()) + decode.success(GetSystemResponse(system:)) +} + +pub fn get_system( + token: AgentToken, + system_symbol: SystemSymbol, +) -> ApiResponse(GetSystemResponse) { + let request = + request_utils.get(AgentAuth(token), "/systems/" <> system_symbol) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_system_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type ListSystemWaypointsResponse { + ListSystemWaypointsResponse(waypoints: List(Waypoint)) +} + +fn list_system_waypoints_response_decoder() -> Decoder( + ListSystemWaypointsResponse, +) { + use waypoints <- decode.then(decode.list(waypoint.decoder())) + decode.success(ListSystemWaypointsResponse(waypoints:)) +} + +pub fn list_system_waypoints( + token: AgentToken, + system_symbol: SystemSymbol, + page: Int, + limit: Int, + type_: Option(WaypointType), + traits: List(WaypointTraitSymbol), +) -> ApiResponse(PagedData(ListSystemWaypointsResponse)) { + let traits_query = + traits + |> list.map(fn(trait) { + #("traits", waypoint_trait_symbol.to_string(trait)) + }) + let query = case type_ { + option.Some(type_) -> [ + #("type", waypoint_type.to_string(type_)), + ..traits_query + ] + option.None -> traits_query + } + let request = + request_utils.get_page_query( + AgentAuth(token), + "/systems/" <> system_symbol <> "/waypoints", + page, + limit, + query, + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.paged_data_parser( + response.body, + list_system_waypoints_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetWaypointResponse { + GetWaypointResponse(waypoint: Waypoint) +} + +fn get_waypoint_response_decoder() -> Decoder(GetWaypointResponse) { + use waypoint <- decode.then(waypoint.decoder()) + decode.success(GetWaypointResponse(waypoint:)) +} + +pub fn get_waypoint( + token: AgentToken, + system_symbol: SystemSymbol, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(GetWaypointResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/systems/" <> system_symbol <> "/waypoints/" <> waypoint_symbol, + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_waypoint_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetConstructionSiteResponse { + GetConstructionSiteResponse(construction: Construction) +} + +fn get_construction_site_response_decoder() -> Decoder( + GetConstructionSiteResponse, +) { + use construction <- decode.then(construction.decoder()) + decode.success(GetConstructionSiteResponse(construction:)) +} + +pub fn get_construction_site( + token: AgentToken, + system_symbol: SystemSymbol, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(GetConstructionSiteResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/systems/" + <> system_symbol + <> "/waypoints/" + <> waypoint_symbol + <> "/construction", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_construction_site_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type SupplyConstructionSiteResponse { + SupplyConstructionSiteResponse(construction: Construction, cargo: ShipCargo) +} + +fn supply_construction_site_response_decoder() -> Decoder( + SupplyConstructionSiteResponse, +) { + use construction <- decode.field("construction", construction.decoder()) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + decode.success(SupplyConstructionSiteResponse(construction:, cargo:)) +} + +pub fn supply_construction_site( + token: AgentToken, + system_symbol: SystemSymbol, + waypoint_symbol: WaypointSymbol, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, + units: Int, +) -> ApiResponse(SupplyConstructionSiteResponse) { + let request = + request_utils.post_json( + AgentAuth(token), + "/systems/" + <> system_symbol + <> "/waypoints/" + <> waypoint_symbol + <> "/construction/supply", + json.object([ + #("shipSymbol", json.string(ship_symbol)), + #("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))), + #("units", json.int(units)), + ]), + ) + use response <- request_utils.try_send(request) + case response.status { + 201 -> + response_utils.data_parser( + response.body, + supply_construction_site_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetMarketResponse { + GetMarketResponse(market: Market) +} + +fn get_market_response_decoder() -> Decoder(GetMarketResponse) { + use market <- decode.then(market.decoder()) + decode.success(GetMarketResponse(market:)) +} + +pub fn get_market( + token: AgentToken, + system_symbol: SystemSymbol, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(GetMarketResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/systems/" + <> system_symbol + <> "/waypoints/" + <> waypoint_symbol + <> "/market", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_market_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetJumpGateResponse { + GetJumpGateResponse(jump_gate: JumpGate) +} + +fn get_jump_gate_response_decoder() -> Decoder(GetJumpGateResponse) { + use jump_gate <- decode.then(jump_gate.decoder()) + decode.success(GetJumpGateResponse(jump_gate:)) +} + +pub fn get_jump_gate( + token: AgentToken, + system_symbol: SystemSymbol, + waypoint_symbol: WaypointSymbol, +) -> ApiResponse(GetJumpGateResponse) { + let request = + request_utils.get( + AgentAuth(token), + "/systems/" + <> system_symbol + <> "/waypoints/" + <> waypoint_symbol + <> "/jump-gate", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser( + response.body, + get_jump_gate_response_decoder(), + ) + _ -> response_utils.error_parser(response.body) + } +} + +pub type GetShipyardResponse { + GetShipyardResponse(shipyard: Shipyard) +} + +fn get_shipyard_response_decoder() -> Decoder(GetShipyardResponse) { + use shipyard <- decode.then(shipyard.decoder()) + decode.success(GetShipyardResponse(shipyard:)) +} + +pub fn get_shipyard(token, system_symbol, waypoint_symbol) { + let request = + request_utils.get( + AgentAuth(token), + "/systems/" + <> system_symbol + <> "/waypoints/" + <> waypoint_symbol + <> "/shipyard", + ) + use response <- request_utils.try_send(request) + case response.status { + 200 -> + response_utils.data_parser(response.body, get_shipyard_response_decoder()) + _ -> response_utils.error_parser(response.body) + } +} diff --git a/src/models/account.gleam b/src/models/account.gleam new file mode 100644 index 0000000..2313575 --- /dev/null +++ b/src/models/account.gleam @@ -0,0 +1,20 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import utils/decode as decode_utils + +pub type Account { + Account( + id: String, + email: Option(String), + token: Option(String), + created_at: String, + ) +} + +pub fn decoder() -> Decoder(Account) { + use id <- decode.field("id", decode.string) + use email <- decode_utils.field_value_optional("email", decode.string) + use token <- decode_utils.field_key_value_optional("token", decode.string) + use created_at <- decode.field("createdAt", decode.string) + decode.success(Account(id:, email:, token:, created_at:)) +} diff --git a/src/models/activity_level.gleam b/src/models/activity_level.gleam new file mode 100644 index 0000000..220be75 --- /dev/null +++ b/src/models/activity_level.gleam @@ -0,0 +1,32 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ActivityLevel { + Weak + Growing + Strong + Restricted +} + +pub fn to_string(activity_level: ActivityLevel) -> String { + case activity_level { + Weak -> "WEAK" + Growing -> "GROWING" + Strong -> "STRONG" + Restricted -> "RESTRICTED" + } +} + +pub fn parse(activity_level_str: String) -> Result(ActivityLevel, ActivityLevel) { + case activity_level_str { + "WEAK" -> Ok(Weak) + "GROWING" -> Ok(Growing) + "STRONG" -> Ok(Strong) + "RESTRICTED" -> Ok(Restricted) + _ -> Error(Weak) + } +} + +pub fn decoder() -> Decoder(ActivityLevel) { + decode_utils.enum_decoder(parse, "ActivityLevel") +} diff --git a/src/models/agent.gleam b/src/models/agent.gleam new file mode 100644 index 0000000..b145f76 --- /dev/null +++ b/src/models/agent.gleam @@ -0,0 +1,30 @@ +import gleam/dynamic/decode.{type Decoder} +import models/agent_symbol.{type AgentSymbol} + +pub type Agent { + Agent( + account_id: String, + symbol: AgentSymbol, + headquarters: String, + credits: Int, + starting_faction: String, + ship_count: Int, + ) +} + +pub fn decoder() -> Decoder(Agent) { + use account_id <- decode.field("accountId", decode.string) + use symbol <- decode.field("symbol", agent_symbol.decoder()) + use headquarters <- decode.field("headquarters", decode.string) + use credits <- decode.field("credits", decode.int) + use starting_faction <- decode.field("startingFaction", decode.string) + use ship_count <- decode.field("shipCount", decode.int) + decode.success(Agent( + account_id:, + symbol:, + headquarters:, + credits:, + starting_faction:, + ship_count:, + )) +} diff --git a/src/models/agent_event.gleam b/src/models/agent_event.gleam new file mode 100644 index 0000000..7bc0296 --- /dev/null +++ b/src/models/agent_event.gleam @@ -0,0 +1,23 @@ +import gleam/dynamic.{type Dynamic} +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import utils/decode as decode_utils + +pub type AgentEvent { + AgentEvent( + id: String, + type_: String, + message: String, + data: Option(Dynamic), + created_at: String, + ) +} + +pub fn decoder() -> Decoder(AgentEvent) { + use id <- decode.field("id", decode.string) + use type_ <- decode.field("type", decode.string) + use message <- decode.field("message", decode.string) + use data <- decode_utils.field_key_value_optional("data", decode.dynamic) + use created_at <- decode.field("createdAt", decode.string) + decode.success(AgentEvent(id:, type_:, message:, data:, created_at:)) +} diff --git a/src/models/agent_symbol.gleam b/src/models/agent_symbol.gleam new file mode 100644 index 0000000..f7df3d0 --- /dev/null +++ b/src/models/agent_symbol.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type AgentSymbol = + String + +pub fn decoder() -> Decoder(AgentSymbol) { + decode.string +} diff --git a/src/models/chart.gleam b/src/models/chart.gleam new file mode 100644 index 0000000..d697249 --- /dev/null +++ b/src/models/chart.gleam @@ -0,0 +1,21 @@ +import gleam/dynamic/decode.{type Decoder} +import models/agent_symbol.{type AgentSymbol} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type Chart { + Chart( + waypoint_symbol: WaypointSymbol, + submitted_by: AgentSymbol, + submitted_on: String, + ) +} + +pub fn decoder() -> Decoder(Chart) { + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use submitted_by <- decode.field("submittedBy", agent_symbol.decoder()) + use submitted_on <- decode.field("submittedOn", decode.string) + decode.success(Chart(waypoint_symbol:, submitted_by:, submitted_on:)) +} diff --git a/src/models/chart_transaction.gleam b/src/models/chart_transaction.gleam new file mode 100644 index 0000000..14c98ea --- /dev/null +++ b/src/models/chart_transaction.gleam @@ -0,0 +1,28 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_symbol.{type ShipSymbol} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type ChartTransaction { + ChartTransaction( + waypoint_symbol: WaypointSymbol, + ship_symbol: ShipSymbol, + total_price: Int, + timestamp: String, + ) +} + +pub fn decoder() -> Decoder(ChartTransaction) { + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) + use total_price <- decode.field("totalPrice", decode.int) + use timestamp <- decode.field("timestamp", decode.string) + decode.success(ChartTransaction( + waypoint_symbol:, + ship_symbol:, + total_price:, + timestamp:, + )) +} diff --git a/src/models/construction.gleam b/src/models/construction.gleam new file mode 100644 index 0000000..5538e06 --- /dev/null +++ b/src/models/construction.gleam @@ -0,0 +1,20 @@ +import gleam/dynamic/decode.{type Decoder} +import models/construction_material.{type ConstructionMaterial} + +pub type Construction { + Construction( + symbol: String, + materials: List(ConstructionMaterial), + is_complete: Bool, + ) +} + +pub fn decoder() -> Decoder(Construction) { + use symbol <- decode.field("symbol", decode.string) + use materials <- decode.field( + "materials", + decode.list(construction_material.decoder()), + ) + use is_complete <- decode.field("isComplete", decode.bool) + decode.success(Construction(symbol:, materials:, is_complete:)) +} diff --git a/src/models/construction_material.gleam b/src/models/construction_material.gleam new file mode 100644 index 0000000..35a9423 --- /dev/null +++ b/src/models/construction_material.gleam @@ -0,0 +1,13 @@ +import gleam/dynamic/decode.{type Decoder} +import models/trade_symbol.{type TradeSymbol} + +pub type ConstructionMaterial { + ConstructionMaterial(trade_symbol: TradeSymbol, required: Int, fulfilled: Int) +} + +pub fn decoder() -> Decoder(ConstructionMaterial) { + use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder()) + use required <- decode.field("required", decode.int) + use fulfilled <- decode.field("fulfilled", decode.int) + decode.success(ConstructionMaterial(trade_symbol:, required:, fulfilled:)) +} diff --git a/src/models/contract.gleam b/src/models/contract.gleam new file mode 100644 index 0000000..19357c5 --- /dev/null +++ b/src/models/contract.gleam @@ -0,0 +1,38 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/contract_terms.{type ContractTerms} +import utils/decode as decode_utils + +pub type Contract { + Contract( + id: String, + faction_symbol: String, + type_: String, + terms: ContractTerms, + accepted: Bool, + fulfilled: Bool, + deadline_to_accept: Option(String), + ) +} + +pub fn decoder() -> Decoder(Contract) { + use id <- decode.field("id", decode.string) + use faction_symbol <- decode.field("factionSymbol", decode.string) + use type_ <- decode.field("type", decode.string) + use terms <- decode.field("terms", contract_terms.decoder()) + use accepted <- decode.field("accepted", decode.bool) + use fulfilled <- decode.field("fulfilled", decode.bool) + use deadline_to_accept <- decode_utils.field_key_value_optional( + "deadlineToAccept", + decode.string, + ) + decode.success(Contract( + id:, + faction_symbol:, + type_:, + terms:, + accepted:, + fulfilled:, + deadline_to_accept:, + )) +} diff --git a/src/models/contract_deliver_good.gleam b/src/models/contract_deliver_good.gleam new file mode 100644 index 0000000..d31cc09 --- /dev/null +++ b/src/models/contract_deliver_good.gleam @@ -0,0 +1,23 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ContractDeliverGood { + ContractDeliverGood( + trade_symbol: String, + destination_symbol: String, + units_required: Int, + units_fulfilled: Int, + ) +} + +pub fn decoder() -> Decoder(ContractDeliverGood) { + use trade_symbol <- decode.field("tradeSymbol", decode.string) + use destination_symbol <- decode.field("destinationSymbol", decode.string) + use units_required <- decode.field("unitsRequired", decode.int) + use units_fulfilled <- decode.field("unitsFulfilled", decode.int) + decode.success(ContractDeliverGood( + trade_symbol:, + destination_symbol:, + units_required:, + units_fulfilled:, + )) +} diff --git a/src/models/contract_payment.gleam b/src/models/contract_payment.gleam new file mode 100644 index 0000000..927b019 --- /dev/null +++ b/src/models/contract_payment.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ContractPayment { + ContractPayment(on_accepted: Int, on_fulfilled: Int) +} + +pub fn decoder() -> Decoder(ContractPayment) { + use on_accepted <- decode.field("onAccepted", decode.int) + use on_fulfilled <- decode.field("onFulfilled", decode.int) + decode.success(ContractPayment(on_accepted:, on_fulfilled:)) +} diff --git a/src/models/contract_terms.gleam b/src/models/contract_terms.gleam new file mode 100644 index 0000000..4fde256 --- /dev/null +++ b/src/models/contract_terms.gleam @@ -0,0 +1,23 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/contract_deliver_good.{type ContractDeliverGood} +import models/contract_payment.{type ContractPayment} +import utils/decode as decode_utils + +pub type ContractTerms { + ContractTerms( + deadline: String, + payment: ContractPayment, + deliver: Option(List(ContractDeliverGood)), + ) +} + +pub fn decoder() -> Decoder(ContractTerms) { + use deadline <- decode.field("deadline", decode.string) + use payment <- decode.field("payment", contract_payment.decoder()) + use deliver <- decode_utils.field_key_value_optional( + "deliver", + decode.list(contract_deliver_good.decoder()), + ) + decode.success(ContractTerms(deadline:, payment:, deliver:)) +} diff --git a/src/models/cooldown.gleam b/src/models/cooldown.gleam new file mode 100644 index 0000000..9fb94c4 --- /dev/null +++ b/src/models/cooldown.gleam @@ -0,0 +1,29 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/ship_symbol.{type ShipSymbol} +import utils/decode as decode_utils + +pub type Cooldown { + Cooldown( + ship_symbol: ShipSymbol, + total_seconds: Int, + remaining_seconds: Int, + expiration: Option(String), + ) +} + +pub fn decoder() -> Decoder(Cooldown) { + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) + use total_seconds <- decode.field("totalSeconds", decode.int) + use remaining_seconds <- decode.field("remainingSeconds", decode.int) + use expiration <- decode_utils.field_key_value_optional( + "expiration", + decode.string, + ) + decode.success(Cooldown( + ship_symbol:, + total_seconds:, + remaining_seconds:, + expiration:, + )) +} diff --git a/src/models/crew_rotation.gleam b/src/models/crew_rotation.gleam new file mode 100644 index 0000000..75dd328 --- /dev/null +++ b/src/models/crew_rotation.gleam @@ -0,0 +1,26 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type CrewRotation { + Strict + Relaxed +} + +pub fn to_string(crew_rotation: CrewRotation) -> String { + case crew_rotation { + Strict -> "STRICT" + Relaxed -> "RELAXED" + } +} + +pub fn parse(crew_rotation_str: String) -> Result(CrewRotation, CrewRotation) { + case crew_rotation_str { + "STRICT" -> Ok(Strict) + "RELAXED" -> Ok(Relaxed) + _ -> Error(Strict) + } +} + +pub fn decoder() -> Decoder(CrewRotation) { + decode_utils.enum_decoder(parse, "CrewRotation") +} diff --git a/src/models/engine_symbol.gleam b/src/models/engine_symbol.gleam new file mode 100644 index 0000000..cdee27d --- /dev/null +++ b/src/models/engine_symbol.gleam @@ -0,0 +1,32 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type EngineSymbol { + EngineImpulseDriveI + EngineIonDriveI + EngineIonDriveII + EngineHyperDriveI +} + +pub fn to_string(engine_symbol: EngineSymbol) -> String { + case engine_symbol { + EngineImpulseDriveI -> "ENGINE_IMPULSE_DRIVE_I" + EngineIonDriveI -> "ENGINE_ION_DRIVE_I" + EngineIonDriveII -> "ENGINE_ION_DRIVE_II" + EngineHyperDriveI -> "ENGINE_HYPER_DRIVE_I" + } +} + +pub fn parse(engine_symbol_str: String) -> Result(EngineSymbol, EngineSymbol) { + case engine_symbol_str { + "ENGINE_IMPULSE_DRIVE_I" -> Ok(EngineImpulseDriveI) + "ENGINE_ION_DRIVE_I" -> Ok(EngineIonDriveI) + "ENGINE_ION_DRIVE_II" -> Ok(EngineIonDriveII) + "ENGINE_HYPER_DRIVE_I" -> Ok(EngineHyperDriveI) + _ -> Error(EngineImpulseDriveI) + } +} + +pub fn decoder() -> Decoder(EngineSymbol) { + decode_utils.enum_decoder(parse, "EngineSymbol") +} diff --git a/src/models/extraction.gleam b/src/models/extraction.gleam new file mode 100644 index 0000000..040cc5a --- /dev/null +++ b/src/models/extraction.gleam @@ -0,0 +1,13 @@ +import gleam/dynamic/decode.{type Decoder} +import models/extraction_yield.{type ExtractionYield} +import models/ship_symbol.{type ShipSymbol} + +pub type Extraction { + Extraction(ship_symbol: ShipSymbol, yield: ExtractionYield) +} + +pub fn decoder() -> Decoder(Extraction) { + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) + use yield <- decode.field("yield", extraction_yield.decoder()) + decode.success(Extraction(ship_symbol:, yield:)) +} diff --git a/src/models/extraction_yield.gleam b/src/models/extraction_yield.gleam new file mode 100644 index 0000000..8697d03 --- /dev/null +++ b/src/models/extraction_yield.gleam @@ -0,0 +1,12 @@ +import gleam/dynamic/decode.{type Decoder} +import models/trade_symbol.{type TradeSymbol} + +pub type ExtractionYield { + ExtractionYield(symbol: TradeSymbol, units: Int) +} + +pub fn decoder() -> Decoder(ExtractionYield) { + use symbol <- decode.field("symbol", trade_symbol.decoder()) + use units <- decode.field("units", decode.int) + decode.success(ExtractionYield(symbol:, units:)) +} diff --git a/src/models/faction.gleam b/src/models/faction.gleam new file mode 100644 index 0000000..7443c32 --- /dev/null +++ b/src/models/faction.gleam @@ -0,0 +1,36 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/faction_symbol.{type FactionSymbol} +import models/faction_trait.{type FactionTrait} +import utils/decode as decode_utils + +pub type Faction { + Faction( + symbol: FactionSymbol, + name: String, + description: String, + headquarters: Option(String), + traits: List(FactionTrait), + is_recruiting: Bool, + ) +} + +pub fn decoder() -> Decoder(Faction) { + use symbol <- decode.field("symbol", faction_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + use headquarters <- decode_utils.field_key_value_optional( + "headquarters", + decode.string, + ) + use traits <- decode.field("traits", decode.list(faction_trait.decoder())) + use is_recruiting <- decode.field("isRecruiting", decode.bool) + decode.success(Faction( + symbol:, + name:, + description:, + headquarters:, + traits:, + is_recruiting:, + )) +} diff --git a/src/models/faction_symbol.gleam b/src/models/faction_symbol.gleam new file mode 100644 index 0000000..4b9029b --- /dev/null +++ b/src/models/faction_symbol.gleam @@ -0,0 +1,77 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type FactionSymbol { + Cosmic + Void + Galactic + Quantum + Dominion + Astro + Corsairs + Obsidian + Aegis + United + Solitary + Cobalt + Omega + Echo + Lord + Cult + Ancients + Shadow + Ethereal +} + +pub fn to_string(symbol: FactionSymbol) -> String { + case symbol { + Cosmic -> "COSMIC" + Void -> "VOID" + Galactic -> "GALACTIC" + Quantum -> "QUANTUM" + Dominion -> "DOMINION" + Astro -> "ASTRO" + Corsairs -> "CORSAIRS" + Obsidian -> "OBSIDIAN" + Aegis -> "AEGIS" + United -> "UNITED" + Solitary -> "SOLITARY" + Cobalt -> "COBALT" + Omega -> "OMEGA" + Echo -> "ECHO" + Lord -> "LORDS" + Cult -> "CULT" + Ancients -> "ANCIENTS" + Shadow -> "SHADOW" + Ethereal -> "ETHEREAL" + } +} + +pub fn parse(symbol_str: String) -> Result(FactionSymbol, FactionSymbol) { + case symbol_str { + "COSMIC" -> Ok(Cosmic) + "VOID" -> Ok(Void) + "GALACTIC" -> Ok(Galactic) + "QUANTUM" -> Ok(Quantum) + "DOMINION" -> Ok(Dominion) + "ASTRO" -> Ok(Astro) + "CORSAIRS" -> Ok(Corsairs) + "OBSIDIAN" -> Ok(Obsidian) + "AEGIS" -> Ok(Aegis) + "UNITED" -> Ok(United) + "SOLITARY" -> Ok(Solitary) + "COBALT" -> Ok(Cobalt) + "OMEGA" -> Ok(Omega) + "ECHO" -> Ok(Echo) + "LORDS" -> Ok(Lord) + "CULT" -> Ok(Cult) + "ANCIENTS" -> Ok(Ancients) + "SHADOW" -> Ok(Shadow) + "ETHEREAL" -> Ok(Ethereal) + _ -> Error(Cosmic) + } +} + +pub fn decoder() -> Decoder(FactionSymbol) { + decode_utils.enum_decoder(parse, "FactionSymbol") +} diff --git a/src/models/faction_trait.gleam b/src/models/faction_trait.gleam new file mode 100644 index 0000000..7b44bb5 --- /dev/null +++ b/src/models/faction_trait.gleam @@ -0,0 +1,13 @@ +import gleam/dynamic/decode.{type Decoder} +import models/faction_trait_symbol.{type FactionTraitSymbol} + +pub type FactionTrait { + FactionTrait(symbol: FactionTraitSymbol, name: String, description: String) +} + +pub fn decoder() -> Decoder(FactionTrait) { + use symbol <- decode.field("symbol", faction_trait_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + decode.success(FactionTrait(symbol:, name:, description:)) +} diff --git a/src/models/faction_trait_symbol.gleam b/src/models/faction_trait_symbol.gleam new file mode 100644 index 0000000..899c4e2 --- /dev/null +++ b/src/models/faction_trait_symbol.gleam @@ -0,0 +1,199 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type FactionTraitSymbol { + Bureaucratic + Secretive + Capitalistic + Industrious + Peaceful + Distrustful + Welcoming + Smugglers + Scavengers + Rebellious + Exiles + Pirates + Raiders + Clan + Guild + Dominion + Fringe + Forsaken + Isolated + Localized + Established + Notable + Dominant + Inescapable + Innovative + Bold + Visionary + Curious + Daring + Exploratory + Resourceful + Flexible + Cooperative + United + Strategic + Intelligent + ResearchFocused + Collaborative + Progressive + Militaristic + TechnologicallyAdvanced + Aggressive + Imperialistic + TreasureHunters + Dexterous + Unpredictable + Brutal + Fleeting + Adaptable + SelfSufficient + Defensive + Proud + Diverse + Independent + SelfInterested + Fragmented + Commercial + FreeMarkets + Entrepreneurial +} + +pub fn to_string(trait_symbol: FactionTraitSymbol) -> String { + case trait_symbol { + Bureaucratic -> "BUREAUCRATIC" + Secretive -> "SECRETIVE" + Capitalistic -> "CAPITALISTIC" + Industrious -> "INDUSTRIOUS" + Peaceful -> "PEACEFUL" + Distrustful -> "DISTRUSTFUL" + Welcoming -> "WELCOMING" + Smugglers -> "SMUGGLERS" + Scavengers -> "SCAVENGERS" + Rebellious -> "REBELLIOUS" + Exiles -> "EXILES" + Pirates -> "PIRATES" + Raiders -> "RAIDERS" + Clan -> "CLAN" + Guild -> "GUILD" + Dominion -> "DOMINION" + Fringe -> "FRINGE" + Forsaken -> "FORSAKEN" + Isolated -> "ISOLATED" + Localized -> "LOCALIZED" + Established -> "ESTABLISHED" + Notable -> "NOTABLE" + Dominant -> "DOMINANT" + Inescapable -> "INESCAPABLE" + Innovative -> "INNOVATIVE" + Bold -> "BOLD" + Visionary -> "VISIONARY" + Curious -> "CURIOUS" + Daring -> "DARING" + Exploratory -> "EXPLORATORY" + Resourceful -> "RESOURCEFUL" + Flexible -> "FLEXIBLE" + Cooperative -> "COOPERATIVE" + United -> "UNITED" + Strategic -> "STRATEGIC" + Intelligent -> "INTELLIGENT" + ResearchFocused -> "RESEARCH_FOCUSED" + Collaborative -> "COLLABORATIVE" + Progressive -> "PROGRESSIVE" + Militaristic -> "MILITARISTIC" + TechnologicallyAdvanced -> "TECHNOLOGICALLY_ADVANCED" + Aggressive -> "AGGRESSIVE" + Imperialistic -> "IMPERIALISTIC" + TreasureHunters -> "TREASURE_HUNTERS" + Dexterous -> "DEXTEROUS" + Unpredictable -> "UNPREDICTABLE" + Brutal -> "BRUTAL" + Fleeting -> "FLEETING" + Adaptable -> "ADAPTABLE" + SelfSufficient -> "SELF_SUFFICIENT" + Defensive -> "DEFENSIVE" + Proud -> "PROUD" + Diverse -> "DIVERSE" + Independent -> "INDEPENDENT" + SelfInterested -> "SELF_INTERESTED" + Fragmented -> "FRAGMENTED" + Commercial -> "COMMERCIAL" + FreeMarkets -> "FREE_MARKETS" + Entrepreneurial -> "ENTREPRENEURIAL" + } +} + +pub fn parse( + trait_symbol_str: String, +) -> Result(FactionTraitSymbol, FactionTraitSymbol) { + case trait_symbol_str { + "BUREAUCRATIC" -> Ok(Bureaucratic) + "SECRETIVE" -> Ok(Secretive) + "CAPITALISTIC" -> Ok(Capitalistic) + "INDUSTRIOUS" -> Ok(Industrious) + "PEACEFUL" -> Ok(Peaceful) + "DISTRUSTFUL" -> Ok(Distrustful) + "WELCOMING" -> Ok(Welcoming) + "SMUGGLERS" -> Ok(Smugglers) + "SCAVENGERS" -> Ok(Scavengers) + "REBELLIOUS" -> Ok(Rebellious) + "EXILES" -> Ok(Exiles) + "PIRATES" -> Ok(Pirates) + "RAIDERS" -> Ok(Raiders) + "CLAN" -> Ok(Clan) + "GUILD" -> Ok(Guild) + "DOMINION" -> Ok(Dominion) + "FRINGE" -> Ok(Fringe) + "FORSAKEN" -> Ok(Forsaken) + "ISOLATED" -> Ok(Isolated) + "LOCALIZED" -> Ok(Localized) + "ESTABLISHED" -> Ok(Established) + "NOTABLE" -> Ok(Notable) + "DOMINANT" -> Ok(Dominant) + "INESCAPABLE" -> Ok(Inescapable) + "INNOVATIVE" -> Ok(Innovative) + "BOLD" -> Ok(Bold) + "VISIONARY" -> Ok(Visionary) + "CURIOUS" -> Ok(Curious) + "DARING" -> Ok(Daring) + "EXPLORATORY" -> Ok(Exploratory) + "RESOURCEFUL" -> Ok(Resourceful) + "FLEXIBLE" -> Ok(Flexible) + "COOPERATIVE" -> Ok(Cooperative) + "UNITED" -> Ok(United) + "STRATEGIC" -> Ok(Strategic) + "INTELLIGENT" -> Ok(Intelligent) + "RESEARCH_FOCUSED" -> Ok(ResearchFocused) + "COLLABORATIVE" -> Ok(Collaborative) + "PROGRESSIVE" -> Ok(Progressive) + "MILITARISTIC" -> Ok(Militaristic) + "TECHNOLOGICALLY_ADVANCED" -> Ok(TechnologicallyAdvanced) + "AGGRESSIVE" -> Ok(Aggressive) + "IMPERIALISTIC" -> Ok(Imperialistic) + "TREASURE_HUNTERS" -> Ok(TreasureHunters) + "DEXTEROUS" -> Ok(Dexterous) + "UNPREDICTABLE" -> Ok(Unpredictable) + "BRUTAL" -> Ok(Brutal) + "FLEETING" -> Ok(Fleeting) + "ADAPTABLE" -> Ok(Adaptable) + "SELF_SUFFICIENT" -> Ok(SelfSufficient) + "DEFENSIVE" -> Ok(Defensive) + "PROUD" -> Ok(Proud) + "DIVERSE" -> Ok(Diverse) + "INDEPENDENT" -> Ok(Independent) + "SELF_INTERESTED" -> Ok(SelfInterested) + "FRAGMENTED" -> Ok(Fragmented) + "COMMERCIAL" -> Ok(Commercial) + "FREE_MARKETS" -> Ok(FreeMarkets) + "ENTREPRENEURIAL" -> Ok(Entrepreneurial) + _ -> Error(Bureaucratic) + } +} + +pub fn decoder() -> Decoder(FactionTraitSymbol) { + decode_utils.enum_decoder(parse, "FactionTraitSymbol") +} diff --git a/src/models/frame_symbol.gleam b/src/models/frame_symbol.gleam new file mode 100644 index 0000000..30b39c1 --- /dev/null +++ b/src/models/frame_symbol.gleam @@ -0,0 +1,68 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type FrameSymbol { + FrameProbe + FrameDrone + FrameInterceptor + FrameRacer + FrameFighter + FrameFrigate + FrameShuttle + FrameExplorer + FrameMiner + FrameLightFreighter + FrameHeavyFreighter + FrameTransport + FrameDestroyer + FrameCruiser + FrameCarrier + FrameBulkFreighter +} + +pub fn to_string(frame_symbol: FrameSymbol) -> String { + case frame_symbol { + FrameProbe -> "FRAME_PROBE" + FrameDrone -> "FRAME_DRONE" + FrameInterceptor -> "FRAME_INTERCEPTOR" + FrameRacer -> "FRAME_RACER" + FrameFighter -> "FRAME_FIGHTER" + FrameFrigate -> "FRAME_FRIGATE" + FrameShuttle -> "FRAME_SHUTTLE" + FrameExplorer -> "FRAME_EXPLORER" + FrameMiner -> "FRAME_MINER" + FrameLightFreighter -> "FRAME_LIGHT_FREIGHTER" + FrameHeavyFreighter -> "FRAME_HEAVY_FREIGHTER" + FrameTransport -> "FRAME_TRANSPORT" + FrameDestroyer -> "FRAME_DESTROYER" + FrameCruiser -> "FRAME_CRUISER" + FrameCarrier -> "FRAME_CARRIER" + FrameBulkFreighter -> "FRAME_BULK_FREIGHTER" + } +} + +pub fn parse(frame_symbol_str: String) -> Result(FrameSymbol, FrameSymbol) { + case frame_symbol_str { + "FRAME_PROBE" -> Ok(FrameProbe) + "FRAME_DRONE" -> Ok(FrameDrone) + "FRAME_INTERCEPTOR" -> Ok(FrameInterceptor) + "FRAME_RACER" -> Ok(FrameRacer) + "FRAME_FIGHTER" -> Ok(FrameFighter) + "FRAME_FRIGATE" -> Ok(FrameFrigate) + "FRAME_SHUTTLE" -> Ok(FrameShuttle) + "FRAME_EXPLORER" -> Ok(FrameExplorer) + "FRAME_MINER" -> Ok(FrameMiner) + "FRAME_LIGHT_FREIGHTER" -> Ok(FrameLightFreighter) + "FRAME_HEAVY_FREIGHTER" -> Ok(FrameHeavyFreighter) + "FRAME_TRANSPORT" -> Ok(FrameTransport) + "FRAME_DESTROYER" -> Ok(FrameDestroyer) + "FRAME_CRUISER" -> Ok(FrameCruiser) + "FRAME_CARRIER" -> Ok(FrameCarrier) + "FRAME_BULK_FREIGHTER" -> Ok(FrameBulkFreighter) + _ -> Error(FrameProbe) + } +} + +pub fn decoder() -> Decoder(FrameSymbol) { + decode_utils.enum_decoder(parse, "FrameSymbol") +} diff --git a/src/models/jump_gate.gleam b/src/models/jump_gate.gleam new file mode 100644 index 0000000..c2beeee --- /dev/null +++ b/src/models/jump_gate.gleam @@ -0,0 +1,12 @@ +import gleam/dynamic/decode.{type Decoder} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type JumpGate { + JumpGate(symbol: WaypointSymbol, connections: List(String)) +} + +pub fn decoder() -> Decoder(JumpGate) { + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) + use connections <- decode.field("connections", decode.list(decode.string)) + decode.success(JumpGate(symbol:, connections:)) +} diff --git a/src/models/market.gleam b/src/models/market.gleam new file mode 100644 index 0000000..f9fb635 --- /dev/null +++ b/src/models/market.gleam @@ -0,0 +1,41 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/market_symbol.{type MarketSymbol} +import models/market_trade_good.{type MarketTradeGood} +import models/market_transaction.{type MarketTransaction} +import models/trade_good.{type TradeGood} +import utils/decode as decode_utils + +pub type Market { + Market( + symbol: MarketSymbol, + exports: List(TradeGood), + imports: List(TradeGood), + exchange: List(TradeGood), + transactions: Option(List(MarketTransaction)), + trade_goods: Option(List(MarketTradeGood)), + ) +} + +pub fn decoder() -> Decoder(Market) { + use symbol <- decode.field("symbol", decode.string) + use exports <- decode.field("exports", decode.list(trade_good.decoder())) + use imports <- decode.field("imports", decode.list(trade_good.decoder())) + use exchange <- decode.field("exchange", decode.list(trade_good.decoder())) + use transactions <- decode_utils.field_key_value_optional( + "transactions", + decode.list(market_transaction.decoder()), + ) + use trade_goods <- decode_utils.field_key_value_optional( + "tradeGoods", + decode.list(market_trade_good.decoder()), + ) + decode.success(Market( + symbol:, + exports:, + imports:, + exchange:, + transactions:, + trade_goods:, + )) +} diff --git a/src/models/market_symbol.gleam b/src/models/market_symbol.gleam new file mode 100644 index 0000000..47d4d5d --- /dev/null +++ b/src/models/market_symbol.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type MarketSymbol = + String + +pub fn decoder() -> Decoder(MarketSymbol) { + decode.string +} diff --git a/src/models/market_trade_good.gleam b/src/models/market_trade_good.gleam new file mode 100644 index 0000000..7581274 --- /dev/null +++ b/src/models/market_trade_good.gleam @@ -0,0 +1,41 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/activity_level.{type ActivityLevel} +import models/supply_level.{type SupplyLevel} +import models/trade_good_type.{type TradeGoodType} +import models/trade_symbol.{type TradeSymbol} +import utils/decode as decode_utils + +pub type MarketTradeGood { + MarketTradeGood( + symbol: TradeSymbol, + type_: TradeGoodType, + trade_volume: Int, + supply: SupplyLevel, + activity: Option(ActivityLevel), + purchase_price: Int, + sell_price: Int, + ) +} + +pub fn decoder() -> Decoder(MarketTradeGood) { + use symbol <- decode.field("symbol", trade_symbol.decoder()) + use type_ <- decode.field("type", trade_good_type.decoder()) + use trade_volume <- decode.field("tradeVolume", decode.int) + use supply <- decode.field("supply", supply_level.decoder()) + use activity <- decode_utils.field_key_value_optional( + "activity", + activity_level.decoder(), + ) + use purchase_price <- decode.field("purchasePrice", decode.int) + use sell_price <- decode.field("sellPrice", decode.int) + decode.success(MarketTradeGood( + symbol:, + type_:, + trade_volume:, + supply:, + activity:, + purchase_price:, + sell_price:, + )) +} diff --git a/src/models/market_transaction.gleam b/src/models/market_transaction.gleam new file mode 100644 index 0000000..1c5f185 --- /dev/null +++ b/src/models/market_transaction.gleam @@ -0,0 +1,42 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_symbol.{type ShipSymbol} +import models/trade_symbol.{type TradeSymbol} +import models/transaction_type.{type TransactionType} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type MarketTransaction { + MarketTransaction( + waypoint_symbol: WaypointSymbol, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, + type_: TransactionType, + units: Int, + price_per_unit: Int, + total_price: Int, + timestamp: String, + ) +} + +pub fn decoder() -> Decoder(MarketTransaction) { + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use ship_symbol <- decode.field("shipSymbol", decode.string) + use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder()) + use type_ <- decode.field("type", transaction_type.decoder()) + use units <- decode.field("units", decode.int) + use price_per_unit <- decode.field("pricePerUnit", decode.int) + use total_price <- decode.field("totalPrice", decode.int) + use timestamp <- decode.field("timestamp", decode.string) + decode.success(MarketTransaction( + waypoint_symbol:, + ship_symbol:, + trade_symbol:, + type_:, + units:, + price_per_unit:, + total_price:, + timestamp:, + )) +} diff --git a/src/models/meta.gleam b/src/models/meta.gleam new file mode 100644 index 0000000..87fdb7e --- /dev/null +++ b/src/models/meta.gleam @@ -0,0 +1,12 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type Meta { + Meta(limit: Int, page: Int, total: Int) +} + +pub fn decoder() -> Decoder(Meta) { + use limit <- decode.field("limit", decode.int) + use page <- decode.field("page", decode.int) + use total <- decode.field("total", decode.int) + decode.success(Meta(limit: limit, page: page, total: total)) +} diff --git a/src/models/module_symbol.gleam b/src/models/module_symbol.gleam new file mode 100644 index 0000000..106f4e2 --- /dev/null +++ b/src/models/module_symbol.gleam @@ -0,0 +1,80 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ModuleSymbol { + ModuleMineralProcessorI + ModuleGasProcessorI + ModuleCargoHoldI + ModuleCargoHoldII + ModuleCargoHoldIII + ModuleCrewQuartersI + ModuleEnvoyQuartersI + ModulePassengerCabinI + ModuleMicroRefineryI + ModuleOreRefineryI + ModuleFuelRefineryI + ModuleScienceLabI + ModuleJumpDriveI + ModuleJumpDriveII + ModuleJumpDriveIII + ModuleWarpDriveI + ModuleWarpDriveII + ModuleWarpDriveIII + ModuleShieldGeneratorI + ModuleShieldGeneratorII +} + +pub fn to_string(module_symbol: ModuleSymbol) -> String { + case module_symbol { + ModuleMineralProcessorI -> "MODULE_MINERAL_PROCESSOR_I" + ModuleGasProcessorI -> "MODULE_GAS_PROCESSOR_I" + ModuleCargoHoldI -> "MODULE_CARGO_HOLD_I" + ModuleCargoHoldII -> "MODULE_CARGO_HOLD_II" + ModuleCargoHoldIII -> "MODULE_CARGO_HOLD_III" + ModuleCrewQuartersI -> "MODULE_CREW_QUARTERS_I" + ModuleEnvoyQuartersI -> "MODULE_ENVOY_QUARTERS_I" + ModulePassengerCabinI -> "MODULE_PASSENGER_CABIN_I" + ModuleMicroRefineryI -> "MODULE_MICRO_REFINERY_I" + ModuleOreRefineryI -> "MODULE_ORE_REFINERY_I" + ModuleFuelRefineryI -> "MODULE_FUEL_REFINERY_I" + ModuleScienceLabI -> "MODULE_SCIENCE_LAB_I" + ModuleJumpDriveI -> "MODULE_JUMP_DRIVE_I" + ModuleJumpDriveII -> "MODULE_JUMP_DRIVE_II" + ModuleJumpDriveIII -> "MODULE_JUMP_DRIVE_III" + ModuleWarpDriveI -> "MODULE_WARP_DRIVE_I" + ModuleWarpDriveII -> "MODULE_WARP_DRIVE_II" + ModuleWarpDriveIII -> "MODULE_WARP_DRIVE_III" + ModuleShieldGeneratorI -> "MODULE_SHIELD_GENERATOR_I" + ModuleShieldGeneratorII -> "MODULE_SHIELD_GENERATOR_II" + } +} + +pub fn parse(module_symbol_str: String) -> Result(ModuleSymbol, ModuleSymbol) { + case module_symbol_str { + "MODULE_MINERAL_PROCESSOR_I" -> Ok(ModuleMineralProcessorI) + "MODULE_GAS_PROCESSOR_I" -> Ok(ModuleGasProcessorI) + "MODULE_CARGO_HOLD_I" -> Ok(ModuleCargoHoldI) + "MODULE_CARGO_HOLD_II" -> Ok(ModuleCargoHoldII) + "MODULE_CARGO_HOLD_III" -> Ok(ModuleCargoHoldIII) + "MODULE_CREW_QUARTERS_I" -> Ok(ModuleCrewQuartersI) + "MODULE_ENVOY_QUARTERS_I" -> Ok(ModuleEnvoyQuartersI) + "MODULE_PASSENGER_CABIN_I" -> Ok(ModulePassengerCabinI) + "MODULE_MICRO_REFINERY_I" -> Ok(ModuleMicroRefineryI) + "MODULE_ORE_REFINERY_I" -> Ok(ModuleOreRefineryI) + "MODULE_FUEL_REFINERY_I" -> Ok(ModuleFuelRefineryI) + "MODULE_SCIENCE_LAB_I" -> Ok(ModuleScienceLabI) + "MODULE_JUMP_DRIVE_I" -> Ok(ModuleJumpDriveI) + "MODULE_JUMP_DRIVE_II" -> Ok(ModuleJumpDriveII) + "MODULE_JUMP_DRIVE_III" -> Ok(ModuleJumpDriveIII) + "MODULE_WARP_DRIVE_I" -> Ok(ModuleWarpDriveI) + "MODULE_WARP_DRIVE_II" -> Ok(ModuleWarpDriveII) + "MODULE_WARP_DRIVE_III" -> Ok(ModuleWarpDriveIII) + "MODULE_SHIELD_GENERATOR_I" -> Ok(ModuleShieldGeneratorI) + "MODULE_SHIELD_GENERATOR_II" -> Ok(ModuleShieldGeneratorII) + _ -> Error(ModuleMineralProcessorI) + } +} + +pub fn decoder() -> Decoder(ModuleSymbol) { + decode_utils.enum_decoder(parse, "ModuleSymbol") +} diff --git a/src/models/mount_deposit.gleam b/src/models/mount_deposit.gleam new file mode 100644 index 0000000..53aa879 --- /dev/null +++ b/src/models/mount_deposit.gleam @@ -0,0 +1,62 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type MountDeposit { + QuartzSand + SiliconCrystals + PreciousStones + IceWater + AmmoniaIce + IronOre + CopperOre + SilverOre + AluminumOre + GoldOre + PlatinumOre + Diamonds + UraniteOre + MeritiumOre +} + +pub fn to_string(mount_deposit: MountDeposit) -> String { + case mount_deposit { + QuartzSand -> "QUARTZ_SAND" + SiliconCrystals -> "SILICON_CRYSTALS" + PreciousStones -> "PRECIOUS_STONES" + IceWater -> "ICE_WATER" + AmmoniaIce -> "AMMONIA_ICE" + IronOre -> "IRON_ORE" + CopperOre -> "COPPER_ORE" + SilverOre -> "SILVER_ORE" + AluminumOre -> "ALUMINUM_ORE" + GoldOre -> "GOLD_ORE" + PlatinumOre -> "PLATINUM_ORE" + Diamonds -> "DIAMONDS" + UraniteOre -> "URANITE_ORE" + MeritiumOre -> "MERITIUM_ORE" + } +} + +pub fn parse(mount_deposit_str: String) -> Result(MountDeposit, MountDeposit) { + case mount_deposit_str { + "QUARTZ_SAND" -> Ok(QuartzSand) + "SILICON_CRYSTALS" -> Ok(SiliconCrystals) + "PRECIOUS_STONES" -> Ok(PreciousStones) + "ICE_WATER" -> Ok(IceWater) + "AMMONIA_ICE" -> Ok(AmmoniaIce) + "IRON_ORE" -> Ok(IronOre) + "COPPER_ORE" -> Ok(CopperOre) + "SILVER_ORE" -> Ok(SilverOre) + "ALUMINUM_ORE" -> Ok(AluminumOre) + "GOLD_ORE" -> Ok(GoldOre) + "PLATINUM_ORE" -> Ok(PlatinumOre) + "DIAMONDS" -> Ok(Diamonds) + "URANITE_ORE" -> Ok(UraniteOre) + "MERITIUM_ORE" -> Ok(MeritiumOre) + _ -> Error(QuartzSand) + } +} + +pub fn decoder() -> Decoder(MountDeposit) { + decode_utils.enum_decoder(parse, "MountDeposit") +} diff --git a/src/models/mount_symbol.gleam b/src/models/mount_symbol.gleam new file mode 100644 index 0000000..b948d70 --- /dev/null +++ b/src/models/mount_symbol.gleam @@ -0,0 +1,65 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type MountSymbol { + MountGasSiphonI + MountGasSiphonII + MountGasSiphonIII + MountSurveyorI + MountSurveyorII + MountSurveyorIII + MountSensorArrayI + MountSensorArrayII + MountSensorArrayIII + MountMiningLaserI + MountMiningLaserII + MountMiningLaserIII + MountLaserCannonI + MountMissileLauncherI + MountTurretI +} + +pub fn to_string(mount_symbol: MountSymbol) -> String { + case mount_symbol { + MountGasSiphonI -> "MOUNT_GAS_SIPHON_I" + MountGasSiphonII -> "MOUNT_GAS_SIPHON_II" + MountGasSiphonIII -> "MOUNT_GAS_SIPHON_III" + MountSurveyorI -> "MOUNT_SURVEYOR_I" + MountSurveyorII -> "MOUNT_SURVEYOR_II" + MountSurveyorIII -> "MOUNT_SURVEYOR_III" + MountSensorArrayI -> "MOUNT_SENSOR_ARRAY_I" + MountSensorArrayII -> "MOUNT_SENSOR_ARRAY_II" + MountSensorArrayIII -> "MOUNT_SENSOR_ARRAY_III" + MountMiningLaserI -> "MOUNT_MINING_LASER_I" + MountMiningLaserII -> "MOUNT_MINING_LASER_II" + MountMiningLaserIII -> "MOUNT_MINING_LASER_III" + MountLaserCannonI -> "MOUNT_LASER_CANNON_I" + MountMissileLauncherI -> "MOUNT_MISSILE_LAUNCHER_I" + MountTurretI -> "MOUNT_TURRET_I" + } +} + +pub fn parse(mount_symbol_str: String) -> Result(MountSymbol, MountSymbol) { + case mount_symbol_str { + "MOUNT_GAS_SIPHON_I" -> Ok(MountGasSiphonI) + "MOUNT_GAS_SIPHON_II" -> Ok(MountGasSiphonII) + "MOUNT_GAS_SIPHON_III" -> Ok(MountGasSiphonIII) + "MOUNT_SURVEYOR_I" -> Ok(MountSurveyorI) + "MOUNT_SURVEYOR_II" -> Ok(MountSurveyorII) + "MOUNT_SURVEYOR_III" -> Ok(MountSurveyorIII) + "MOUNT_SENSOR_ARRAY_I" -> Ok(MountSensorArrayI) + "MOUNT_SENSOR_ARRAY_II" -> Ok(MountSensorArrayII) + "MOUNT_SENSOR_ARRAY_III" -> Ok(MountSensorArrayIII) + "MOUNT_MINING_LASER_I" -> Ok(MountMiningLaserI) + "MOUNT_MINING_LASER_II" -> Ok(MountMiningLaserII) + "MOUNT_MINING_LASER_III" -> Ok(MountMiningLaserIII) + "MOUNT_LASER_CANNON_I" -> Ok(MountLaserCannonI) + "MOUNT_MISSILE_LAUNCHER_I" -> Ok(MountMissileLauncherI) + "MOUNT_TURRET_I" -> Ok(MountTurretI) + _ -> Error(MountGasSiphonI) + } +} + +pub fn decoder() -> Decoder(MountSymbol) { + decode_utils.enum_decoder(parse, "MountSymbol") +} diff --git a/src/models/public_agent.gleam b/src/models/public_agent.gleam new file mode 100644 index 0000000..64090e5 --- /dev/null +++ b/src/models/public_agent.gleam @@ -0,0 +1,26 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type PublicAgent { + PublicAgent( + symbol: String, + headquarters: String, + credits: Int, + starting_faction: String, + ship_count: Int, + ) +} + +pub fn decoder() -> Decoder(PublicAgent) { + use symbol <- decode.field("symbol", decode.string) + use headquarters <- decode.field("headquarters", decode.string) + use credits <- decode.field("credits", decode.int) + use starting_faction <- decode.field("startingFaction", decode.string) + use ship_count <- decode.field("shipCount", decode.int) + decode.success(PublicAgent( + symbol:, + headquarters:, + credits:, + starting_faction:, + ship_count:, + )) +} diff --git a/src/models/reactor_symbol.gleam b/src/models/reactor_symbol.gleam new file mode 100644 index 0000000..48903a4 --- /dev/null +++ b/src/models/reactor_symbol.gleam @@ -0,0 +1,35 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ReactorSymbol { + ReactorSolarI + ReactorFusionI + ReactorFissionI + ReactorChemicalI + ReactorAntimatterI +} + +pub fn to_string(reactor_symbol: ReactorSymbol) -> String { + case reactor_symbol { + ReactorSolarI -> "REACTOR_SOLAR_I" + ReactorFusionI -> "REACTOR_FUSION_I" + ReactorFissionI -> "REACTOR_FISSION_I" + ReactorChemicalI -> "REACTOR_CHEMICAL_I" + ReactorAntimatterI -> "REACTOR_ANTIMATTER_I" + } +} + +pub fn parse(reactor_symbol_str: String) -> Result(ReactorSymbol, ReactorSymbol) { + case reactor_symbol_str { + "REACTOR_SOLAR_I" -> Ok(ReactorSolarI) + "REACTOR_FUSION_I" -> Ok(ReactorFusionI) + "REACTOR_FISSION_I" -> Ok(ReactorFissionI) + "REACTOR_CHEMICAL_I" -> Ok(ReactorChemicalI) + "REACTOR_ANTIMATTER_I" -> Ok(ReactorAntimatterI) + _ -> Error(ReactorSolarI) + } +} + +pub fn decoder() -> Decoder(ReactorSymbol) { + decode_utils.enum_decoder(parse, "ReactorSymbol") +} diff --git a/src/models/refinement_produce.gleam b/src/models/refinement_produce.gleam new file mode 100644 index 0000000..510b54d --- /dev/null +++ b/src/models/refinement_produce.gleam @@ -0,0 +1,49 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type RefinementProduce { + Iron + Copper + Silver + Gold + Aluminum + Platinum + Uranite + Meritium + Fuel +} + +pub fn to_string(refinement_produce: RefinementProduce) -> String { + case refinement_produce { + Iron -> "IRON" + Copper -> "COPPER" + Silver -> "SILVER" + Gold -> "GOLD" + Aluminum -> "ALUMINUM" + Platinum -> "PLATINUM" + Uranite -> "URANITE" + Meritium -> "MERITIUM" + Fuel -> "FUEL" + } +} + +pub fn parse( + refinement_produce_str: String, +) -> Result(RefinementProduce, RefinementProduce) { + case refinement_produce_str { + "IRON" -> Ok(Iron) + "COPPER" -> Ok(Copper) + "SILVER" -> Ok(Silver) + "GOLD" -> Ok(Gold) + "ALUMINUM" -> Ok(Aluminum) + "PLATINUM" -> Ok(Platinum) + "URANITE" -> Ok(Uranite) + "MERITIUM" -> Ok(Meritium) + "FUEL" -> Ok(Fuel) + _ -> Error(Iron) + } +} + +pub fn decoder() -> Decoder(RefinementProduce) { + decode_utils.enum_decoder(parse, "RefinementProduce") +} diff --git a/src/models/refinement_yield.gleam b/src/models/refinement_yield.gleam new file mode 100644 index 0000000..1b2d89a --- /dev/null +++ b/src/models/refinement_yield.gleam @@ -0,0 +1,12 @@ +import gleam/dynamic/decode.{type Decoder} +import models/trade_symbol.{type TradeSymbol} + +pub type RefinementYield { + RefinementYield(trade_symbol: TradeSymbol, units: Int) +} + +pub fn decoder() -> Decoder(RefinementYield) { + use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder()) + use units <- decode.field("units", decode.int) + decode.success(RefinementYield(trade_symbol:, units:)) +} diff --git a/src/models/repair_transaction.gleam b/src/models/repair_transaction.gleam new file mode 100644 index 0000000..121b85f --- /dev/null +++ b/src/models/repair_transaction.gleam @@ -0,0 +1,28 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_symbol.{type ShipSymbol} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type RepairTransaction { + RepairTransaction( + waypoint_symbol: WaypointSymbol, + ship_symbol: ShipSymbol, + total_price: Int, + timestamp: String, + ) +} + +pub fn decoder() -> Decoder(RepairTransaction) { + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) + use total_price <- decode.field("totalPrice", decode.int) + use timestamp <- decode.field("timestamp", decode.string) + decode.success(RepairTransaction( + waypoint_symbol:, + ship_symbol:, + total_price:, + timestamp:, + )) +} diff --git a/src/models/scanned_ship.gleam b/src/models/scanned_ship.gleam new file mode 100644 index 0000000..11f693a --- /dev/null +++ b/src/models/scanned_ship.gleam @@ -0,0 +1,50 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/scanned_ship_engine.{type ScannedShipEngine} +import models/scanned_ship_frame.{type ScannedShipFrame} +import models/scanned_ship_mount.{type ScannedShipMount} +import models/scanned_ship_reactor.{type ScannedShipReactor} +import models/ship_nav.{type ShipNav} +import models/ship_registration.{type ShipRegistration} +import models/ship_symbol.{type ShipSymbol} +import utils/decode as decode_utils + +pub type ScannedShip { + ScannedShip( + symbol: ShipSymbol, + registration: ShipRegistration, + nav: ShipNav, + frame: Option(ScannedShipFrame), + reactor: Option(ScannedShipReactor), + engine: ScannedShipEngine, + mounts: Option(List(ScannedShipMount)), + ) +} + +pub fn decoder() -> Decoder(ScannedShip) { + use symbol <- decode.field("symbol", decode.string) + use registration <- decode.field("registration", ship_registration.decoder()) + use nav <- decode.field("nav", ship_nav.decoder()) + use frame <- decode_utils.field_key_value_optional( + "frame", + scanned_ship_frame.decoder(), + ) + use reactor <- decode_utils.field_key_value_optional( + "reactor", + scanned_ship_reactor.decoder(), + ) + use engine <- decode.field("engine", scanned_ship_engine.decoder()) + use mounts <- decode_utils.field_key_value_optional( + "mounts", + decode.list(scanned_ship_mount.decoder()), + ) + decode.success(ScannedShip( + symbol:, + registration:, + nav:, + frame:, + reactor:, + engine:, + mounts:, + )) +} diff --git a/src/models/scanned_ship_engine.gleam b/src/models/scanned_ship_engine.gleam new file mode 100644 index 0000000..33a745a --- /dev/null +++ b/src/models/scanned_ship_engine.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} +import models/engine_symbol.{type EngineSymbol} + +pub type ScannedShipEngine { + ScannedShipEngine(symbol: EngineSymbol) +} + +pub fn decoder() -> Decoder(ScannedShipEngine) { + use symbol <- decode.field("symbol", engine_symbol.decoder()) + decode.success(ScannedShipEngine(symbol:)) +} diff --git a/src/models/scanned_ship_frame.gleam b/src/models/scanned_ship_frame.gleam new file mode 100644 index 0000000..c01c6d2 --- /dev/null +++ b/src/models/scanned_ship_frame.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} +import models/frame_symbol.{type FrameSymbol} + +pub type ScannedShipFrame { + ScannedShipFrame(symbol: FrameSymbol) +} + +pub fn decoder() -> Decoder(ScannedShipFrame) { + use symbol <- decode.field("symbol", frame_symbol.decoder()) + decode.success(ScannedShipFrame(symbol:)) +} diff --git a/src/models/scanned_ship_mount.gleam b/src/models/scanned_ship_mount.gleam new file mode 100644 index 0000000..431325d --- /dev/null +++ b/src/models/scanned_ship_mount.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} +import models/mount_symbol.{type MountSymbol} + +pub type ScannedShipMount { + ScannedShipMount(symbol: MountSymbol) +} + +pub fn decoder() -> Decoder(ScannedShipMount) { + use symbol <- decode.field("symbol", mount_symbol.decoder()) + decode.success(ScannedShipMount(symbol:)) +} diff --git a/src/models/scanned_ship_reactor.gleam b/src/models/scanned_ship_reactor.gleam new file mode 100644 index 0000000..dd037f5 --- /dev/null +++ b/src/models/scanned_ship_reactor.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} +import models/reactor_symbol.{type ReactorSymbol} + +pub type ScannedShipReactor { + ScannedShipReactor(symbol: ReactorSymbol) +} + +pub fn decoder() -> Decoder(ScannedShipReactor) { + use symbol <- decode.field("symbol", reactor_symbol.decoder()) + decode.success(ScannedShipReactor(symbol:)) +} diff --git a/src/models/scanned_system.gleam b/src/models/scanned_system.gleam new file mode 100644 index 0000000..a6ad9a3 --- /dev/null +++ b/src/models/scanned_system.gleam @@ -0,0 +1,31 @@ +import gleam/dynamic/decode.{type Decoder} +import models/system_symbol.{type SystemSymbol} +import models/system_type.{type SystemType} + +pub type ScannedSystem { + ScannedSystem( + symbol: SystemSymbol, + sector_symbol: String, + type_: SystemType, + x: Int, + y: Int, + distance: Int, + ) +} + +pub fn decoder() -> Decoder(ScannedSystem) { + use symbol <- decode.field("symbol", decode.string) + use sector_symbol <- decode.field("sectorSymbol", decode.string) + use type_ <- decode.field("type", system_type.decoder()) + use x <- decode.field("x", decode.int) + use y <- decode.field("y", decode.int) + use distance <- decode.field("distance", decode.int) + decode.success(ScannedSystem( + symbol:, + sector_symbol:, + type_:, + x:, + y:, + distance:, + )) +} diff --git a/src/models/scanned_waypoint.gleam b/src/models/scanned_waypoint.gleam new file mode 100644 index 0000000..ccb1b27 --- /dev/null +++ b/src/models/scanned_waypoint.gleam @@ -0,0 +1,57 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/chart.{type Chart} +import models/system_symbol.{type SystemSymbol} +import models/waypoint_faction.{type WaypointFaction} +import models/waypoint_orbital.{type WaypointOrbital} +import models/waypoint_symbol.{type WaypointSymbol} +import models/waypoint_trait.{type WaypointTrait} +import models/waypoint_type.{type WaypointType} + +pub type ScannedWaypoint { + ScannedWaypoint( + symbol: WaypointSymbol, + type_: WaypointType, + system_symbol: SystemSymbol, + x: Int, + y: Int, + orbitals: List(WaypointOrbital), + faction: Option(WaypointFaction), + traits: List(WaypointTrait), + chart: Option(Chart), + ) +} + +pub fn decoder() -> Decoder(ScannedWaypoint) { + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) + use type_ <- decode.field("type", waypoint_type.decoder()) + use system_symbol <- decode.field("systemSymbol", system_symbol.decoder()) + use x <- decode.field("x", decode.int) + use y <- decode.field("y", decode.int) + use orbitals <- decode.field( + "orbitals", + decode.list(waypoint_orbital.decoder()), + ) + use faction <- decode.optional_field( + "faction", + option.None, + decode.optional(waypoint_faction.decoder()), + ) + use traits <- decode.field("traits", decode.list(waypoint_trait.decoder())) + use chart <- decode.optional_field( + "chart", + option.None, + decode.optional(chart.decoder()), + ) + decode.success(ScannedWaypoint( + symbol:, + type_:, + system_symbol:, + x:, + y:, + orbitals:, + faction:, + traits:, + chart:, + )) +} diff --git a/src/models/scrap_transaction.gleam b/src/models/scrap_transaction.gleam new file mode 100644 index 0000000..39b85c5 --- /dev/null +++ b/src/models/scrap_transaction.gleam @@ -0,0 +1,28 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_symbol.{type ShipSymbol} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type ScrapTransaction { + ScrapTransaction( + waypoint_symbol: WaypointSymbol, + ship_symbol: ShipSymbol, + total_price: Int, + timestamp: String, + ) +} + +pub fn decoder() -> Decoder(ScrapTransaction) { + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) + use total_price <- decode.field("totalPrice", decode.int) + use timestamp <- decode.field("timestamp", decode.string) + decode.success(ScrapTransaction( + waypoint_symbol:, + ship_symbol:, + total_price:, + timestamp:, + )) +} diff --git a/src/models/ship.gleam b/src/models/ship.gleam new file mode 100644 index 0000000..5c8b085 --- /dev/null +++ b/src/models/ship.gleam @@ -0,0 +1,59 @@ +import gleam/dynamic/decode.{type Decoder} +import models/cooldown.{type Cooldown} +import models/ship_cargo.{type ShipCargo} +import models/ship_crew.{type ShipCrew} +import models/ship_engine.{type ShipEngine} +import models/ship_frame.{type ShipFrame} +import models/ship_fuel.{type ShipFuel} +import models/ship_module.{type ShipModule} +import models/ship_mount.{type ShipMount} +import models/ship_nav.{type ShipNav} +import models/ship_reactor.{type ShipReactor} +import models/ship_registration.{type ShipRegistration} +import models/ship_symbol.{type ShipSymbol} + +pub type Ship { + Ship( + symbol: ShipSymbol, + registration: ShipRegistration, + nav: ShipNav, + crew: ShipCrew, + frame: ShipFrame, + reactor: ShipReactor, + engine: ShipEngine, + modules: List(ShipModule), + mounts: List(ShipMount), + cargo: ShipCargo, + cooldown: Cooldown, + fuel: ShipFuel, + ) +} + +pub fn decoder() -> Decoder(Ship) { + use symbol <- decode.field("symbol", decode.string) + use registration <- decode.field("registration", ship_registration.decoder()) + use nav <- decode.field("nav", ship_nav.decoder()) + use crew <- decode.field("crew", ship_crew.decoder()) + use frame <- decode.field("frame", ship_frame.decoder()) + use reactor <- decode.field("reactor", ship_reactor.decoder()) + use engine <- decode.field("engine", ship_engine.decoder()) + use modules <- decode.field("modules", decode.list(ship_module.decoder())) + use mounts <- decode.field("mounts", decode.list(ship_mount.decoder())) + use cargo <- decode.field("cargo", ship_cargo.decoder()) + use cooldown <- decode.field("cooldown", cooldown.decoder()) + use fuel <- decode.field("fuel", ship_fuel.decoder()) + decode.success(Ship( + symbol:, + registration:, + nav:, + crew:, + frame:, + reactor:, + engine:, + modules:, + mounts:, + cargo:, + cooldown:, + fuel:, + )) +} diff --git a/src/models/ship_cargo.gleam b/src/models/ship_cargo.gleam new file mode 100644 index 0000000..04e6c04 --- /dev/null +++ b/src/models/ship_cargo.gleam @@ -0,0 +1,16 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_cargo_item.{type ShipCargoItem} + +pub type ShipCargo { + ShipCargo(capacity: Int, units: Int, inventory: List(ShipCargoItem)) +} + +pub fn decoder() -> Decoder(ShipCargo) { + use capacity <- decode.field("capacity", decode.int) + use units <- decode.field("units", decode.int) + use inventory <- decode.field( + "inventory", + decode.list(ship_cargo_item.decoder()), + ) + decode.success(ShipCargo(capacity:, units:, inventory:)) +} diff --git a/src/models/ship_cargo_item.gleam b/src/models/ship_cargo_item.gleam new file mode 100644 index 0000000..9ad4433 --- /dev/null +++ b/src/models/ship_cargo_item.gleam @@ -0,0 +1,19 @@ +import gleam/dynamic/decode.{type Decoder} +import models/trade_symbol.{type TradeSymbol} + +pub type ShipCargoItem { + ShipCargoItem( + symbol: TradeSymbol, + name: String, + description: String, + units: Int, + ) +} + +pub fn decoder() -> Decoder(ShipCargoItem) { + use symbol <- decode.field("symbol", trade_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + use units <- decode.field("units", decode.int) + decode.success(ShipCargoItem(symbol:, name:, description:, units:)) +} diff --git a/src/models/ship_component.gleam b/src/models/ship_component.gleam new file mode 100644 index 0000000..32cb697 --- /dev/null +++ b/src/models/ship_component.gleam @@ -0,0 +1,29 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ShipComponent { + Frame + Reactor + Engine +} + +pub fn to_string(ship_component: ShipComponent) -> String { + case ship_component { + Frame -> "FRAME" + Reactor -> "REACTOR" + Engine -> "ENGINE" + } +} + +pub fn parse(ship_component_str: String) -> Result(ShipComponent, ShipComponent) { + case ship_component_str { + "FRAME" -> Ok(Frame) + "REACTOR" -> Ok(Reactor) + "ENGINE" -> Ok(Engine) + _ -> Error(Frame) + } +} + +pub fn decoder() -> Decoder(ShipComponent) { + decode_utils.enum_decoder(parse, "ShipComponent") +} diff --git a/src/models/ship_component_condition.gleam b/src/models/ship_component_condition.gleam new file mode 100644 index 0000000..2b72921 --- /dev/null +++ b/src/models/ship_component_condition.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ShipComponentCondition = + Float + +pub fn decoder() -> Decoder(ShipComponentCondition) { + decode.float +} diff --git a/src/models/ship_component_integrity.gleam b/src/models/ship_component_integrity.gleam new file mode 100644 index 0000000..d909bc5 --- /dev/null +++ b/src/models/ship_component_integrity.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ShipComponentIntegrity = + Float + +pub fn decoder() -> Decoder(ShipComponentIntegrity) { + decode.float +} diff --git a/src/models/ship_component_quality.gleam b/src/models/ship_component_quality.gleam new file mode 100644 index 0000000..c8f7ea5 --- /dev/null +++ b/src/models/ship_component_quality.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ShipComponentQuality = + Float + +pub fn decoder() -> Decoder(ShipComponentQuality) { + decode.float +} diff --git a/src/models/ship_condition_event.gleam b/src/models/ship_condition_event.gleam new file mode 100644 index 0000000..3fee1fb --- /dev/null +++ b/src/models/ship_condition_event.gleam @@ -0,0 +1,20 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_component.{type ShipComponent} +import models/ship_condition_event_symbol.{type ShipConditionEventSymbol} + +pub type ShipConditionEvent { + ShipConditionEvent( + symbol: ShipConditionEventSymbol, + component: ShipComponent, + name: String, + description: String, + ) +} + +pub fn decoder() -> Decoder(ShipConditionEvent) { + use symbol <- decode.field("symbol", ship_condition_event_symbol.decoder()) + use component <- decode.field("component", ship_component.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + decode.success(ShipConditionEvent(symbol:, component:, name:, description:)) +} diff --git a/src/models/ship_condition_event_symbol.gleam b/src/models/ship_condition_event_symbol.gleam new file mode 100644 index 0000000..4788d13 --- /dev/null +++ b/src/models/ship_condition_event_symbol.gleam @@ -0,0 +1,105 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ShipConditionEventSymbol { + ReactorOverload + EnergySpikeFromMineral + SolarFlareInterference + CoolantLeak + PowerDistributionFluctuation + MagneticFieldDisruption + HullMicrometeoriteStrikes + StructuralStressFractures + CorrosiveMineralContamination + ThermalExpansionMismatch + VibrationDamageFromDrilling + ElectromagneticFieldInterference + ImpactWithExtractedDebris + FuelEfficiencyDegradation + CoolantSystemAgeing + DustMicroabrasions + ThrusterNozzleWear + ExhaustPortClogging + BearingLubricationFade + SensorCalibrationDrift + HullMicrometeoriteDamage + SpaceDebrisCollision + ThermalStress + VibrationOverload + PressureDifferentialStress + ElectromagneticSurgeEffects + AtmosphericEntryHeat +} + +pub fn to_string( + ship_condition_event_symbol: ShipConditionEventSymbol, +) -> String { + case ship_condition_event_symbol { + ReactorOverload -> "REACTOR_OVERLOAD" + EnergySpikeFromMineral -> "ENERGY_SPIKE_FROM_MINERAL" + SolarFlareInterference -> "SOLAR_FLARE_INTERFERENCE" + CoolantLeak -> "COOLANT_LEAK" + PowerDistributionFluctuation -> "POWER_DISTRIBUTION_FLUCTUATION" + MagneticFieldDisruption -> "MAGNETIC_FIELD_DISRUPTION" + HullMicrometeoriteStrikes -> "HULL_MICROMETEORITE_STRIKES" + StructuralStressFractures -> "STRUCTURAL_STRESS_FRACTURES" + CorrosiveMineralContamination -> "CORROSIVE_MINERAL_CONTAMINATION" + ThermalExpansionMismatch -> "THERMAL_EXPANSION_MISMATCH" + VibrationDamageFromDrilling -> "VIBRATION_DAMAGE_FROM_DRILLING" + ElectromagneticFieldInterference -> "ELECTROMAGNETIC_FIELD_INTERFERENCE" + ImpactWithExtractedDebris -> "IMPACT_WITH_EXTRACTED_DEBRIS" + FuelEfficiencyDegradation -> "FUEL_EFFICIENCY_DEGRADATION" + CoolantSystemAgeing -> "COOLANT_SYSTEM_AGEING" + DustMicroabrasions -> "DUST_MICROABRASIONS" + ThrusterNozzleWear -> "THRUSTER_NOZZLE_WEAR" + ExhaustPortClogging -> "EXHAUST_PORT_CLOGGING" + BearingLubricationFade -> "BEARING_LUBRICATION_FADE" + SensorCalibrationDrift -> "SENSOR_CALIBRATION_DRIFT" + HullMicrometeoriteDamage -> "HULL_MICROMETEORITE_DAMAGE" + SpaceDebrisCollision -> "SPACE_DEBRIS_COLLISION" + ThermalStress -> "THERMAL_STRESS" + VibrationOverload -> "VIBRATION_OVERLOAD" + PressureDifferentialStress -> "PRESSURE_DIFFERENTIAL_STRESS" + ElectromagneticSurgeEffects -> "ELECTROMAGNETIC_SURGE_EFFECTS" + AtmosphericEntryHeat -> "ATMOSPHERIC_ENTRY_HEAT" + } +} + +pub fn parse( + ship_condition_event_symbol_str: String, +) -> Result(ShipConditionEventSymbol, ShipConditionEventSymbol) { + case ship_condition_event_symbol_str { + "REACTOR_OVERLOAD" -> Ok(ReactorOverload) + "ENERGY_SPIKE_FROM_MINERAL" -> Ok(EnergySpikeFromMineral) + "SOLAR_FLARE_INTERFERENCE" -> Ok(SolarFlareInterference) + "COOLANT_LEAK" -> Ok(CoolantLeak) + "POWER_DISTRIBUTION_FLUCTUATION" -> Ok(PowerDistributionFluctuation) + "MAGNETIC_FIELD_DISRUPTION" -> Ok(MagneticFieldDisruption) + "HULL_MICROMETEORITE_STRIKES" -> Ok(HullMicrometeoriteStrikes) + "STRUCTURAL_STRESS_FRACTURES" -> Ok(StructuralStressFractures) + "CORROSIVE_MINERAL_CONTAMINATION" -> Ok(CorrosiveMineralContamination) + "THERMAL_EXPANSION_MISMATCH" -> Ok(ThermalExpansionMismatch) + "VIBRATION_DAMAGE_FROM_DRILLING" -> Ok(VibrationDamageFromDrilling) + "ELECTROMAGNETIC_FIELD_INTERFERENCE" -> Ok(ElectromagneticFieldInterference) + "IMPACT_WITH_EXTRACTED_DEBRIS" -> Ok(ImpactWithExtractedDebris) + "FUEL_EFFICIENCY_DEGRADATION" -> Ok(FuelEfficiencyDegradation) + "COOLANT_SYSTEM_AGEING" -> Ok(CoolantSystemAgeing) + "DUST_MICROABRASIONS" -> Ok(DustMicroabrasions) + "THRUSTER_NOZZLE_WEAR" -> Ok(ThrusterNozzleWear) + "EXHAUST_PORT_CLOGGING" -> Ok(ExhaustPortClogging) + "BEARING_LUBRICATION_FADE" -> Ok(BearingLubricationFade) + "SENSOR_CALIBRATION_DRIFT" -> Ok(SensorCalibrationDrift) + "HULL_MICROMETEORITE_DAMAGE" -> Ok(HullMicrometeoriteDamage) + "SPACE_DEBRIS_COLLISION" -> Ok(SpaceDebrisCollision) + "THERMAL_STRESS" -> Ok(ThermalStress) + "VIBRATION_OVERLOAD" -> Ok(VibrationOverload) + "PRESSURE_DIFFERENTIAL_STRESS" -> Ok(PressureDifferentialStress) + "ELECTROMAGNETIC_SURGE_EFFECTS" -> Ok(ElectromagneticSurgeEffects) + "ATMOSPHERIC_ENTRY_HEAT" -> Ok(AtmosphericEntryHeat) + _ -> Error(ReactorOverload) + } +} + +pub fn decoder() -> Decoder(ShipConditionEventSymbol) { + decode_utils.enum_decoder(parse, "ShipConditionEventSymbol") +} diff --git a/src/models/ship_crew.gleam b/src/models/ship_crew.gleam new file mode 100644 index 0000000..889d6e0 --- /dev/null +++ b/src/models/ship_crew.gleam @@ -0,0 +1,30 @@ +import gleam/dynamic/decode.{type Decoder} +import models/crew_rotation.{type CrewRotation} + +pub type ShipCrew { + ShipCrew( + current: Int, + required: Int, + capacity: Int, + rotation: CrewRotation, + morale: Int, + wages: Int, + ) +} + +pub fn decoder() -> Decoder(ShipCrew) { + use current <- decode.field("current", decode.int) + use required <- decode.field("required", decode.int) + use capacity <- decode.field("capacity", decode.int) + use rotation <- decode.field("rotation", crew_rotation.decoder()) + use morale <- decode.field("morale", decode.int) + use wages <- decode.field("wages", decode.int) + decode.success(ShipCrew( + current: current, + required: required, + capacity: capacity, + rotation: rotation, + morale: morale, + wages: wages, + )) +} diff --git a/src/models/ship_engine.gleam b/src/models/ship_engine.gleam new file mode 100644 index 0000000..fbf5d28 --- /dev/null +++ b/src/models/ship_engine.gleam @@ -0,0 +1,40 @@ +import gleam/dynamic/decode.{type Decoder} +import models/engine_symbol.{type EngineSymbol} +import models/ship_component_condition.{type ShipComponentCondition} +import models/ship_component_integrity.{type ShipComponentIntegrity} +import models/ship_component_quality.{type ShipComponentQuality} +import models/ship_requirements.{type ShipRequirements} + +pub type ShipEngine { + ShipEngine( + symbol: EngineSymbol, + name: String, + condition: ShipComponentCondition, + integrity: ShipComponentIntegrity, + description: String, + speed: Int, + requirements: ShipRequirements, + quality: ShipComponentQuality, + ) +} + +pub fn decoder() -> Decoder(ShipEngine) { + use symbol <- decode.field("symbol", engine_symbol.decoder()) + use name <- decode.field("name", decode.string) + use condition <- decode.field("condition", ship_component_condition.decoder()) + use integrity <- decode.field("integrity", ship_component_integrity.decoder()) + use description <- decode.field("description", decode.string) + use speed <- decode.field("speed", decode.int) + use requirements <- decode.field("requirements", ship_requirements.decoder()) + use quality <- decode.field("quality", ship_component_quality.decoder()) + decode.success(ShipEngine( + symbol:, + name:, + condition:, + integrity:, + description:, + speed:, + requirements:, + quality:, + )) +} diff --git a/src/models/ship_frame.gleam b/src/models/ship_frame.gleam new file mode 100644 index 0000000..c4d6a9d --- /dev/null +++ b/src/models/ship_frame.gleam @@ -0,0 +1,46 @@ +import gleam/dynamic/decode.{type Decoder} +import models/frame_symbol.{type FrameSymbol} +import models/ship_component_condition.{type ShipComponentCondition} +import models/ship_component_integrity.{type ShipComponentIntegrity} +import models/ship_component_quality.{type ShipComponentQuality} +import models/ship_requirements.{type ShipRequirements} + +pub type ShipFrame { + ShipFrame( + symbol: FrameSymbol, + name: String, + condition: ShipComponentCondition, + integrity: ShipComponentIntegrity, + description: String, + module_slots: Int, + mounting_points: Int, + fuel_capacity: Int, + requirements: ShipRequirements, + quality: ShipComponentQuality, + ) +} + +pub fn decoder() -> Decoder(ShipFrame) { + use symbol <- decode.field("symbol", frame_symbol.decoder()) + use name <- decode.field("name", decode.string) + use condition <- decode.field("condition", ship_component_condition.decoder()) + use integrity <- decode.field("integrity", ship_component_integrity.decoder()) + use description <- decode.field("description", decode.string) + use module_slots <- decode.field("moduleSlots", decode.int) + use mounting_points <- decode.field("mountingPoints", decode.int) + use fuel_capacity <- decode.field("fuelCapacity", decode.int) + use requirements <- decode.field("requirements", ship_requirements.decoder()) + use quality <- decode.field("quality", ship_component_quality.decoder()) + decode.success(ShipFrame( + symbol:, + name:, + condition:, + integrity:, + description:, + module_slots:, + mounting_points:, + fuel_capacity:, + requirements:, + quality:, + )) +} diff --git a/src/models/ship_fuel.gleam b/src/models/ship_fuel.gleam new file mode 100644 index 0000000..784ca81 --- /dev/null +++ b/src/models/ship_fuel.gleam @@ -0,0 +1,18 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/ship_fuel_consumed.{type ShipFuelConsumed} +import utils/decode as decode_utils + +pub type ShipFuel { + ShipFuel(current: Int, capacity: Int, consumed: Option(ShipFuelConsumed)) +} + +pub fn decoder() -> Decoder(ShipFuel) { + use current <- decode.field("current", decode.int) + use capacity <- decode.field("capacity", decode.int) + use consumed <- decode_utils.field_key_value_optional( + "consumed", + ship_fuel_consumed.decoder(), + ) + decode.success(ShipFuel(current:, capacity:, consumed:)) +} diff --git a/src/models/ship_fuel_consumed.gleam b/src/models/ship_fuel_consumed.gleam new file mode 100644 index 0000000..673d019 --- /dev/null +++ b/src/models/ship_fuel_consumed.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ShipFuelConsumed { + ShipFuelConsumed(amount: Int, timestamp: String) +} + +pub fn decoder() -> Decoder(ShipFuelConsumed) { + use amount <- decode.field("amount", decode.int) + use timestamp <- decode.field("timestamp", decode.string) + decode.success(ShipFuelConsumed(amount:, timestamp:)) +} diff --git a/src/models/ship_modification_transaction.gleam b/src/models/ship_modification_transaction.gleam new file mode 100644 index 0000000..74bbd5c --- /dev/null +++ b/src/models/ship_modification_transaction.gleam @@ -0,0 +1,32 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_symbol.{type ShipSymbol} +import models/trade_symbol.{type TradeSymbol} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type ShipModificationTransaction { + ShipModificationTransaction( + waypoint_symbol: WaypointSymbol, + ship_symbol: ShipSymbol, + trade_symbol: TradeSymbol, + total_price: Int, + timestamp: String, + ) +} + +pub fn decoder() -> Decoder(ShipModificationTransaction) { + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) + use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder()) + use total_price <- decode.field("totalPrice", decode.int) + use timestamp <- decode.field("timestamp", decode.string) + decode.success(ShipModificationTransaction( + waypoint_symbol:, + ship_symbol:, + trade_symbol:, + total_price:, + timestamp:, + )) +} diff --git a/src/models/ship_module.gleam b/src/models/ship_module.gleam new file mode 100644 index 0000000..8ad1201 --- /dev/null +++ b/src/models/ship_module.gleam @@ -0,0 +1,33 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/module_symbol.{type ModuleSymbol} +import models/ship_requirements.{type ShipRequirements} +import utils/decode as decode_utils + +pub type ShipModule { + ShipModule( + symbol: ModuleSymbol, + name: String, + description: String, + capacity: Option(Int), + range: Option(Int), + requirements: ShipRequirements, + ) +} + +pub fn decoder() -> Decoder(ShipModule) { + use symbol <- decode.field("symbol", module_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + use capacity <- decode_utils.field_key_value_optional("capacity", decode.int) + use range <- decode_utils.field_key_value_optional("range", decode.int) + use requirements <- decode.field("requirements", ship_requirements.decoder()) + decode.success(ShipModule( + symbol:, + name:, + description:, + capacity:, + range:, + requirements:, + )) +} diff --git a/src/models/ship_mount.gleam b/src/models/ship_mount.gleam new file mode 100644 index 0000000..ee3afc3 --- /dev/null +++ b/src/models/ship_mount.gleam @@ -0,0 +1,37 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/mount_deposit.{type MountDeposit} +import models/mount_symbol.{type MountSymbol} +import models/ship_requirements.{type ShipRequirements} +import utils/decode as decode_utils + +pub type ShipMount { + ShipMount( + symbol: MountSymbol, + name: String, + description: String, + strength: Option(Int), + deposits: Option(List(MountDeposit)), + requirements: ShipRequirements, + ) +} + +pub fn decoder() -> Decoder(ShipMount) { + use symbol <- decode.field("symbol", mount_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + use strength <- decode_utils.field_key_value_optional("strength", decode.int) + use deposits <- decode_utils.field_key_value_optional( + "deposits", + decode.list(mount_deposit.decoder()), + ) + use requirements <- decode.field("requirements", ship_requirements.decoder()) + decode.success(ShipMount( + symbol:, + name:, + description:, + strength:, + deposits:, + requirements:, + )) +} diff --git a/src/models/ship_nav.gleam b/src/models/ship_nav.gleam new file mode 100644 index 0000000..6456d33 --- /dev/null +++ b/src/models/ship_nav.gleam @@ -0,0 +1,34 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_nav_flight_mode.{type ShipNavFlightMode} +import models/ship_nav_route.{type ShipNavRoute} +import models/ship_nav_status.{type ShipNavStatus} +import models/system_symbol.{type SystemSymbol} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type ShipNav { + ShipNav( + system_symbol: SystemSymbol, + waypoint_symbol: WaypointSymbol, + route: ShipNavRoute, + status: ShipNavStatus, + flight_mode: ShipNavFlightMode, + ) +} + +pub fn decoder() -> Decoder(ShipNav) { + use system_symbol <- decode.field("systemSymbol", system_symbol.decoder()) + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use route <- decode.field("route", ship_nav_route.decoder()) + use status <- decode.field("status", ship_nav_status.decoder()) + use flight_mode <- decode.field("flightMode", ship_nav_flight_mode.decoder()) + decode.success(ShipNav( + system_symbol:, + waypoint_symbol:, + route:, + status:, + flight_mode:, + )) +} diff --git a/src/models/ship_nav_flight_mode.gleam b/src/models/ship_nav_flight_mode.gleam new file mode 100644 index 0000000..f5281d3 --- /dev/null +++ b/src/models/ship_nav_flight_mode.gleam @@ -0,0 +1,34 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ShipNavFlightMode { + Drift + Stealth + Cruise + Burn +} + +pub fn to_string(ship_nav_flight_mode: ShipNavFlightMode) -> String { + case ship_nav_flight_mode { + Drift -> "DRIFT" + Stealth -> "STEALTH" + Cruise -> "CRUISE" + Burn -> "BURN" + } +} + +pub fn parse( + ship_nav_flight_mode_str: String, +) -> Result(ShipNavFlightMode, ShipNavFlightMode) { + case ship_nav_flight_mode_str { + "DRIFT" -> Ok(Drift) + "STEALTH" -> Ok(Stealth) + "CRUISE" -> Ok(Cruise) + "BURN" -> Ok(Burn) + _ -> Error(Drift) + } +} + +pub fn decoder() -> Decoder(ShipNavFlightMode) { + decode_utils.enum_decoder(parse, "ShipNavFlightMode") +} diff --git a/src/models/ship_nav_route.gleam b/src/models/ship_nav_route.gleam new file mode 100644 index 0000000..d94caa1 --- /dev/null +++ b/src/models/ship_nav_route.gleam @@ -0,0 +1,22 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_nav_route_waypoint.{type ShipNavRouteWaypoint} + +pub type ShipNavRoute { + ShipNavRoute( + destination: ShipNavRouteWaypoint, + origin: ShipNavRouteWaypoint, + departure_time: String, + arrival: String, + ) +} + +pub fn decoder() -> Decoder(ShipNavRoute) { + use destination <- decode.field( + "destination", + ship_nav_route_waypoint.decoder(), + ) + use origin <- decode.field("origin", ship_nav_route_waypoint.decoder()) + use departure_time <- decode.field("departureTime", decode.string) + use arrival <- decode.field("arrival", decode.string) + decode.success(ShipNavRoute(destination:, origin:, departure_time:, arrival:)) +} diff --git a/src/models/ship_nav_route_waypoint.gleam b/src/models/ship_nav_route_waypoint.gleam new file mode 100644 index 0000000..04bba3e --- /dev/null +++ b/src/models/ship_nav_route_waypoint.gleam @@ -0,0 +1,23 @@ +import gleam/dynamic/decode.{type Decoder} +import models/system_symbol.{type SystemSymbol} +import models/waypoint_symbol.{type WaypointSymbol} +import models/waypoint_type.{type WaypointType} + +pub type ShipNavRouteWaypoint { + ShipNavRouteWaypoint( + symbol: WaypointSymbol, + type_: WaypointType, + system_symbol: SystemSymbol, + x: Int, + y: Int, + ) +} + +pub fn decoder() -> Decoder(ShipNavRouteWaypoint) { + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) + use type_ <- decode.field("type", waypoint_type.decoder()) + use system_symbol <- decode.field("systemSymbol", system_symbol.decoder()) + use x <- decode.field("x", decode.int) + use y <- decode.field("y", decode.int) + decode.success(ShipNavRouteWaypoint(symbol:, type_:, system_symbol:, x:, y:)) +} diff --git a/src/models/ship_nav_status.gleam b/src/models/ship_nav_status.gleam new file mode 100644 index 0000000..ce8a274 --- /dev/null +++ b/src/models/ship_nav_status.gleam @@ -0,0 +1,31 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ShipNavStatus { + InTransit + InOrbit + Docked +} + +pub fn to_string(ship_nav_status: ShipNavStatus) -> String { + case ship_nav_status { + InTransit -> "IN_TRANSIT" + InOrbit -> "IN_ORBIT" + Docked -> "DOCKED" + } +} + +pub fn parse( + ship_nav_status_str: String, +) -> Result(ShipNavStatus, ShipNavStatus) { + case ship_nav_status_str { + "IN_TRANSIT" -> Ok(InTransit) + "IN_ORBIT" -> Ok(InOrbit) + "DOCKED" -> Ok(Docked) + _ -> Error(InTransit) + } +} + +pub fn decoder() -> Decoder(ShipNavStatus) { + decode_utils.enum_decoder(parse, "ShipNavStatus") +} diff --git a/src/models/ship_reactor.gleam b/src/models/ship_reactor.gleam new file mode 100644 index 0000000..e178c58 --- /dev/null +++ b/src/models/ship_reactor.gleam @@ -0,0 +1,40 @@ +import gleam/dynamic/decode.{type Decoder} +import models/reactor_symbol.{type ReactorSymbol} +import models/ship_component_condition.{type ShipComponentCondition} +import models/ship_component_integrity.{type ShipComponentIntegrity} +import models/ship_component_quality.{type ShipComponentQuality} +import models/ship_requirements.{type ShipRequirements} + +pub type ShipReactor { + ShipReactor( + symbol: ReactorSymbol, + name: String, + condition: ShipComponentCondition, + integrity: ShipComponentIntegrity, + description: String, + power_output: Int, + requirements: ShipRequirements, + quality: ShipComponentQuality, + ) +} + +pub fn decoder() -> Decoder(ShipReactor) { + use symbol <- decode.field("symbol", reactor_symbol.decoder()) + use name <- decode.field("name", decode.string) + use condition <- decode.field("condition", ship_component_condition.decoder()) + use integrity <- decode.field("integrity", ship_component_integrity.decoder()) + use description <- decode.field("description", decode.string) + use power_output <- decode.field("powerOutput", decode.int) + use requirements <- decode.field("requirements", ship_requirements.decoder()) + use quality <- decode.field("quality", ship_component_quality.decoder()) + decode.success(ShipReactor( + symbol:, + name:, + condition:, + integrity:, + description:, + power_output:, + requirements:, + quality:, + )) +} diff --git a/src/models/ship_registration.gleam b/src/models/ship_registration.gleam new file mode 100644 index 0000000..c0a47f5 --- /dev/null +++ b/src/models/ship_registration.gleam @@ -0,0 +1,14 @@ +import gleam/dynamic/decode.{type Decoder} +import models/faction_symbol.{type FactionSymbol} +import models/ship_role.{type ShipRole} + +pub type ShipRegistration { + ShipRegistration(name: String, faction_symbol: FactionSymbol, role: ShipRole) +} + +pub fn decoder() -> Decoder(ShipRegistration) { + use name <- decode.field("name", decode.string) + use faction_symbol <- decode.field("factionSymbol", faction_symbol.decoder()) + use role <- decode.field("role", ship_role.decoder()) + decode.success(ShipRegistration(name:, faction_symbol:, role:)) +} diff --git a/src/models/ship_requirements.gleam b/src/models/ship_requirements.gleam new file mode 100644 index 0000000..3b2326b --- /dev/null +++ b/src/models/ship_requirements.gleam @@ -0,0 +1,14 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import utils/decode as decode_utils + +pub type ShipRequirements { + ShipRequirements(power: Option(Int), crew: Option(Int), slots: Option(Int)) +} + +pub fn decoder() -> Decoder(ShipRequirements) { + use power <- decode_utils.field_key_value_optional("power", decode.int) + use crew <- decode_utils.field_key_value_optional("crew", decode.int) + use slots <- decode_utils.field_key_value_optional("slots", decode.int) + decode.success(ShipRequirements(power:, crew:, slots:)) +} diff --git a/src/models/ship_role.gleam b/src/models/ship_role.gleam new file mode 100644 index 0000000..6f7c56c --- /dev/null +++ b/src/models/ship_role.gleam @@ -0,0 +1,62 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ShipRole { + Fabricator + Harvester + Hauler + Interceptor + Excavator + Transport + Repair + Surveyor + Command + Carrier + Patrol + Satellite + Explorer + Refinery +} + +pub fn to_string(ship_role: ShipRole) -> String { + case ship_role { + Fabricator -> "FABRICATOR" + Harvester -> "HARVESTER" + Hauler -> "HAULER" + Interceptor -> "INTERCEPTOR" + Excavator -> "EXCAVATOR" + Transport -> "TRANSPORT" + Repair -> "REPAIR" + Surveyor -> "SURVEYOR" + Command -> "COMMAND" + Carrier -> "CARRIER" + Patrol -> "PATROL" + Satellite -> "SATELLITE" + Explorer -> "EXPLORER" + Refinery -> "REFINERY" + } +} + +pub fn parse(ship_role_str: String) -> Result(ShipRole, ShipRole) { + case ship_role_str { + "FABRICATOR" -> Ok(Fabricator) + "HARVESTER" -> Ok(Harvester) + "HAULER" -> Ok(Hauler) + "INTERCEPTOR" -> Ok(Interceptor) + "EXCAVATOR" -> Ok(Excavator) + "TRANSPORT" -> Ok(Transport) + "REPAIR" -> Ok(Repair) + "SURVEYOR" -> Ok(Surveyor) + "COMMAND" -> Ok(Command) + "CARRIER" -> Ok(Carrier) + "PATROL" -> Ok(Patrol) + "SATELLITE" -> Ok(Satellite) + "EXPLORER" -> Ok(Explorer) + "REFINERY" -> Ok(Refinery) + _ -> Error(Fabricator) + } +} + +pub fn decoder() -> Decoder(ShipRole) { + decode_utils.enum_decoder(parse, "ShipRole") +} diff --git a/src/models/ship_symbol.gleam b/src/models/ship_symbol.gleam new file mode 100644 index 0000000..40610db --- /dev/null +++ b/src/models/ship_symbol.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ShipSymbol = + String + +pub fn decoder() -> Decoder(ShipSymbol) { + decode.string +} diff --git a/src/models/ship_type.gleam b/src/models/ship_type.gleam new file mode 100644 index 0000000..a23919f --- /dev/null +++ b/src/models/ship_type.gleam @@ -0,0 +1,35 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type ShipType { + ShipProbe + ShipMiningDrone + ShipSiphonDrone + ShipInterceptor + ShipLightHauler +} + +pub fn to_string(ship_type: ShipType) -> String { + case ship_type { + ShipProbe -> "SHIP_PROBE" + ShipMiningDrone -> "SHIP_MINING_DRONE" + ShipSiphonDrone -> "SHIP_SIPHON_DRONE" + ShipInterceptor -> "SHIP_INTERCEPTOR" + ShipLightHauler -> "SHIP_LIGHT_HAULER" + } +} + +pub fn parse(ship_type_str: String) -> Result(ShipType, ShipType) { + case ship_type_str { + "SHIP_PROBE" -> Ok(ShipProbe) + "SHIP_MINING_DRONE" -> Ok(ShipMiningDrone) + "SHIP_SIPHON_DRONE" -> Ok(ShipSiphonDrone) + "SHIP_INTERCEPTOR" -> Ok(ShipInterceptor) + "SHIP_LIGHT_HAULER" -> Ok(ShipLightHauler) + _ -> Error(ShipProbe) + } +} + +pub fn decoder() -> Decoder(ShipType) { + decode_utils.enum_decoder(parse, "ShipType") +} diff --git a/src/models/shipyard.gleam b/src/models/shipyard.gleam new file mode 100644 index 0000000..132f09b --- /dev/null +++ b/src/models/shipyard.gleam @@ -0,0 +1,38 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/ship_type.{type ShipType} +import models/shipyard_ship.{type ShipyardShip} +import models/shipyard_symbol.{type ShipyardSymbol} +import models/shipyard_transaction.{type ShipyardTransaction} +import utils/decode as decode_utils + +pub type Shipyard { + Shipyard( + symbol: ShipyardSymbol, + ship_types: List(ShipType), + transactions: Option(List(ShipyardTransaction)), + ships: Option(List(ShipyardShip)), + modifications_fee: Int, + ) +} + +pub fn decoder() -> Decoder(Shipyard) { + use symbol <- decode.field("symbol", decode.string) + use ship_types <- decode.field("shipTypes", decode.list(ship_type.decoder())) + use transactions <- decode_utils.field_key_value_optional( + "transactions", + decode.list(shipyard_transaction.decoder()), + ) + use ships <- decode_utils.field_key_value_optional( + "ships", + decode.list(shipyard_ship.decoder()), + ) + use modifications_fee <- decode.field("modificationsFee", decode.int) + decode.success(Shipyard( + symbol:, + ship_types:, + transactions:, + ships:, + modifications_fee:, + )) +} diff --git a/src/models/shipyard_ship.gleam b/src/models/shipyard_ship.gleam new file mode 100644 index 0000000..2836056 --- /dev/null +++ b/src/models/shipyard_ship.gleam @@ -0,0 +1,61 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/activity_level.{type ActivityLevel} +import models/ship_engine.{type ShipEngine} +import models/ship_frame.{type ShipFrame} +import models/ship_module.{type ShipModule} +import models/ship_mount.{type ShipMount} +import models/ship_reactor.{type ShipReactor} +import models/ship_type.{type ShipType} +import models/shipyard_ship_crew.{type ShipyardShipCrew} +import models/supply_level.{type SupplyLevel} +import utils/decode as decode_utils + +pub type ShipyardShip { + ShipyardShip( + type_: ShipType, + name: String, + description: String, + activity: Option(ActivityLevel), + supply: SupplyLevel, + purchase_price: Int, + frame: ShipFrame, + reactor: ShipReactor, + engine: ShipEngine, + modules: List(ShipModule), + mounts: List(ShipMount), + crew: ShipyardShipCrew, + ) +} + +pub fn decoder() -> Decoder(ShipyardShip) { + use type_ <- decode.field("type", ship_type.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + use activity <- decode_utils.field_key_value_optional( + "activity", + activity_level.decoder(), + ) + use supply <- decode.field("supply", supply_level.decoder()) + use purchase_price <- decode.field("purchasePrice", decode.int) + use frame <- decode.field("frame", ship_frame.decoder()) + use reactor <- decode.field("reactor", ship_reactor.decoder()) + use engine <- decode.field("engine", ship_engine.decoder()) + use modules <- decode.field("modules", decode.list(ship_module.decoder())) + use mounts <- decode.field("mounts", decode.list(ship_mount.decoder())) + use crew <- decode.field("crew", shipyard_ship_crew.decoder()) + decode.success(ShipyardShip( + type_:, + name:, + description:, + activity:, + supply:, + purchase_price:, + frame:, + reactor:, + engine:, + modules:, + mounts:, + crew:, + )) +} diff --git a/src/models/shipyard_ship_crew.gleam b/src/models/shipyard_ship_crew.gleam new file mode 100644 index 0000000..d5f257d --- /dev/null +++ b/src/models/shipyard_ship_crew.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ShipyardShipCrew { + ShipCrew(required: Int, capacity: Int) +} + +pub fn decoder() -> Decoder(ShipyardShipCrew) { + use required <- decode.field("required", decode.int) + use capacity <- decode.field("capacity", decode.int) + decode.success(ShipCrew(required:, capacity:)) +} diff --git a/src/models/shipyard_symbol.gleam b/src/models/shipyard_symbol.gleam new file mode 100644 index 0000000..b6e48f7 --- /dev/null +++ b/src/models/shipyard_symbol.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type ShipyardSymbol = + String + +pub fn decoder() -> Decoder(ShipyardSymbol) { + decode.string +} diff --git a/src/models/shipyard_transaction.gleam b/src/models/shipyard_transaction.gleam new file mode 100644 index 0000000..77948e0 --- /dev/null +++ b/src/models/shipyard_transaction.gleam @@ -0,0 +1,32 @@ +import gleam/dynamic/decode.{type Decoder} +import models/agent_symbol.{type AgentSymbol} +import models/ship_type.{type ShipType} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type ShipyardTransaction { + ShipyardTransaction( + waypoint_symbol: WaypointSymbol, + ship_type: ShipType, + price: Int, + agent_symbol: AgentSymbol, + timestamp: String, + ) +} + +pub fn decoder() -> Decoder(ShipyardTransaction) { + use waypoint_symbol <- decode.field( + "waypointSymbol", + waypoint_symbol.decoder(), + ) + use ship_type <- decode.field("shipType", ship_type.decoder()) + use price <- decode.field("price", decode.int) + use agent_symbol <- decode.field("agentSymbol", agent_symbol.decoder()) + use timestamp <- decode.field("timestamp", decode.string) + decode.success(ShipyardTransaction( + waypoint_symbol:, + ship_type:, + price:, + agent_symbol:, + timestamp:, + )) +} diff --git a/src/models/siphon.gleam b/src/models/siphon.gleam new file mode 100644 index 0000000..20e54f4 --- /dev/null +++ b/src/models/siphon.gleam @@ -0,0 +1,13 @@ +import gleam/dynamic/decode.{type Decoder} +import models/ship_symbol.{type ShipSymbol} +import models/siphon_yield.{type SiphonYield} + +pub type Siphon { + Siphon(ship_symbol: ShipSymbol, yield: SiphonYield) +} + +pub fn decoder() -> Decoder(Siphon) { + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) + use yield <- decode.field("yield", siphon_yield.decoder()) + decode.success(Siphon(ship_symbol:, yield:)) +} diff --git a/src/models/siphon_yield.gleam b/src/models/siphon_yield.gleam new file mode 100644 index 0000000..3d11cd5 --- /dev/null +++ b/src/models/siphon_yield.gleam @@ -0,0 +1,12 @@ +import gleam/dynamic/decode.{type Decoder} +import models/trade_symbol.{type TradeSymbol} + +pub type SiphonYield { + SiphonYield(symbol: TradeSymbol, units: Int) +} + +pub fn decoder() -> Decoder(SiphonYield) { + use symbol <- decode.field("symbol", trade_symbol.decoder()) + use units <- decode.field("units", decode.int) + decode.success(SiphonYield(symbol:, units:)) +} diff --git a/src/models/supply_level.gleam b/src/models/supply_level.gleam new file mode 100644 index 0000000..8d4aae9 --- /dev/null +++ b/src/models/supply_level.gleam @@ -0,0 +1,35 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type SupplyLevel { + Scarce + Limited + Moderate + High + Abundant +} + +pub fn to_string(supply_level: SupplyLevel) -> String { + case supply_level { + Scarce -> "SCARCE" + Limited -> "LIMITED" + Moderate -> "MODERATE" + High -> "HIGH" + Abundant -> "ABUNDANT" + } +} + +pub fn parse(supply_level_str: String) -> Result(SupplyLevel, SupplyLevel) { + case supply_level_str { + "SCARCE" -> Ok(Scarce) + "LIMITED" -> Ok(Limited) + "MODERATE" -> Ok(Moderate) + "HIGH" -> Ok(High) + "ABUNDANT" -> Ok(Abundant) + _ -> Error(Scarce) + } +} + +pub fn decoder() -> Decoder(SupplyLevel) { + decode_utils.enum_decoder(parse, "SupplyLevel") +} diff --git a/src/models/survey.gleam b/src/models/survey.gleam new file mode 100644 index 0000000..6c41dc3 --- /dev/null +++ b/src/models/survey.gleam @@ -0,0 +1,38 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import models/survey_deposit.{type SurveyDeposit} +import models/survey_signature.{type SurveySignature} +import models/survey_size.{type SurveySize} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type Survey { + Survey( + signature: SurveySignature, + symbol: WaypointSymbol, + deposits: List(SurveyDeposit), + expiration: String, + size: SurveySize, + ) +} + +pub fn encode(data: Survey) -> Json { + json.object([ + #("signature", json.string(data.signature)), + #("symbol", json.string(data.symbol)), + #("deposits", json.array(data.deposits, survey_deposit.encode)), + #("expiration", json.string(data.expiration)), + #("size", survey_size.encode(data.size)), + ]) +} + +pub fn decoder() -> Decoder(Survey) { + use signature <- decode.field("signature", survey_signature.decoder()) + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) + use deposits <- decode.field( + "deposits", + decode.list(survey_deposit.decoder()), + ) + use expiration <- decode.field("expiration", decode.string) + use size <- decode.field("size", survey_size.decoder()) + decode.success(Survey(signature:, symbol:, deposits:, expiration:, size:)) +} diff --git a/src/models/survey_deposit.gleam b/src/models/survey_deposit.gleam new file mode 100644 index 0000000..a97f5c2 --- /dev/null +++ b/src/models/survey_deposit.gleam @@ -0,0 +1,16 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import models/trade_symbol.{type TradeSymbol} + +pub type SurveyDeposit { + SurveyDeposit(symbol: TradeSymbol) +} + +pub fn encode(survey_deposit: SurveyDeposit) -> Json { + json.object([#("symbol", trade_symbol.encode(survey_deposit.symbol))]) +} + +pub fn decoder() -> Decoder(SurveyDeposit) { + use symbol <- decode.field("symbol", trade_symbol.decoder()) + decode.success(SurveyDeposit(symbol:)) +} diff --git a/src/models/survey_signature.gleam b/src/models/survey_signature.gleam new file mode 100644 index 0000000..5c2793e --- /dev/null +++ b/src/models/survey_signature.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type SurveySignature = + String + +pub fn decoder() -> Decoder(SurveySignature) { + decode.string +} diff --git a/src/models/survey_size.gleam b/src/models/survey_size.gleam new file mode 100644 index 0000000..afdde04 --- /dev/null +++ b/src/models/survey_size.gleam @@ -0,0 +1,34 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import utils/decode as decode_utils + +pub type SurveySize { + Small + Moderate + Large +} + +pub fn to_string(survey_size: SurveySize) -> String { + case survey_size { + Small -> "SMALL" + Moderate -> "MODERATE" + Large -> "LARGE" + } +} + +pub fn parse(survey_size_str: String) -> Result(SurveySize, SurveySize) { + case survey_size_str { + "SMALL" -> Ok(Small) + "MODERATE" -> Ok(Moderate) + "LARGE" -> Ok(Large) + _ -> Error(Small) + } +} + +pub fn encode(survey_size: SurveySize) -> Json { + json.string(to_string(survey_size)) +} + +pub fn decoder() -> Decoder(SurveySize) { + decode_utils.enum_decoder(parse, "SurveySize") +} diff --git a/src/models/system.gleam b/src/models/system.gleam new file mode 100644 index 0000000..1aa39d7 --- /dev/null +++ b/src/models/system.gleam @@ -0,0 +1,54 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/system_faction.{type SystemFaction} +import models/system_symbol.{type SystemSymbol} +import models/system_type.{type SystemType} +import models/system_waypoint.{type SystemWaypoint} +import utils/decode as decode_utils + +pub type System { + System( + constellation: Option(String), + symbol: SystemSymbol, + sector_symbol: String, + type_: SystemType, + x: Int, + y: Int, + waypoints: List(SystemWaypoint), + factions: List(SystemFaction), + name: Option(String), + ) +} + +pub fn decoder() -> Decoder(System) { + use constellation <- decode.optional_field( + "constellation", + option.None, + decode.optional(decode.string), + ) + use symbol <- decode.field("symbol", decode.string) + use sector_symbol <- decode.field("sectorSymbol", decode.string) + use type_ <- decode.field("type", system_type.decoder()) + use x <- decode.field("x", decode.int) + use y <- decode.field("y", decode.int) + use waypoints <- decode.field( + "waypoints", + decode.list(system_waypoint.decoder()), + ) + use factions <- decode.field( + "factions", + decode.list(system_faction.decoder()), + ) + use name <- decode_utils.field_key_value_optional("name", decode.string) + decode.success(System( + constellation:, + symbol:, + sector_symbol:, + type_:, + x:, + y:, + waypoints:, + factions:, + name:, + )) +} diff --git a/src/models/system_faction.gleam b/src/models/system_faction.gleam new file mode 100644 index 0000000..81e4c8b --- /dev/null +++ b/src/models/system_faction.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} +import models/faction_symbol.{type FactionSymbol} + +pub type SystemFaction { + SystemFaction(symbol: FactionSymbol) +} + +pub fn decoder() -> Decoder(SystemFaction) { + use symbol <- decode.field("symbol", faction_symbol.decoder()) + decode.success(SystemFaction(symbol:)) +} diff --git a/src/models/system_symbol.gleam b/src/models/system_symbol.gleam new file mode 100644 index 0000000..b93eced --- /dev/null +++ b/src/models/system_symbol.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type SystemSymbol = + String + +pub fn decoder() -> Decoder(SystemSymbol) { + decode.string +} diff --git a/src/models/system_type.gleam b/src/models/system_type.gleam new file mode 100644 index 0000000..608f224 --- /dev/null +++ b/src/models/system_type.gleam @@ -0,0 +1,50 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type SystemType { + NeutronStar + RedStar + OrangeStar + BlueStar + YoungStar + WhiteDwarf + BlackHole + Hypergiant + Nebula + Unstable +} + +pub fn to_string(system_type: SystemType) -> String { + case system_type { + NeutronStar -> "NEUTRON_STAR" + RedStar -> "RED_STAR" + OrangeStar -> "ORANGE_STAR" + BlueStar -> "BLUE_STAR" + YoungStar -> "YOUNG_STAR" + WhiteDwarf -> "WHITE_DWARF" + BlackHole -> "BLACK_HOLE" + Hypergiant -> "HYPERGIANT" + Nebula -> "NEBULA" + Unstable -> "UNSTABLE" + } +} + +pub fn parse(system_type_str: String) -> Result(SystemType, SystemType) { + case system_type_str { + "NEUTRON_STAR" -> Ok(NeutronStar) + "RED_STAR" -> Ok(RedStar) + "ORANGE_STAR" -> Ok(OrangeStar) + "BLUE_STAR" -> Ok(BlueStar) + "YOUNG_STAR" -> Ok(YoungStar) + "WHITE_DWARF" -> Ok(WhiteDwarf) + "BLACK_HOLE" -> Ok(BlackHole) + "HYPERGIANT" -> Ok(Hypergiant) + "NEBULA" -> Ok(Nebula) + "UNSTABLE" -> Ok(Unstable) + _ -> Ok(NeutronStar) + } +} + +pub fn decoder() -> Decoder(SystemType) { + decode_utils.enum_decoder(parse, "SystemType") +} diff --git a/src/models/system_waypoint.gleam b/src/models/system_waypoint.gleam new file mode 100644 index 0000000..7d9844f --- /dev/null +++ b/src/models/system_waypoint.gleam @@ -0,0 +1,30 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/waypoint_orbital.{type WaypointOrbital} +import models/waypoint_symbol.{type WaypointSymbol} +import models/waypoint_type.{type WaypointType} +import utils/decode as decode_utils + +pub type SystemWaypoint { + SystemWaypoint( + symbol: WaypointSymbol, + type_: WaypointType, + x: Int, + y: Int, + orbitals: List(WaypointOrbital), + orbits: Option(String), + ) +} + +pub fn decoder() -> Decoder(SystemWaypoint) { + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) + use type_ <- decode.field("type", waypoint_type.decoder()) + use x <- decode.field("x", decode.int) + use y <- decode.field("y", decode.int) + use orbitals <- decode.field( + "orbitals", + decode.list(waypoint_orbital.decoder()), + ) + use orbits <- decode_utils.field_key_value_optional("orbits", decode.string) + decode.success(SystemWaypoint(symbol:, type_:, x:, y:, orbitals:, orbits:)) +} diff --git a/src/models/trade_good.gleam b/src/models/trade_good.gleam new file mode 100644 index 0000000..33a8fbd --- /dev/null +++ b/src/models/trade_good.gleam @@ -0,0 +1,13 @@ +import gleam/dynamic/decode.{type Decoder} +import models/trade_symbol.{type TradeSymbol} + +pub type TradeGood { + TradeGood(symbol: TradeSymbol, name: String, description: String) +} + +pub fn decoder() -> Decoder(TradeGood) { + use symbol <- decode.field("symbol", trade_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + decode.success(TradeGood(symbol:, name:, description:)) +} diff --git a/src/models/trade_good_type.gleam b/src/models/trade_good_type.gleam new file mode 100644 index 0000000..4c5f84b --- /dev/null +++ b/src/models/trade_good_type.gleam @@ -0,0 +1,31 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type TradeGoodType { + Import + Export + Exchange +} + +pub fn to_string(trade_good_type: TradeGoodType) -> String { + case trade_good_type { + Import -> "IMPORT" + Export -> "EXPORT" + Exchange -> "EXCHANGE" + } +} + +pub fn parse( + trade_good_type_str: String, +) -> Result(TradeGoodType, TradeGoodType) { + case trade_good_type_str { + "IMPORT" -> Ok(Import) + "EXPORT" -> Ok(Export) + "EXCHANGE" -> Ok(Exchange) + _ -> Error(Import) + } +} + +pub fn decoder() -> Decoder(TradeGoodType) { + decode_utils.enum_decoder(parse, "TradeGoodType") +} diff --git a/src/models/trade_symbol.gleam b/src/models/trade_symbol.gleam new file mode 100644 index 0000000..7807e93 --- /dev/null +++ b/src/models/trade_symbol.gleam @@ -0,0 +1,460 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import utils/decode as decode_utils + +pub type TradeSymbol { + PreciousStones + QuartzSand + SiliconCrystals + AmmoniaIce + LiquidHydrogen + LiquidNitrogen + IceWater + ExoticMatter + AdvancedCircuitry + GravitonEmitters + Iron + IronOre + Copper + CopperOre + Aluminum + AluminumOre + Silver + SilverOre + Gold + GoldOre + Platinum + PlatinumOre + Diamonds + Uranite + UraniteOre + Meritium + MeritiumOre + Hydrocarbon + Antimatter + FabMats + Fertilizers + Fabrics + Food + Jewelry + Machinery + Firearms + AssaultRifles + MilitaryEquipment + Explosives + LabInstruments + Ammunition + Electronics + ShipPlating + ShipParts + Equipment + Fuel + Medicine + Drugs + Clothing + Microprocessors + Plastics + Polynucleotides + Biocomposites + QuantumStabilizers + Nanobots + AiMainframes + QuantumDrives + RoboticDrones + CyberImplants + GeneTherapeutics + NeuralChips + MoodRegulators + ViralAgents + MicroFusionGenerators + Supergrains + LaserRifles + Holographics + ShipSalvage + RelicTech + NovelLifeforms + BotanicalSpecimens + CulturalArtifacts + FrameProbe + FrameDrone + FrameInterceptor + FrameRacer + FrameFighter + FrameFrigate + FrameShuttle + FrameExplorer + FrameMiner + FrameLightFreighter + FrameHeavyFreighter + FrameTransport + FrameDestroyer + FrameCruiser + FrameCarrier + FrameBulkFreighter + ReactorSolarI + ReactorFusionI + ReactorFissionI + ReactorChemicalI + ReactorAntimatterI + EngineImpulseDriveI + EngineIonDriveI + EngineIonDriveIi + EngineHyperDriveI + ModuleMineralProcessorI + ModuleGasProcessorI + ModuleCargoHoldI + ModuleCargoHoldII + ModuleCargoHoldIII + ModuleCrewQuartersI + ModuleEnvoyQuartersI + ModulePassengerCabinI + ModuleMicroRefineryI + ModuleScienceLabI + ModuleJumpDriveI + ModuleJumpDriveII + ModuleJumpDriveIII + ModuleWarpDriveI + ModuleWarpDriveII + ModuleWarpDriveIII + ModuleShieldGeneratorI + ModuleShieldGeneratorII + ModuleOreRefineryI + ModuleFuelRefineryI + MountGasSiphonI + MountGasSiphonII + MountGasSiphonIII + MountSurveyorI + MountSurveyorII + MountSurveyorIII + MountSensorArrayI + MountSensorArrayII + MountSensorArrayIII + MountMiningLaserI + MountMiningLaserII + MountMiningLaserIII + MountLaserCannonI + MountMissileLauncherI + MountTurretI + ShipProbe + ShipMiningDrone + ShipSiphonDrone + ShipInterceptor + ShipLightHauler + ShipCommandFrigate + ShipExplorer + ShipHeavyFreighter + ShipLightShuttle + ShipOreHound + ShipRefiningFreighter + ShipSurveyor + ShipBulkFreighter +} + +pub fn to_string(trade_symbol: TradeSymbol) -> String { + case trade_symbol { + PreciousStones -> "PRECIOUS_STONES" + QuartzSand -> "QUARTZ_SAND" + SiliconCrystals -> "SILICON_CRYSTALS" + AmmoniaIce -> "AMMONIA_ICE" + LiquidHydrogen -> "LIQUID_HYDROGEN" + LiquidNitrogen -> "LIQUID_NITROGEN" + IceWater -> "ICE_WATER" + ExoticMatter -> "EXOTIC_MATTER" + AdvancedCircuitry -> "ADVANCED_CIRCUITRY" + GravitonEmitters -> "GRAVITON_EMITTERS" + Iron -> "IRON" + IronOre -> "IRON_ORE" + Copper -> "COPPER" + CopperOre -> "COPPER_ORE" + Aluminum -> "ALUMINUM" + AluminumOre -> "ALUMINUM_ORE" + Silver -> "SILVER" + SilverOre -> "SILVER_ORE" + Gold -> "GOLD" + GoldOre -> "GOLD_ORE" + Platinum -> "PLATINUM" + PlatinumOre -> "PLATINUM_ORE" + Diamonds -> "DIAMONDS" + Uranite -> "URANITE" + UraniteOre -> "URANITE_ORE" + Meritium -> "MERITIUM" + MeritiumOre -> "MERITIUM_ORE" + Hydrocarbon -> "HYDROCARBON" + Antimatter -> "ANTIMATTER" + FabMats -> "FAB_MATS" + Fertilizers -> "FERTILIZERS" + Fabrics -> "FABRICS" + Food -> "FOOD" + Jewelry -> "JEWELRY" + Machinery -> "MACHINERY" + Firearms -> "FIREARMS" + AssaultRifles -> "ASSAULT_RIFLES" + MilitaryEquipment -> "MILITARY_EQUIPMENT" + Explosives -> "EXPLOSIVES" + LabInstruments -> "LAB_INSTRUMENTS" + Ammunition -> "AMMUNITION" + Electronics -> "ELECTRONICS" + ShipPlating -> "SHIP_PLATING" + ShipParts -> "SHIP_PARTS" + Equipment -> "EQUIPMENT" + Fuel -> "FUEL" + Medicine -> "MEDICINE" + Drugs -> "DRUGS" + Clothing -> "CLOTHING" + Microprocessors -> "MICROPROCESSORS" + Plastics -> "PLASTICS" + Polynucleotides -> "POLYNUCLEOTIDES" + Biocomposites -> "BIOCOMPOSITES" + QuantumStabilizers -> "QUANTUM_STABILIZERS" + Nanobots -> "NANOBOTS" + AiMainframes -> "AI_MAINFRAMES" + QuantumDrives -> "QUANTUM_DRIVES" + RoboticDrones -> "ROBOTIC_DRONES" + CyberImplants -> "CYBER_IMPLANTS" + GeneTherapeutics -> "GENE_THERAPEUTICS" + NeuralChips -> "NEURAL_CHIPS" + MoodRegulators -> "MOOD_REGULATORS" + ViralAgents -> "VIRAL_AGENTS" + MicroFusionGenerators -> "MICRO_FUSION_GENERATORS" + Supergrains -> "SUPERGRAINS" + LaserRifles -> "LASER_RIFLES" + Holographics -> "HOLOGRAPHICS" + ShipSalvage -> "SHIP_SALVAGE" + RelicTech -> "RELIC_TECH" + NovelLifeforms -> "NOVEL_LIFEFORMS" + BotanicalSpecimens -> "BOTANICAL_SPECIMENS" + CulturalArtifacts -> "CULTURAL_ARTIFACTS" + FrameProbe -> "FRAME_PROBE" + FrameDrone -> "FRAME_DRONE" + FrameInterceptor -> "FRAME_INTERCEPTOR" + FrameRacer -> "FRAME_RACER" + FrameFighter -> "FRAME_FIGHTER" + FrameFrigate -> "FRAME_FRIGATE" + FrameShuttle -> "FRAME_SHUTTLE" + FrameExplorer -> "FRAME_EXPLORER" + FrameMiner -> "FRAME_MINER" + FrameLightFreighter -> "FRAME_LIGHT_FREIGHTER" + FrameHeavyFreighter -> "FRAME_HEAVY_FREIGHTER" + FrameTransport -> "FRAME_TRANSPORT" + FrameDestroyer -> "FRAME_DESTROYER" + FrameCruiser -> "FRAME_CRUISER" + FrameCarrier -> "FRAME_CARRIER" + FrameBulkFreighter -> "FRAME_BULK_FREIGHTER" + ReactorSolarI -> "REACTOR_SOLAR_I" + ReactorFusionI -> "REACTOR_FUSION_I" + ReactorFissionI -> "REACTOR_FISSION_I" + ReactorChemicalI -> "REACTOR_CHEMICAL_I" + ReactorAntimatterI -> "REACTOR_ANTIMATTER_I" + EngineImpulseDriveI -> "ENGINE_IMPULSE_DRIVE_I" + EngineIonDriveI -> "ENGINE_ION_DRIVE_I" + EngineIonDriveIi -> "ENGINE_ION_DRIVE_II" + EngineHyperDriveI -> "ENGINE_HYPER_DRIVE_I" + ModuleMineralProcessorI -> "MODULE_MINERAL_PROCESSOR_I" + ModuleGasProcessorI -> "MODULE_GAS_PROCESSOR_I" + ModuleCargoHoldI -> "MODULE_CARGO_HOLD_I" + ModuleCargoHoldII -> "MODULE_CARGO_HOLD_II" + ModuleCargoHoldIII -> "MODULE_CARGO_HOLD_III" + ModuleCrewQuartersI -> "MODULE_CREW_QUARTERS_I" + ModuleEnvoyQuartersI -> "MODULE_ENVOY_QUARTERS_I" + ModulePassengerCabinI -> "MODULE_PASSENGER_CABIN_I" + ModuleMicroRefineryI -> "MODULE_MICRO_REFINERY_I" + ModuleScienceLabI -> "MODULE_SCIENCE_LAB_I" + ModuleJumpDriveI -> "MODULE_JUMP_DRIVE_I" + ModuleJumpDriveII -> "MODULE_JUMP_DRIVE_II" + ModuleJumpDriveIII -> "MODULE_JUMP_DRIVE_III" + ModuleWarpDriveI -> "MODULE_WARP_DRIVE_I" + ModuleWarpDriveII -> "MODULE_WARP_DRIVE_II" + ModuleWarpDriveIII -> "MODULE_WARP_DRIVE_III" + ModuleShieldGeneratorI -> "MODULE_SHIELD_GENERATOR_I" + ModuleShieldGeneratorII -> "MODULE_SHIELD_GENERATOR_II" + ModuleOreRefineryI -> "MODULE_ORE_REFINERY_I" + ModuleFuelRefineryI -> "MODULE_FUEL_REFINERY_I" + MountGasSiphonI -> "MOUNT_GAS_SIPHON_I" + MountGasSiphonII -> "MOUNT_GAS_SIPHON_II" + MountGasSiphonIII -> "MOUNT_GAS_SIPHON_III" + MountSurveyorI -> "MOUNT_SURVEYOR_I" + MountSurveyorII -> "MOUNT_SURVEYOR_II" + MountSurveyorIII -> "MOUNT_SURVEYOR_III" + MountSensorArrayI -> "MOUNT_SENSOR_ARRAY_I" + MountSensorArrayII -> "MOUNT_SENSOR_ARRAY_II" + MountSensorArrayIII -> "MOUNT_SENSOR_ARRAY_III" + MountMiningLaserI -> "MOUNT_MINING_LASER_I" + MountMiningLaserII -> "MOUNT_MINING_LASER_II" + MountMiningLaserIII -> "MOUNT_MINING_LASER_III" + MountLaserCannonI -> "MOUNT_LASER_CANNON_I" + MountMissileLauncherI -> "MOUNT_MISSILE_LAUNCHER_I" + MountTurretI -> "MOUNT_TURRET_I" + ShipProbe -> "SHIP_PROBE" + ShipMiningDrone -> "SHIP_MINING_DRONE" + ShipSiphonDrone -> "SHIP_SIPHON_DRONE" + ShipInterceptor -> "SHIP_INTERCEPTOR" + ShipLightHauler -> "SHIP_LIGHT_HAULER" + ShipCommandFrigate -> "SHIP_COMMAND_FRIGATE" + ShipExplorer -> "SHIP_EXPLORER" + ShipHeavyFreighter -> "SHIP_HEAVY_FREIGHTER" + ShipLightShuttle -> "SHIP_LIGHT_SHUTTLE" + ShipOreHound -> "SHIP_ORE_HOUND" + ShipRefiningFreighter -> "SHIP_REFINING_FREIGHTER" + ShipSurveyor -> "SHIP_SURVEYOR" + ShipBulkFreighter -> "SHIP_BULK_FREIGHTER" + } +} + +pub fn parse(trade_symbol_str: String) -> Result(TradeSymbol, TradeSymbol) { + case trade_symbol_str { + "PRECIOUS_STONES" -> Ok(PreciousStones) + "QUARTZ_SAND" -> Ok(QuartzSand) + "SILICON_CRYSTALS" -> Ok(SiliconCrystals) + "AMMONIA_ICE" -> Ok(AmmoniaIce) + "LIQUID_HYDROGEN" -> Ok(LiquidHydrogen) + "LIQUID_NITROGEN" -> Ok(LiquidNitrogen) + "ICE_WATER" -> Ok(IceWater) + "EXOTIC_MATTER" -> Ok(ExoticMatter) + "ADVANCED_CIRCUITRY" -> Ok(AdvancedCircuitry) + "GRAVITON_EMITTERS" -> Ok(GravitonEmitters) + "IRON" -> Ok(Iron) + "IRON_ORE" -> Ok(IronOre) + "COPPER" -> Ok(Copper) + "COPPER_ORE" -> Ok(CopperOre) + "ALUMINUM" -> Ok(Aluminum) + "ALUMINUM_ORE" -> Ok(AluminumOre) + "SILVER" -> Ok(Silver) + "SILVER_ORE" -> Ok(SilverOre) + "GOLD" -> Ok(Gold) + "GOLD_ORE" -> Ok(GoldOre) + "PLATINUM" -> Ok(Platinum) + "PLATINUM_ORE" -> Ok(PlatinumOre) + "DIAMONDS" -> Ok(Diamonds) + "URANITE" -> Ok(Uranite) + "URANITE_ORE" -> Ok(UraniteOre) + "MERITIUM" -> Ok(Meritium) + "MERITIUM_ORE" -> Ok(MeritiumOre) + "HYDROCARBON" -> Ok(Hydrocarbon) + "ANTIMATTER" -> Ok(Antimatter) + "FAB_MATS" -> Ok(FabMats) + "FERTILIZERS" -> Ok(Fertilizers) + "FABRICS" -> Ok(Fabrics) + "FOOD" -> Ok(Food) + "JEWELRY" -> Ok(Jewelry) + "MACHINERY" -> Ok(Machinery) + "FIREARMS" -> Ok(Firearms) + "ASSAULT_RIFLES" -> Ok(AssaultRifles) + "MILITARY_EQUIPMENT" -> Ok(MilitaryEquipment) + "EXPLOSIVES" -> Ok(Explosives) + "LAB_INSTRUMENTS" -> Ok(LabInstruments) + "AMMUNITION" -> Ok(Ammunition) + "ELECTRONICS" -> Ok(Electronics) + "SHIP_PLATING" -> Ok(ShipPlating) + "SHIP_PARTS" -> Ok(ShipParts) + "EQUIPMENT" -> Ok(Equipment) + "FUEL" -> Ok(Fuel) + "MEDICINE" -> Ok(Medicine) + "DRUGS" -> Ok(Drugs) + "CLOTHING" -> Ok(Clothing) + "MICROPROCESSORS" -> Ok(Microprocessors) + "PLASTICS" -> Ok(Plastics) + "POLYNUCLEOTIDES" -> Ok(Polynucleotides) + "BIOCOMPOSITES" -> Ok(Biocomposites) + "QUANTUM_STABILIZERS" -> Ok(QuantumStabilizers) + "NANOBOTS" -> Ok(Nanobots) + "AI_MAINFRAMES" -> Ok(AiMainframes) + "QUANTUM_DRIVES" -> Ok(QuantumDrives) + "ROBOTIC_DRONES" -> Ok(RoboticDrones) + "CYBER_IMPLANTS" -> Ok(CyberImplants) + "GENE_THERAPEUTICS" -> Ok(GeneTherapeutics) + "NEURAL_CHIPS" -> Ok(NeuralChips) + "MOOD_REGULATORS" -> Ok(MoodRegulators) + "VIRAL_AGENTS" -> Ok(ViralAgents) + "MICRO_FUSION_GENERATORS" -> Ok(MicroFusionGenerators) + "SUPERGRAINS" -> Ok(Supergrains) + "LASER_RIFLES" -> Ok(LaserRifles) + "HOLOGRAPHICS" -> Ok(Holographics) + "SHIP_SALVAGE" -> Ok(ShipSalvage) + "RELIC_TECH" -> Ok(RelicTech) + "NOVEL_LIFEFORMS" -> Ok(NovelLifeforms) + "BOTANICAL_SPECIMENS" -> Ok(BotanicalSpecimens) + "CULTURAL_ARTIFACTS" -> Ok(CulturalArtifacts) + "FRAME_PROBE" -> Ok(FrameProbe) + "FRAME_DRONE" -> Ok(FrameDrone) + "FRAME_INTERCEPTOR" -> Ok(FrameInterceptor) + "FRAME_RACER" -> Ok(FrameRacer) + "FRAME_FIGHTER" -> Ok(FrameFighter) + "FRAME_FRIGATE" -> Ok(FrameFrigate) + "FRAME_SHUTTLE" -> Ok(FrameShuttle) + "FRAME_EXPLORER" -> Ok(FrameExplorer) + "FRAME_MINER" -> Ok(FrameMiner) + "FRAME_LIGHT_FREIGHTER" -> Ok(FrameLightFreighter) + "FRAME_HEAVY_FREIGHTER" -> Ok(FrameHeavyFreighter) + "FRAME_TRANSPORT" -> Ok(FrameTransport) + "FRAME_DESTROYER" -> Ok(FrameDestroyer) + "FRAME_CRUISER" -> Ok(FrameCruiser) + "FRAME_CARRIER" -> Ok(FrameCarrier) + "FRAME_BULK_FREIGHTER" -> Ok(FrameBulkFreighter) + "REACTOR_SOLAR_I" -> Ok(ReactorSolarI) + "REACTOR_FUSION_I" -> Ok(ReactorFusionI) + "REACTOR_FISSION_I" -> Ok(ReactorFissionI) + "REACTOR_CHEMICAL_I" -> Ok(ReactorChemicalI) + "REACTOR_ANTIMATTER_I" -> Ok(ReactorAntimatterI) + "ENGINE_IMPULSE_DRIVE_I" -> Ok(EngineImpulseDriveI) + "ENGINE_ION_DRIVE_I" -> Ok(EngineIonDriveI) + "ENGINE_ION_DRIVE_II" -> Ok(EngineIonDriveIi) + "ENGINE_HYPER_DRIVE_I" -> Ok(EngineHyperDriveI) + "MODULE_MINERAL_PROCESSOR_I" -> Ok(ModuleMineralProcessorI) + "MODULE_GAS_PROCESSOR_I" -> Ok(ModuleGasProcessorI) + "MODULE_CARGO_HOLD_I" -> Ok(ModuleCargoHoldI) + "MODULE_CARGO_HOLD_II" -> Ok(ModuleCargoHoldII) + "MODULE_CARGO_HOLD_III" -> Ok(ModuleCargoHoldIII) + "MODULE_CREW_QUARTERS_I" -> Ok(ModuleCrewQuartersI) + "MODULE_ENVOY_QUARTERS_I" -> Ok(ModuleEnvoyQuartersI) + "MODULE_PASSENGER_CABIN_I" -> Ok(ModulePassengerCabinI) + "MODULE_MICRO_REFINERY_I" -> Ok(ModuleMicroRefineryI) + "MODULE_SCIENCE_LAB_I" -> Ok(ModuleScienceLabI) + "MODULE_JUMP_DRIVE_I" -> Ok(ModuleJumpDriveI) + "MODULE_JUMP_DRIVE_II" -> Ok(ModuleJumpDriveII) + "MODULE_JUMP_DRIVE_III" -> Ok(ModuleJumpDriveIII) + "MODULE_WARP_DRIVE_I" -> Ok(ModuleWarpDriveI) + "MODULE_WARP_DRIVE_II" -> Ok(ModuleWarpDriveII) + "MODULE_WARP_DRIVE_III" -> Ok(ModuleWarpDriveIII) + "MODULE_SHIELD_GENERATOR_I" -> Ok(ModuleShieldGeneratorI) + "MODULE_SHIELD_GENERATOR_II" -> Ok(ModuleShieldGeneratorII) + "MODULE_ORE_REFINERY_I" -> Ok(ModuleOreRefineryI) + "MODULE_FUEL_REFINERY_I" -> Ok(ModuleFuelRefineryI) + "MOUNT_GAS_SIPHON_I" -> Ok(MountGasSiphonI) + "MOUNT_GAS_SIPHON_II" -> Ok(MountGasSiphonII) + "MOUNT_GAS_SIPHON_III" -> Ok(MountGasSiphonIII) + "MOUNT_SURVEYOR_I" -> Ok(MountSurveyorI) + "MOUNT_SURVEYOR_II" -> Ok(MountSurveyorII) + "MOUNT_SURVEYOR_III" -> Ok(MountSurveyorIII) + "MOUNT_SENSOR_ARRAY_I" -> Ok(MountSensorArrayI) + "MOUNT_SENSOR_ARRAY_II" -> Ok(MountSensorArrayII) + "MOUNT_SENSOR_ARRAY_III" -> Ok(MountSensorArrayIII) + "MOUNT_MINING_LASER_I" -> Ok(MountMiningLaserI) + "MOUNT_MINING_LASER_II" -> Ok(MountMiningLaserII) + "MOUNT_MINING_LASER_III" -> Ok(MountMiningLaserIII) + "MOUNT_LASER_CANNON_I" -> Ok(MountLaserCannonI) + "MOUNT_MISSILE_LAUNCHER_I" -> Ok(MountMissileLauncherI) + "MOUNT_TURRET_I" -> Ok(MountTurretI) + "SHIP_PROBE" -> Ok(ShipProbe) + "SHIP_MINING_DRONE" -> Ok(ShipMiningDrone) + "SHIP_SIPHON_DRONE" -> Ok(ShipSiphonDrone) + "SHIP_INTERCEPTOR" -> Ok(ShipInterceptor) + "SHIP_LIGHT_HAULER" -> Ok(ShipLightHauler) + "SHIP_COMMAND_FRIGATE" -> Ok(ShipCommandFrigate) + "SHIP_EXPLORER" -> Ok(ShipExplorer) + "SHIP_HEAVY_FREIGHTER" -> Ok(ShipHeavyFreighter) + "SHIP_LIGHT_SHUTTLE" -> Ok(ShipLightShuttle) + "SHIP_ORE_HOUND" -> Ok(ShipOreHound) + "SHIP_REFINING_FREIGHTER" -> Ok(ShipRefiningFreighter) + "SHIP_SURVEYOR" -> Ok(ShipSurveyor) + "SHIP_BULK_FREIGHTER" -> Ok(ShipBulkFreighter) + _ -> Error(PreciousStones) + } +} + +pub fn encode(trade_symbol: TradeSymbol) -> Json { + json.string(to_string(trade_symbol)) +} + +pub fn decoder() -> Decoder(TradeSymbol) { + decode_utils.enum_decoder(parse, "TradeSymbol") +} diff --git a/src/models/transaction_type.gleam b/src/models/transaction_type.gleam new file mode 100644 index 0000000..b449d2b --- /dev/null +++ b/src/models/transaction_type.gleam @@ -0,0 +1,28 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type TransactionType { + Purchase + Sell +} + +pub fn to_string(transaction_type: TransactionType) -> String { + case transaction_type { + Purchase -> "PURCHASE" + Sell -> "SELL" + } +} + +pub fn parse( + transaction_type_str: String, +) -> Result(TransactionType, TransactionType) { + case transaction_type_str { + "PURCHASE" -> Ok(Purchase) + "SELL" -> Ok(Sell) + _ -> Error(Purchase) + } +} + +pub fn decoder() -> Decoder(TransactionType) { + decode_utils.enum_decoder(parse, "TransactionType") +} diff --git a/src/models/waypoint.gleam b/src/models/waypoint.gleam new file mode 100644 index 0000000..069960d --- /dev/null +++ b/src/models/waypoint.gleam @@ -0,0 +1,66 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/chart.{type Chart} +import models/system_symbol.{type SystemSymbol} +import models/waypoint_faction.{type WaypointFaction} +import models/waypoint_modifier.{type WaypointModifier} +import models/waypoint_orbital.{type WaypointOrbital} +import models/waypoint_symbol.{type WaypointSymbol} +import models/waypoint_trait.{type WaypointTrait} +import models/waypoint_type.{type WaypointType} +import utils/decode as decode_utils + +pub type Waypoint { + Waypoint( + symbol: WaypointSymbol, + type_: WaypointType, + system_symbol: SystemSymbol, + x: Int, + y: Int, + orbitals: List(WaypointOrbital), + orbits: Option(String), + faction: Option(WaypointFaction), + traits: List(WaypointTrait), + modifiers: Option(List(WaypointModifier)), + chart: Option(Chart), + is_under_construction: Bool, + ) +} + +pub fn decoder() -> Decoder(Waypoint) { + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) + use type_ <- decode.field("type", waypoint_type.decoder()) + use system_symbol <- decode.field("systemSymbol", system_symbol.decoder()) + use x <- decode.field("x", decode.int) + use y <- decode.field("y", decode.int) + use orbitals <- decode.field( + "orbitals", + decode.list(waypoint_orbital.decoder()), + ) + use orbits <- decode_utils.field_key_value_optional("orbits", decode.string) + use chart <- decode_utils.field_key_value_optional("chart", chart.decoder()) + use faction <- decode_utils.field_key_value_optional( + "faction", + waypoint_faction.decoder(), + ) + use traits <- decode.field("traits", decode.list(waypoint_trait.decoder())) + use modifiers <- decode_utils.field_key_value_optional( + "modifiers", + decode.list(waypoint_modifier.decoder()), + ) + use is_under_construction <- decode.field("isUnderConstruction", decode.bool) + decode.success(Waypoint( + symbol:, + type_:, + system_symbol:, + x:, + y:, + orbitals:, + orbits:, + faction:, + traits:, + modifiers:, + chart:, + is_under_construction:, + )) +} diff --git a/src/models/waypoint_faction.gleam b/src/models/waypoint_faction.gleam new file mode 100644 index 0000000..dd9f01a --- /dev/null +++ b/src/models/waypoint_faction.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} +import models/faction_symbol.{type FactionSymbol} + +pub type WaypointFaction { + WaypointFaction(symbol: FactionSymbol) +} + +pub fn decoder() -> Decoder(WaypointFaction) { + use symbol <- decode.field("symbol", faction_symbol.decoder()) + decode.success(WaypointFaction(symbol:)) +} diff --git a/src/models/waypoint_modifier.gleam b/src/models/waypoint_modifier.gleam new file mode 100644 index 0000000..d1680f7 --- /dev/null +++ b/src/models/waypoint_modifier.gleam @@ -0,0 +1,17 @@ +import gleam/dynamic/decode.{type Decoder} +import models/waypoint_modifier_symbol.{type WaypointModifierSymbol} + +pub type WaypointModifier { + WaypointModifier( + symbol: WaypointModifierSymbol, + name: String, + description: String, + ) +} + +pub fn decoder() -> Decoder(WaypointModifier) { + use symbol <- decode.field("symbol", waypoint_modifier_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + decode.success(WaypointModifier(symbol:, name:, description:)) +} diff --git a/src/models/waypoint_modifier_symbol.gleam b/src/models/waypoint_modifier_symbol.gleam new file mode 100644 index 0000000..b8257d3 --- /dev/null +++ b/src/models/waypoint_modifier_symbol.gleam @@ -0,0 +1,37 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type WaypointModifierSymbol { + Stripped + Unstable + RadiationLeak + CriticalLimit + CivilUnrest +} + +pub fn to_string(waypoint_modifier_symbol: WaypointModifierSymbol) -> String { + case waypoint_modifier_symbol { + Stripped -> "STRIPPED" + Unstable -> "UNSTABLE" + RadiationLeak -> "RADIATION_LEAK" + CriticalLimit -> "CRITICAL_LIMIT" + CivilUnrest -> "CIVIL_UNREST" + } +} + +pub fn parse( + waypoint_modifier_symbol_str: String, +) -> Result(WaypointModifierSymbol, WaypointModifierSymbol) { + case waypoint_modifier_symbol_str { + "STRIPPED" -> Ok(Stripped) + "UNSTABLE" -> Ok(Unstable) + "RADIATION_LEAK" -> Ok(RadiationLeak) + "CRITICAL_LIMIT" -> Ok(CriticalLimit) + "CIVIL_UNREST" -> Ok(CivilUnrest) + _ -> Error(Stripped) + } +} + +pub fn decoder() -> Decoder(WaypointModifierSymbol) { + decode_utils.enum_decoder(parse, "WaypointModifierSymbol") +} diff --git a/src/models/waypoint_orbital.gleam b/src/models/waypoint_orbital.gleam new file mode 100644 index 0000000..5b20ccc --- /dev/null +++ b/src/models/waypoint_orbital.gleam @@ -0,0 +1,11 @@ +import gleam/dynamic/decode.{type Decoder} +import models/waypoint_symbol.{type WaypointSymbol} + +pub type WaypointOrbital { + WaypointOrbital(symbol: WaypointSymbol) +} + +pub fn decoder() -> Decoder(WaypointOrbital) { + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) + decode.success(WaypointOrbital(symbol:)) +} diff --git a/src/models/waypoint_symbol.gleam b/src/models/waypoint_symbol.gleam new file mode 100644 index 0000000..7482cd0 --- /dev/null +++ b/src/models/waypoint_symbol.gleam @@ -0,0 +1,8 @@ +import gleam/dynamic/decode.{type Decoder} + +pub type WaypointSymbol = + String + +pub fn decoder() -> Decoder(WaypointSymbol) { + decode.string +} diff --git a/src/models/waypoint_trait.gleam b/src/models/waypoint_trait.gleam new file mode 100644 index 0000000..7f389c8 --- /dev/null +++ b/src/models/waypoint_trait.gleam @@ -0,0 +1,13 @@ +import gleam/dynamic/decode.{type Decoder} +import models/waypoint_trait_symbol.{type WaypointTraitSymbol} + +pub type WaypointTrait { + WaypointTrait(symbol: WaypointTraitSymbol, name: String, description: String) +} + +pub fn decoder() -> Decoder(WaypointTrait) { + use symbol <- decode.field("symbol", waypoint_trait_symbol.decoder()) + use name <- decode.field("name", decode.string) + use description <- decode.field("description", decode.string) + decode.success(WaypointTrait(symbol:, name:, description:)) +} diff --git a/src/models/waypoint_trait_symbol.gleam b/src/models/waypoint_trait_symbol.gleam new file mode 100644 index 0000000..bc570e6 --- /dev/null +++ b/src/models/waypoint_trait_symbol.gleam @@ -0,0 +1,229 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type WaypointTraitSymbol { + Uncharted + UnderConstruction + Marketplace + Shipyard + Outpost + ScatteredSettlements + SprawlingCities + MegaStructures + PirateBase + Overcrowded + HighTech + Corrupt + Bureaucratic + TradingHub + Industrial + BlackMarket + ResearchFacility + MilitaryBase + SurveillanceOutpost + ExplorationOutpost + MineralDeposits + CommonMetalDeposits + PreciousMetalDeposits + RareMetalDeposits + MethanePools + IceCrystals + ExplosiveGases + StrongMagnetosphere + VibrantAuroras + SaltFlats + Canyons + PerpetualDaylight + PerpetualOvercast + DrySeabeds + MagmaSeas + Supervolcanoes + AshClouds + VastRuins + MutatedFlora + Terraformed + ExtremeTemperatures + ExtremePressure + DiverseLife + ScarceLife + Fossils + WeakGravity + StrongGravity + CrushingGravity + ToxicAtmosphere + CorrosiveAtmosphere + BreathableAtmosphere + ThinAtmosphere + Jovian + Rocky + Volcanic + Frozen + Swamp + Barren + Temperate + Jungle + Ocean + Radioactive + MicroGravityAnomalies + DebrisCluster + DeepCraters + ShallowCraters + UnstableComposition + HollowedInterior + Stripped +} + +pub fn to_string(waypoint_trait_symbol: WaypointTraitSymbol) -> String { + case waypoint_trait_symbol { + Uncharted -> "UNCHARTED" + UnderConstruction -> "UNDER_CONSTRUCTION" + Marketplace -> "MARKETPLACE" + Shipyard -> "SHIPYARD" + Outpost -> "OUTPOST" + ScatteredSettlements -> "SCATTERED_SETTLEMENTS" + SprawlingCities -> "SPRAWLING_CITIES" + MegaStructures -> "MEGA_STRUCTURES" + PirateBase -> "PIRATE_BASE" + Overcrowded -> "OVERCROWDED" + HighTech -> "HIGH_TECH" + Corrupt -> "CORRUPT" + Bureaucratic -> "BUREAUCRATIC" + TradingHub -> "TRADING_HUB" + Industrial -> "INDUSTRIAL" + BlackMarket -> "BLACK_MARKET" + ResearchFacility -> "RESEARCH_FACILITY" + MilitaryBase -> "MILITARY_BASE" + SurveillanceOutpost -> "SURVEILLANCE_OUTPOST" + ExplorationOutpost -> "EXPLORATION_OUTPOST" + MineralDeposits -> "MINERAL_DEPOSITS" + CommonMetalDeposits -> "COMMON_METAL_DEPOSITS" + PreciousMetalDeposits -> "PRECIOUS_METAL_DEPOSITS" + RareMetalDeposits -> "RARE_METAL_DEPOSITS" + MethanePools -> "METHANE_POOLS" + IceCrystals -> "ICE_CRYSTALS" + ExplosiveGases -> "EXPLOSIVE_GASES" + StrongMagnetosphere -> "STRONG_MAGNETOSPHERE" + VibrantAuroras -> "VIBRANT_AURORAS" + SaltFlats -> "SALT_FLATS" + Canyons -> "CANYONS" + PerpetualDaylight -> "PERPETUAL_DAYLIGHT" + PerpetualOvercast -> "PERPETUAL_OVERCAST" + DrySeabeds -> "DRY_SEABEDS" + MagmaSeas -> "MAGMA_SEAS" + Supervolcanoes -> "SUPERVOLCANOES" + AshClouds -> "ASH_CLOUDS" + VastRuins -> "VAST_RUINS" + MutatedFlora -> "MUTATED_FLORA" + Terraformed -> "TERRAFORMED" + ExtremeTemperatures -> "EXTREME_TEMPERATURES" + ExtremePressure -> "EXTREME_PRESSURE" + DiverseLife -> "DIVERSE_LIFE" + ScarceLife -> "SCARCE_LIFE" + Fossils -> "FOSSILS" + WeakGravity -> "WEAK_GRAVITY" + StrongGravity -> "STRONG_GRAVITY" + CrushingGravity -> "CRUSHING_GRAVITY" + ToxicAtmosphere -> "TOXIC_ATMOSPHERE" + CorrosiveAtmosphere -> "CORROSIVE_ATMOSPHERE" + BreathableAtmosphere -> "BREATHABLE_ATMOSPHERE" + ThinAtmosphere -> "THIN_ATMOSPHERE" + Jovian -> "JOVIAN" + Rocky -> "ROCKY" + Volcanic -> "VOLCANIC" + Frozen -> "FROZEN" + Swamp -> "SWAMP" + Barren -> "BARREN" + Temperate -> "TEMPERATE" + Jungle -> "JUNGLE" + Ocean -> "OCEAN" + Radioactive -> "RADIOACTIVE" + MicroGravityAnomalies -> "MICRO_GRAVITY_ANOMALIES" + DebrisCluster -> "DEBRIS_CLUSTER" + DeepCraters -> "DEEP_CRATERS" + ShallowCraters -> "SHALLOW_CRATERS" + UnstableComposition -> "UNSTABLE_COMPOSITION" + HollowedInterior -> "HOLLOWED_INTERIOR" + Stripped -> "STRIPPED" + } +} + +pub fn parse( + waypoint_trait_symbol_str: String, +) -> Result(WaypointTraitSymbol, WaypointTraitSymbol) { + case waypoint_trait_symbol_str { + "UNCHARTED" -> Ok(Uncharted) + "UNDER_CONSTRUCTION" -> Ok(UnderConstruction) + "MARKETPLACE" -> Ok(Marketplace) + "SHIPYARD" -> Ok(Shipyard) + "OUTPOST" -> Ok(Outpost) + "SCATTERED_SETTLEMENTS" -> Ok(ScatteredSettlements) + "SPRAWLING_CITIES" -> Ok(SprawlingCities) + "MEGA_STRUCTURES" -> Ok(MegaStructures) + "PIRATE_BASE" -> Ok(PirateBase) + "OVERCROWDED" -> Ok(Overcrowded) + "HIGH_TECH" -> Ok(HighTech) + "CORRUPT" -> Ok(Corrupt) + "BUREAUCRATIC" -> Ok(Bureaucratic) + "TRADING_HUB" -> Ok(TradingHub) + "INDUSTRIAL" -> Ok(Industrial) + "BLACK_MARKET" -> Ok(BlackMarket) + "RESEARCH_FACILITY" -> Ok(ResearchFacility) + "MILITARY_BASE" -> Ok(MilitaryBase) + "SURVEILLANCE_OUTPOST" -> Ok(SurveillanceOutpost) + "EXPLORATION_OUTPOST" -> Ok(ExplorationOutpost) + "MINERAL_DEPOSITS" -> Ok(MineralDeposits) + "COMMON_METAL_DEPOSITS" -> Ok(CommonMetalDeposits) + "PRECIOUS_METAL_DEPOSITS" -> Ok(PreciousMetalDeposits) + "RARE_METAL_DEPOSITS" -> Ok(RareMetalDeposits) + "METHANE_POOLS" -> Ok(MethanePools) + "ICE_CRYSTALS" -> Ok(IceCrystals) + "EXPLOSIVE_GASES" -> Ok(ExplosiveGases) + "STRONG_MAGNETOSPHERE" -> Ok(StrongMagnetosphere) + "VIBRANT_AURORAS" -> Ok(VibrantAuroras) + "SALT_FLATS" -> Ok(SaltFlats) + "CANYONS" -> Ok(Canyons) + "PERPETUAL_DAYLIGHT" -> Ok(PerpetualDaylight) + "PERPETUAL_OVERCAST" -> Ok(PerpetualOvercast) + "DRY_SEABEDS" -> Ok(DrySeabeds) + "MAGMA_SEAS" -> Ok(MagmaSeas) + "SUPERVOLCANOES" -> Ok(Supervolcanoes) + "ASH_CLOUDS" -> Ok(AshClouds) + "VAST_RUINS" -> Ok(VastRuins) + "MUTATED_FLORA" -> Ok(MutatedFlora) + "TERRAFORMED" -> Ok(Terraformed) + "EXTREME_TEMPERATURES" -> Ok(ExtremeTemperatures) + "EXTREME_PRESSURE" -> Ok(ExtremePressure) + "DIVERSE_LIFE" -> Ok(DiverseLife) + "SCARCE_LIFE" -> Ok(ScarceLife) + "FOSSILS" -> Ok(Fossils) + "WEAK_GRAVITY" -> Ok(WeakGravity) + "STRONG_GRAVITY" -> Ok(StrongGravity) + "CRUSHING_GRAVITY" -> Ok(CrushingGravity) + "TOXIC_ATMOSPHERE" -> Ok(ToxicAtmosphere) + "CORROSIVE_ATMOSPHERE" -> Ok(CorrosiveAtmosphere) + "BREATHABLE_ATMOSPHERE" -> Ok(BreathableAtmosphere) + "THIN_ATMOSPHERE" -> Ok(ThinAtmosphere) + "JOVIAN" -> Ok(Jovian) + "ROCKY" -> Ok(Rocky) + "VOLCANIC" -> Ok(Volcanic) + "FROZEN" -> Ok(Frozen) + "SWAMP" -> Ok(Swamp) + "BARREN" -> Ok(Barren) + "TEMPERATE" -> Ok(Temperate) + "JUNGLE" -> Ok(Jungle) + "OCEAN" -> Ok(Ocean) + "RADIOACTIVE" -> Ok(Radioactive) + "MICRO_GRAVITY_ANOMALIES" -> Ok(MicroGravityAnomalies) + "DEBRIS_CLUSTER" -> Ok(DebrisCluster) + "DEEP_CRATERS" -> Ok(DeepCraters) + "SHALLOW_CRATERS" -> Ok(ShallowCraters) + "UNSTABLE_COMPOSITION" -> Ok(UnstableComposition) + "HOLLOWED_INTERIOR" -> Ok(HollowedInterior) + "STRIPPED" -> Ok(Stripped) + _ -> Error(Uncharted) + } +} + +pub fn decoder() -> Decoder(WaypointTraitSymbol) { + decode_utils.enum_decoder(parse, "WaypointTraitSymbol") +} diff --git a/src/models/waypoint_type.gleam b/src/models/waypoint_type.gleam new file mode 100644 index 0000000..9f0e2f7 --- /dev/null +++ b/src/models/waypoint_type.gleam @@ -0,0 +1,62 @@ +import gleam/dynamic/decode.{type Decoder} +import utils/decode as decode_utils + +pub type WaypointType { + Planet + GasGiant + Moon + OrbitalStation + JumpGate + AsteroidField + Asteroid + EngineeredAsteroid + AsteroidBase + Nebula + DebrisField + GravityWell + ArtificialGravityWell + FuelStation +} + +pub fn to_string(waypoint_type: WaypointType) -> String { + case waypoint_type { + Planet -> "PLANET" + GasGiant -> "GAS_GIANT" + Moon -> "MOON" + OrbitalStation -> "ORBITAL_STATION" + JumpGate -> "JUMP_GATE" + AsteroidField -> "ASTEROID_FIELD" + Asteroid -> "ASTEROID" + EngineeredAsteroid -> "ENGINEERED_ASTEROID" + AsteroidBase -> "ASTEROID_BASE" + Nebula -> "NEBULA" + DebrisField -> "DEBRIS_FIELD" + GravityWell -> "GRAVITY_WELL" + ArtificialGravityWell -> "ARTIFICIAL_GRAVITY_WELL" + FuelStation -> "FUEL_STATION" + } +} + +pub fn parse(waypoint_type_str: String) -> Result(WaypointType, WaypointType) { + case waypoint_type_str { + "PLANET" -> Ok(Planet) + "GAS_GIANT" -> Ok(GasGiant) + "MOON" -> Ok(Moon) + "ORBITAL_STATION" -> Ok(OrbitalStation) + "JUMP_GATE" -> Ok(JumpGate) + "ASTEROID_FIELD" -> Ok(AsteroidField) + "ASTEROID" -> Ok(Asteroid) + "ENGINEERED_ASTEROID" -> Ok(EngineeredAsteroid) + "ASTEROID_BASE" -> Ok(AsteroidBase) + "NEBULA" -> Ok(Nebula) + "DEBRIS_FIELD" -> Ok(DebrisField) + "GRAVITY_WELL" -> Ok(GravityWell) + "ARTIFICIAL_GRAVITY_WELL" -> Ok(ArtificialGravityWell) + "FUEL_STATION" -> Ok(FuelStation) + _ -> Error(Planet) + } +} + +pub fn decoder() -> Decoder(WaypointType) { + decode_utils.enum_decoder(parse, "WaypointType") +} diff --git a/src/utils/auth.gleam b/src/utils/auth.gleam new file mode 100644 index 0000000..6624afc --- /dev/null +++ b/src/utils/auth.gleam @@ -0,0 +1,71 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/http/request.{type Request} +import gleam/result +import utils/jwt + +pub opaque type AccountToken { + AccountToken(token: String) +} + +pub opaque type AgentToken { + AgentToken(token: String) +} + +pub type TokenParseError { + InvalidToken + IncorrectType +} + +pub fn parse_account_token( + token_str: String, +) -> Result(AccountToken, TokenParseError) { + use jwt <- result.try( + jwt.parse(token_str) |> result.replace_error(InvalidToken), + ) + case jwt.payload.subject { + "account-token" -> Ok(AccountToken(token_str)) + _ -> Error(IncorrectType) + } +} + +pub fn account_token_decoder() -> Decoder(AccountToken) { + use token_str <- decode.then(decode.string) + case parse_account_token(token_str) { + Ok(token) -> decode.success(token) + Error(_) -> decode.failure(AccountToken("invalid"), "AccountToken") + } +} + +pub fn parse_agent_token( + token_str: String, +) -> Result(AgentToken, TokenParseError) { + use jwt <- result.try( + jwt.parse(token_str) |> result.replace_error(InvalidToken), + ) + case jwt.payload.subject { + "agent-token" -> Ok(AgentToken(token_str)) + _ -> Error(IncorrectType) + } +} + +pub fn agent_token_decoder() -> Decoder(AgentToken) { + use token_str <- decode.then(decode.string) + case parse_agent_token(token_str) { + Ok(token) -> decode.success(token) + Error(_) -> decode.failure(AgentToken("invalid"), "AgentToken") + } +} + +pub type AuthMethod { + AccountAuth(AccountToken) + AgentAuth(AgentToken) + NoAuth +} + +pub fn set_auth(req: Request(a), auth_method: AuthMethod) -> Request(a) { + case auth_method { + NoAuth -> req + AccountAuth(AccountToken(token)) | AgentAuth(AgentToken(token)) -> + req |> request.set_header("Authorization", "Bearer " <> token) + } +} diff --git a/src/utils/decode.gleam b/src/utils/decode.gleam new file mode 100644 index 0000000..e55741d --- /dev/null +++ b/src/utils/decode.gleam @@ -0,0 +1,68 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/option.{type Option} +import models/meta +import utils/types.{type ErrorResponse, type PagedData, ErrorResponse, PagedData} + +pub fn data_decoder(decoder: Decoder(data)) -> Decoder(data) { + use data <- decode.field("data", decoder) + decode.success(data) +} + +pub fn paged_data_decoder(decoder: Decoder(data)) -> Decoder(PagedData(data)) { + use data <- decode.field("data", decoder) + use meta <- decode.field("meta", meta.decoder()) + decode.success(PagedData(data:, meta:)) +} + +pub fn error_response_decoder() -> Decoder(ErrorResponse) { + use code <- decode.field("code", decode.int) + use message <- decode.field("message", decode.string) + use data <- field_key_value_optional("data", decode.dynamic) + use request_id <- field_key_value_optional("requestId", decode.string) + decode.success(ErrorResponse(code:, message:, data:, request_id:)) +} + +pub fn error_decoder() -> Decoder(ErrorResponse) { + use data <- decode.field("error", error_response_decoder()) + decode.success(data) +} + +pub fn enum_decoder( + parse_enum: fn(String) -> Result(enum, enum), + expected: String, +) -> Decoder(enum) { + use enum_str <- decode.then(decode.string) + case parse_enum(enum_str) { + Ok(enum) -> decode.success(enum) + Error(enum) -> decode.failure(enum, expected) + } +} + +pub fn field_value_optional( + field: String, + decoder: Decoder(a), + next: fn(Option(a)) -> Decoder(b), +) { + decode.field(field, decode.optional(decoder), next) +} + +pub fn field_key_optional( + field: String, + decoder: Decoder(a), + next: fn(Option(a)) -> Decoder(b), +) { + decode.optional_field( + field, + option.None, + decode.map(decoder, option.Some), + next, + ) +} + +pub fn field_key_value_optional( + field: String, + decoder: Decoder(a), + next: fn(Option(a)) -> Decoder(b), +) { + decode.optional_field(field, option.None, decode.optional(decoder), next) +} diff --git a/src/utils/env.gleam b/src/utils/env.gleam new file mode 100644 index 0000000..10f985f --- /dev/null +++ b/src/utils/env.gleam @@ -0,0 +1,41 @@ +import dot_env +import dot_env/env +import gleam/result +import utils/auth.{type AccountToken, type AgentToken} + +pub type Env { + Env(account_token: AccountToken, agent_token: AgentToken) +} + +pub type EnvError { + MissingVar(name: String) + InvalidVar(name: String) +} + +fn get_string(name: String) -> Result(String, EnvError) { + env.get_string(name) |> result.replace_error(MissingVar(name)) +} + +pub fn load() -> Result(Env, EnvError) { + dot_env.default |> dot_env.load + use account_token <- result.try( + get_string("ACCOUNT_TOKEN") + |> result.then(fn(token_str) { + auth.parse_account_token(token_str) + |> result.replace_error(InvalidVar("ACCOUNT_TOKEN")) + }), + ) + use agent_token <- result.try( + get_string("AGENT_TOKEN") + |> result.then(fn(token_str) { + auth.parse_agent_token(token_str) + |> result.replace_error(InvalidVar("AGENT_TOKEN")) + }), + ) + Ok(Env(account_token:, agent_token:)) +} + +pub fn load_unsafe() -> Env { + let assert Ok(env) = load() as "Failed to load environment variables" + env +} diff --git a/src/utils/jwt.gleam b/src/utils/jwt.gleam new file mode 100644 index 0000000..a352d77 --- /dev/null +++ b/src/utils/jwt.gleam @@ -0,0 +1,137 @@ +import gleam/bit_array +import gleam/dynamic/decode.{type Decoder} +import gleam/json +import gleam/option.{type Option} +import gleam/result +import gleam/string +import utils/decode as decode_utils + +pub type JwtDecodeError { + MissingHeader + MissingPayload + MissingSignature + InvalidHeader + InvalidPayload + InvalidSignature + InvalidExpiration + TokenExpired + TokenNotValidYet + InvalidNotBefore + InvalidAlgorithm +} + +pub type JwtAlgorithm { + HS256 + HS384 + HS512 + RS256 + RS384 + RS512 + ES256 + ES384 + ES512 + PS256 + PS384 + PS512 + None +} + +pub fn parse_jwt_algorithm( + jwt_algorithm_str: String, +) -> Result(JwtAlgorithm, JwtAlgorithm) { + case jwt_algorithm_str { + "HS256" -> Ok(HS256) + "HS384" -> Ok(HS384) + "HS512" -> Ok(HS512) + "RS256" -> Ok(RS256) + "RS384" -> Ok(RS384) + "RS512" -> Ok(RS512) + "ES256" -> Ok(ES256) + "ES384" -> Ok(ES384) + "ES512" -> Ok(ES512) + "PS256" -> Ok(PS256) + "PS384" -> Ok(PS384) + "PS512" -> Ok(PS512) + "none" -> Ok(None) + _ -> Error(None) + } +} + +pub fn jwt_algorithm_decoder() -> Decoder(JwtAlgorithm) { + decode_utils.enum_decoder(parse_jwt_algorithm, "JwtAlgorithm") +} + +pub type JwtHeader { + JwtHeader(algorithm: JwtAlgorithm, token_type: String) +} + +fn jwt_header_decoder() -> Decoder(JwtHeader) { + use algorithm <- decode.field("alg", jwt_algorithm_decoder()) + use token_type <- decode.field("typ", decode.string) + decode.success(JwtHeader(algorithm:, token_type:)) +} + +pub type JwtPayload { + JwtPayload( + identifier: String, + version: String, + reset_date: Option(String), + issued_at: Int, + subject: String, + ) +} + +fn jwt_payload_decoder() -> Decoder(JwtPayload) { + use identifier <- decode.field("identifier", decode.string) + use version <- decode.field("version", decode.string) + use reset_date <- decode_utils.field_key_value_optional( + "reset_date", + decode.string, + ) + use issued_at <- decode.field("iat", decode.int) + use subject <- decode.field("sub", decode.string) + decode.success(JwtPayload( + identifier:, + version:, + reset_date:, + issued_at:, + subject:, + )) +} + +pub type Jwt { + Jwt(header: JwtHeader, payload: JwtPayload, signature: String) +} + +pub fn parse(token: String) -> Result(Jwt, JwtDecodeError) { + case string.split(token, ".") { + [encoded_header, encoded_payload, signature, ..] -> { + use header <- result.try( + bit_array.base64_url_decode(encoded_header) + |> result.replace_error(InvalidHeader) + |> result.then(fn(x) { + bit_array.to_string(x) |> result.replace_error(InvalidHeader) + }) + |> result.then(fn(x) { + json.parse(x, jwt_header_decoder()) + |> result.replace_error(InvalidHeader) + }), + ) + use payload <- result.try( + bit_array.base64_url_decode(encoded_payload) + |> result.replace_error(InvalidPayload) + |> result.then(fn(x) { + bit_array.to_string(x) |> result.replace_error(InvalidPayload) + }) + |> result.then(fn(x) { + json.parse(x, jwt_payload_decoder()) + |> result.replace_error(InvalidPayload) + }), + ) + Ok(Jwt(header:, payload:, signature:)) + } + [_, _] -> Error(MissingSignature) + [_] -> Error(MissingPayload) + [] -> Error(MissingHeader) + } +} diff --git a/src/utils/request.gleam b/src/utils/request.gleam new file mode 100644 index 0000000..78bbfce --- /dev/null +++ b/src/utils/request.gleam @@ -0,0 +1,144 @@ +import gleam/bit_array +import gleam/http.{type Method} +import gleam/http/request.{type Request} +import gleam/http/response.{type Response} +import gleam/httpc +import gleam/int +import gleam/json.{type Json} +import gleam/option +import gleam/result +import gleam/string_tree +import utils/auth.{type AuthMethod} +import utils/types.{type ApiResponse} + +const base_request = request.Request( + method: http.Get, + headers: [], + body: <<>>, + scheme: http.Https, + host: "api.spacetraders.io", + port: option.None, + path: "/v2", + query: option.None, +) + +fn set_body( + req: request.Request(a), + content_type: String, + body: BitArray, +) -> request.Request(BitArray) { + req + |> request.set_header("Content-Type", content_type) + |> request.set_body(body) +} + +fn set_text_body(req: Request(a), text: String) { + req |> set_body("text/plain", bit_array.from_string(text)) +} + +fn set_json_body(req: Request(a), json: Json) { + req + |> set_body( + "application/json", + json + |> json.to_string_tree + |> string_tree.to_string + |> bit_array.from_string, + ) +} + +fn make_request(method: Method, auth_method: AuthMethod, path: String) { + base_request + |> request.set_method(method) + |> auth.set_auth(auth_method) + |> request.set_path(base_request.path <> path) +} + +pub fn get(auth_method: AuthMethod, path: String) { + make_request(http.Get, auth_method, path) +} + +pub fn get_query( + auth_method: AuthMethod, + path: String, + query: List(#(String, String)), +) { + make_request(http.Get, auth_method, path) |> request.set_query(query) +} + +pub fn get_page(auth_method: AuthMethod, path: String, page: Int, limit: Int) { + make_request(http.Get, auth_method, path) + |> request.set_query([ + #("page", int.to_string(page)), + #("limit", int.to_string(limit)), + ]) +} + +pub fn get_page_query( + auth_method: AuthMethod, + path: String, + page: Int, + limit: Int, + query: List(#(String, String)), +) { + make_request(http.Get, auth_method, path) + |> request.set_query([ + #("page", int.to_string(page)), + #("limit", int.to_string(limit)), + ..query + ]) +} + +pub fn post(auth_method: AuthMethod, path: String) { + make_request(http.Post, auth_method, path) +} + +pub fn post_text(auth_method: AuthMethod, path: String, body: String) { + make_request(http.Post, auth_method, path) |> set_text_body(body) +} + +pub fn post_json(auth_method: AuthMethod, path: String, body: Json) { + make_request(http.Post, auth_method, path) |> set_json_body(body) +} + +pub fn patch(auth_method: AuthMethod, path: String) { + make_request(http.Patch, auth_method, path) +} + +pub fn patch_text(auth_method: AuthMethod, path: String, body: String) { + make_request(http.Patch, auth_method, path) |> set_text_body(body) +} + +pub fn patch_json(auth_method: AuthMethod, path: String, body: Json) { + make_request(http.Patch, auth_method, path) |> set_json_body(body) +} + +pub fn put(auth_method: AuthMethod, path: String) { + make_request(http.Put, auth_method, path) +} + +pub fn put_text(auth_method: AuthMethod, path: String, body: String) { + make_request(http.Put, auth_method, path) |> set_text_body(body) +} + +pub fn put_json(auth_method: AuthMethod, path: String, body: Json) { + make_request(http.Put, auth_method, path) |> set_json_body(body) +} + +pub fn delete(auth_method: AuthMethod, path: String) { + make_request(http.Delete, auth_method, path) +} + +pub fn send(request: Request(BitArray)) { + case httpc.send_bits(request) { + Ok(res) -> Ok(res) + Error(err) -> Error(types.HttpcError(err)) + } +} + +pub fn try_send( + request: Request(BitArray), + apply fun: fn(Response(BitArray)) -> ApiResponse(data), +) { + result.try(send(request), fun) +} diff --git a/src/utils/response.gleam b/src/utils/response.gleam new file mode 100644 index 0000000..cce69f6 --- /dev/null +++ b/src/utils/response.gleam @@ -0,0 +1,29 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json +import utils/decode as decode_utils +import utils/types.{type ApiResponse} + +pub fn parser(body: BitArray, decoder: Decoder(data)) -> ApiResponse(data) { + case json.parse_bits(body, decoder) { + Ok(data) -> Ok(data) + Error(err) -> Error(types.JsonDecodeError(err)) + } +} + +pub fn data_parser(body: BitArray, decoder: Decoder(data)) -> ApiResponse(data) { + parser(body, decode_utils.data_decoder(decoder)) +} + +pub fn paged_data_parser( + body: BitArray, + decoder: Decoder(data), +) -> ApiResponse(types.PagedData(data)) { + parser(body, decode_utils.paged_data_decoder(decoder)) +} + +pub fn error_parser(body: BitArray) -> ApiResponse(data) { + Error(case parser(body, decode_utils.error_decoder()) { + Ok(err) -> types.ResponseError(err) + Error(err) -> err + }) +} diff --git a/src/utils/types.gleam b/src/utils/types.gleam new file mode 100644 index 0000000..0d5fa4a --- /dev/null +++ b/src/utils/types.gleam @@ -0,0 +1,28 @@ +import gleam/dynamic.{type Dynamic} +import gleam/httpc.{type HttpError} +import gleam/json.{type DecodeError} +import gleam/option.{type Option} +import models/meta.{type Meta} + +pub type PagedData(data) { + PagedData(data: data, meta: Meta) +} + +pub type ErrorResponse { + ErrorResponse( + code: Int, + message: String, + data: Option(Dynamic), + request_id: Option(String), + ) +} + +pub type ApiError { + HttpcError(HttpError) + JsonDecodeError(DecodeError) + ResponseError(ErrorResponse) + UnknownError +} + +pub type ApiResponse(a) = + Result(a, ApiError) diff --git a/test/spacetraders_sdk_test.gleam b/test/spacetraders_sdk_test.gleam index fba3c88..fc57f7c 100644 --- a/test/spacetraders_sdk_test.gleam +++ b/test/spacetraders_sdk_test.gleam @@ -1,13 +1,20 @@ +import endpoints/accounts +import endpoints/global import gleeunit +import utils/env pub fn main() -> Nil { gleeunit.main() } -// gleeunit test functions end in `_test` -pub fn hello_world_test() { - let name = "Joe" - let greeting = "Hello, " <> name <> "!" - - assert greeting == "Hello, Joe!" +pub fn status_test() { + let assert Ok(_) = global.get_server_status() +} + +pub fn error_codes_test() { + let assert Ok(_) = global.list_error_codes() +} + +pub fn account_test() { + let assert Ok(_) = accounts.get_account(env.load_unsafe().agent_token) }