Skip to content

Skyhooks & Sovereignty Hubs ​

Needs an access token

Queries 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:skyhooks

examples/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();

Released under the GPL-3.0-or-later license.