Skyhooks & Sovereignty Hubs
Needs an access tokenQueries Upwell sovereignty structures — sovereignty hubs, orbital skyhooks with silo levels, and currently raidable skyhooks.
Note: Sovereignty hub and skyhook endpoints require authentication. The raidable skyhooks endpoint is public. Some endpoints may return 404 if CCP has not yet deployed skyhook content to the current server version.
Calls: skyhooks.getSovereigntyHubs · skyhooks.getOrbitalSkyhooks · skyhooks.getRaidableSkyhooks · skyhooks.getSkyhookDetail · skyhooks.getSovereigntyHubDetail
Run it
bash
git clone https://github.com/lgriffin/ESI.ts.git && cd ESI.ts
npm ci
npm run example:skyhooksexamples/skyhooks.ts on GitHub. The imports below are written as a consumer of the package writes them; the file in the repository imports from ../src.
Source
ts
import { EsiClient } from '@lgriffin/esi.ts';
import { isNotFound } from '@lgriffin/esi.ts/errors';
import { createConsoleLogger } from '@lgriffin/esi.ts';
// The program's own output. The client logs through the same console sink
// at ESI_LOG_LEVEL (default warn), so its diagnostics stay out of the way.
const log = createConsoleLogger('info');
const esiLog = createConsoleLogger();
async function main() {
const client = new EsiClient({ logger: esiLog });
// Corporation ID to query sovereignty structures for
const corporationId = parseInt(process.env.CORPORATION_ID || '0', 10);
if (!corporationId) {
log.error(
'Set CORPORATION_ID environment variable to your corporation ID.',
);
process.exit(1);
}
try {
log.info('Skyhooks & Sovereignty Hubs\n');
let hubs: Awaited<ReturnType<typeof client.skyhooks.getSovereigntyHubs>>;
let skyhooks: Awaited<
ReturnType<typeof client.skyhooks.getOrbitalSkyhooks>
>;
let raidable: Awaited<
ReturnType<typeof client.skyhooks.getRaidableSkyhooks>
>;
try {
[hubs, skyhooks, raidable] = await Promise.all([
client.skyhooks.getSovereigntyHubs(corporationId),
client.skyhooks.getOrbitalSkyhooks(corporationId),
client.skyhooks.getRaidableSkyhooks(),
]);
} catch (err) {
if (isNotFound(err)) {
log.info(
'Skyhook endpoints are not currently available on this ESI version.',
);
log.info(
'These endpoints may be deployed in a future EVE Online patch.',
);
return;
}
throw err;
}
const hubList = hubs.sovereignty_hubs;
const skyhookList = skyhooks.skyhooks;
log.info('Sovereignty Hubs');
log.info('-'.repeat(60));
log.info(` Total: ${hubList.length}`);
for (const hub of hubList.slice(0, 5)) {
log.info(` Hub ${hub.id} — System ${hub.solar_system_id}`);
}
if (hubList.length > 5) log.info(` ... and ${hubList.length - 5} more`);
log.info('\nOrbital Skyhooks');
log.info('-'.repeat(60));
log.info(` Total: ${skyhookList.length}`);
for (const sk of skyhookList.slice(0, 5)) {
log.info(` Skyhook ${sk.id} — Planet ${sk.planet_id}`);
}
if (skyhookList.length > 5)
log.info(` ... and ${skyhookList.length - 5} more`);
log.info('\nRaidable Skyhooks');
log.info('-'.repeat(60));
// A skyhook is open to theft between its window's start and end.
const now = Date.now();
const windows = raidable.skyhooks.map((r) => ({
...r,
start: Date.parse(r.theft_vulnerability.start),
end: Date.parse(r.theft_vulnerability.end),
}));
const nowRaidable = windows.filter((r) => r.start <= now && now < r.end);
const upcoming = windows.filter((r) => r.start > now);
log.info(` Currently raidable: ${nowRaidable.length}`);
log.info(` Becoming raidable: ${upcoming.length}`);
for (const r of nowRaidable.slice(0, 5)) {
log.info(
` Planet ${r.planet_id} (system ${r.solar_system_id}) — RAIDABLE until ${r.theft_vulnerability.end}`,
);
}
for (const r of upcoming.slice(0, 3)) {
log.info(
` Planet ${r.planet_id} (system ${r.solar_system_id}) — raidable from ${r.theft_vulnerability.start}`,
);
}
// Fetch detail for the first skyhook
const firstSkyhooks = skyhookList[0];
if (firstSkyhooks) {
log.info('\nSkyhook Detail');
log.info('-'.repeat(60));
const detail = await client.skyhooks.getSkyhookDetail(
corporationId,
firstSkyhooks.id,
);
log.info(
` Skyhook ${detail.id} — Planet ${detail.planet_id} — State: ${detail.state}`,
);
log.info(
` Active: ${detail.is_active} — Workforce: ${detail.effective_workforce ?? 'N/A'}`,
);
if (detail.reagents?.length) {
for (const r of detail.reagents) {
log.info(
` Reagent ${r.type_id}: Secured ${r.secured_stock} / Unsecured ${r.unsecured_stock}`,
);
}
}
if (detail.theft_vulnerability) {
log.info(
` Theft window: ${detail.theft_vulnerability.start} — ${detail.theft_vulnerability.end}`,
);
}
}
// Fetch detail for the first sovereignty hub
const firstHubs = hubList[0];
if (firstHubs) {
log.info('\nSovereignty Hub Detail');
log.info('-'.repeat(60));
const hubDetail = await client.skyhooks.getSovereigntyHubDetail(
corporationId,
firstHubs.id,
);
log.info(` Hub ${hubDetail.id} — System ${hubDetail.solar_system_id}`);
log.info(` Upgrades: ${hubDetail.upgrades.length}`);
for (const u of hubDetail.upgrades.slice(0, 5)) {
log.info(` Type ${u.type_id} — ${u.power_state}`);
}
const { power, workforce } = hubDetail.resources;
log.info(` Power: ${power.allocated} / ${power.available} allocated`);
log.info(
` Workforce: ${workforce.allocated} / ${workforce.available} allocated`,
);
log.info(
` Reagent bay last updated: ${hubDetail.reagent_bay.last_updated}`,
);
if (hubDetail.vulnerability_window) {
log.info(
` Vulnerability: ${hubDetail.vulnerability_window.start} — ${hubDetail.vulnerability_window.end}`,
);
}
}
} catch (err) {
log.error('Request failed', { error: err });
process.exit(1);
} finally {
await client.shutdown();
}
}
main();