diff --git a/bun.lockb b/bun.lockb index 089e5a4..5d43546 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/commands/events.ts b/commands/events.ts index 81c2bf3..e0a5305 100644 --- a/commands/events.ts +++ b/commands/events.ts @@ -1,14 +1,12 @@ import chalk from "chalk"; import boxen from "boxen"; import type { Command } from "commander"; - -import HellHub, { - type APIResponse, - type GlobalEvent, -} from "@hellhub-collective/sdk"; +import HellHub, { type GlobalEvent } from "@hellhub-collective/sdk"; import ascii from "utils/ascii"; -import { createListCommand, parseListOptions } from "utils/list-options"; +import request from "utils/request"; +import interval from "utils/interval"; +import { createListCommand, parseListOptions } from "utils/options"; const border = (message: string) => { if (message.includes("MAJOR")) { @@ -47,35 +45,13 @@ const description = (message: string) => { }; export default function events(program: Command) { - createListCommand( - program, - "events", - "fetch a list of events or get a event by id", - ).action(async (...args) => { - const [id, query] = parseListOptions(...args); - - let response: APIResponse | undefined; - if (!!id) { - response = await HellHub.events(id, { query }); - } else { - response = await HellHub.events({ - limit: 1, - sort: ["id:desc"], - ...query, - } as any); - } - - if (!response) { - console.error("An error occurred while fetching data."); - process.exit(1); - } + const handler = async (...args: any[]) => { + const [id, query] = parseListOptions(...args); - const { data, error } = await response.json(); - - if (!response.ok || !!error || !data) { - console.error(error?.details?.[0]); - process.exit(1); - } + const { data, url } = await request(HellHub.events, id, { + ...query, + ...(!id ? { limit: 1, sort: ["id:desc"] } : {}), + }); if (!!args[1].raw) { console.log(data); @@ -121,7 +97,17 @@ export default function events(program: Command) { if (!!args[1].url) { console.log(chalk.bold("\nRequest Source")); - console.log(chalk.gray(`/${response.url.split("/").slice(3).join("/")}`)); + console.log(chalk.gray(`/${url.split("/").slice(3).join("/")}`)); } + }; + + createListCommand( + program, + "events", + "fetch a list of events or get a event by id", + ).action(async (...args: any[]) => { + await handler(...args); + if (!args[1].watch) process.exit(0); + interval(async () => await handler(...args), args[1].watch); }); } diff --git a/commands/major.ts b/commands/major.ts index 7acdbb1..d9ec7bd 100644 --- a/commands/major.ts +++ b/commands/major.ts @@ -2,57 +2,25 @@ import chalk from "chalk"; import boxen from "boxen"; import { formatMoney } from "accounting"; import type { Command } from "commander"; - -import HellHub, { - type APIResponse, - type Assignment, -} from "@hellhub-collective/sdk"; +import HellHub, { type Assignment } from "@hellhub-collective/sdk"; import ascii from "utils/ascii"; -import { createListCommand, parseListOptions } from "utils/list-options"; +import request from "utils/request"; +import interval from "utils/interval"; +import { createListCommand, parseListOptions } from "utils/options"; export default function major(program: Command) { - createListCommand( - program, - "major", - "show details for the current major order", - ).action(async (...args) => { + const handler = async (...args: any[]) => { const [id, query] = parseListOptions(...args); - let response: APIResponse | undefined; - if (!!id) { - response = await HellHub.assignments(id, { - query: { - ...query, - include: [ - ...(Array.isArray(query.include) ? query.include : [] ?? []), - "reward", - ], - } as any, - }); - } else { - response = await HellHub.assignments({ - limit: 1, - sort: ["id:desc"], - ...query, - include: [ - ...(Array.isArray(query.include) ? query.include : [] ?? []), - "reward", - ], - } as any); - } - - if (!response) { - console.error("An error occurred while fetching data."); - process.exit(1); - } - - const { data, error } = await response.json(); - - if (!response.ok || !!error || !data) { - console.error(error?.details?.[0]); - process.exit(1); - } + const { data, url } = await request(HellHub.assignments, id, { + ...(!id ? { limit: 1, sort: ["id:desc"] } : {}), + ...query, + include: [ + ...(Array.isArray(query.include) ? query.include : [] ?? []), + "reward", + ], + }); if (!!args[1].raw) { console.log(data); @@ -107,7 +75,17 @@ export default function major(program: Command) { if (!!args[1].url) { console.log(chalk.bold("\nRequest Source")); - console.log(chalk.gray(`/${response.url.split("/").slice(3).join("/")}`)); + console.log(chalk.gray(`/${url.split("/").slice(3).join("/")}`)); } + }; + + createListCommand( + program, + "major", + "show details for the current major order", + ).action(async (...args: any[]) => { + await handler(...args); + if (!args[1].watch) process.exit(0); + interval(async () => await handler(...args), args[1].watch); }); } diff --git a/commands/planets.ts b/commands/planets.ts index c96b25d..9b8e81a 100644 --- a/commands/planets.ts +++ b/commands/planets.ts @@ -2,14 +2,12 @@ import chalk from "chalk"; import Table from "cli-table3"; import type { Command } from "commander"; import { formatMoney } from "accounting"; - -import HellHub, { - type APIResponse, - type Planet, -} from "@hellhub-collective/sdk"; +import HellHub, { type Planet } from "@hellhub-collective/sdk"; import ascii from "utils/ascii"; -import { createListCommand, parseListOptions } from "utils/list-options"; +import request from "utils/request"; +import interval from "utils/interval"; +import { createListCommand, parseListOptions } from "utils/options"; const owner = (index: number) => { switch (index) { @@ -25,31 +23,10 @@ const owner = (index: number) => { }; export default function planets(program: Command) { - createListCommand( - program, - "planets", - "fetch a list of planets or get a planet by id", - ).action(async (...args) => { - const [id, query] = parseListOptions(...args); - - let response: APIResponse | undefined; - if (!!id) { - response = await HellHub.planets(id, { query }); - } else { - response = await HellHub.planets(query); - } - - if (!response) { - console.error("An error occurred while fetching data."); - process.exit(1); - } - - const { data, error } = await response.json(); + const handler = async (...args: any[]) => { + const [id, query] = parseListOptions(...args); - if (!response.ok || !!error || !data) { - console.error(error?.details?.[0]); - process.exit(1); - } + const { data, url } = await request(HellHub.planets, id, query); if (!!args[1].raw) { console.log(data); @@ -115,7 +92,17 @@ export default function planets(program: Command) { if (!!args[1].url) { console.log(chalk.bold("\nRequest Source")); - console.log(chalk.gray(`/${response.url.split("/").slice(3).join("/")}`)); + console.log(chalk.gray(`/${url.split("/").slice(3).join("/")}`)); } + }; + + createListCommand( + program, + "planets", + "fetch a list of planets or get a planet by id", + ).action(async (...args: any[]) => { + await handler(...args); + if (!args[1].watch) process.exit(0); + interval(async () => await handler(...args), args[1].watch); }); } diff --git a/commands/reports.ts b/commands/reports.ts index 45ec359..3aa7608 100644 --- a/commands/reports.ts +++ b/commands/reports.ts @@ -1,14 +1,12 @@ import chalk from "chalk"; import boxen from "boxen"; import type { Command } from "commander"; - -import HellHub, { - type APIResponse, - type Report, -} from "@hellhub-collective/sdk"; +import HellHub, { type Report } from "@hellhub-collective/sdk"; import ascii from "utils/ascii"; -import { createListCommand, parseListOptions } from "utils/list-options"; +import request from "utils/request"; +import interval from "utils/interval"; +import { createListCommand, parseListOptions } from "utils/options"; const border = (message: string) => { if (message.includes("MAJOR")) { @@ -47,35 +45,13 @@ const description = (message: string) => { }; export default function reports(program: Command) { - createListCommand( - program, - "reports", - "fetch a list of reports or get a report by id", - ).action(async (...args) => { - const [id, query] = parseListOptions(...args); - - let response: APIResponse | undefined; - if (!!id) { - response = await HellHub.reports(id, { query }); - } else { - response = await HellHub.reports({ - limit: 1, - sort: ["id:desc"], - ...query, - } as any); - } - - if (!response) { - console.error("An error occurred while fetching data."); - process.exit(1); - } + const handler = async (...args: any[]) => { + const [id, query] = parseListOptions(...args); - const { data, error } = await response.json(); - - if (!response.ok || !!error || !data) { - console.error(error?.details?.[0]); - process.exit(1); - } + const { data, url } = await request(HellHub.reports, id, { + ...(!id ? { limit: 1, sort: ["id:desc"] } : {}), + ...query, + }); if (!!args[1].raw) { console.log(data); @@ -121,7 +97,17 @@ export default function reports(program: Command) { if (!!args[1].url) { console.log(chalk.bold("\nRequest Source")); - console.log(chalk.gray(`/${response.url.split("/").slice(3).join("/")}`)); + console.log(chalk.gray(`/${url.split("/").slice(3).join("/")}`)); } + }; + + createListCommand( + program, + "reports", + "fetch a list of reports or get a report by id", + ).action(async (...args: any[]) => { + await handler(...args); + if (!args[1].watch) process.exit(0); + interval(async () => await handler(...args), args[1].watch); }); } diff --git a/commands/sectors.ts b/commands/sectors.ts index ba39f5d..03f3767 100644 --- a/commands/sectors.ts +++ b/commands/sectors.ts @@ -1,41 +1,20 @@ import chalk from "chalk"; import Table from "cli-table3"; import type { Command } from "commander"; - -import HellHub, { - type Sector, - type APIResponse, -} from "@hellhub-collective/sdk"; +import HellHub, { type Sector } from "@hellhub-collective/sdk"; import ascii from "utils/ascii"; -import { createListCommand, parseListOptions } from "utils/list-options"; +import request from "utils/request"; +import interval from "utils/interval"; +import { createListCommand, parseListOptions } from "utils/options"; export default function sectors(program: Command) { - createListCommand( - program, - "sectors", - "fetch a list of sectors or get a sector by id", - ).action(async (...args) => { - const [id, query] = parseListOptions(...args); - - let response: APIResponse | undefined; - if (!!id) { - response = await HellHub.sectors(id, { query }); - } else { - response = await HellHub.sectors(query); - } - - if (!response) { - console.error("An error occurred while fetching data."); - process.exit(1); - } + const handler = async (...args: any[]) => { + const [id, query] = parseListOptions(...args); - const { data, error } = await response.json(); - - if (!response.ok || !!error || !data) { - console.error(error?.details?.[0]); - process.exit(1); - } + const { data, url } = await request(HellHub.sectors, id, { + ...query, + }); if (!!args[1].raw) { console.log(data); @@ -68,7 +47,17 @@ export default function sectors(program: Command) { if (!!args[1].url) { console.log(chalk.bold("\nRequest Source")); - console.log(chalk.gray(`/${response.url.split("/").slice(3).join("/")}`)); + console.log(chalk.gray(`/${url.split("/").slice(3).join("/")}`)); } + }; + + createListCommand( + program, + "sectors", + "fetch a list of sectors or get a sector by id", + ).action(async (...args: any[]) => { + await handler(...args); + if (!args[1].watch) process.exit(0); + interval(async () => await handler(...args), args[1].watch); }); } diff --git a/commands/statistics.ts b/commands/statistics.ts index 8125f19..2ff75da 100644 --- a/commands/statistics.ts +++ b/commands/statistics.ts @@ -1,41 +1,22 @@ import chalk from "chalk"; import Table from "cli-table3"; +import { formatMoney } from "accounting"; import type { Command } from "commander"; +import HellHub, { type Stat } from "@hellhub-collective/sdk"; import ascii from "utils/ascii"; -import { createListCommand, parseListOptions } from "utils/list-options"; -import HellHub, { type Stat, type APIResponse } from "@hellhub-collective/sdk"; -import { formatMoney } from "accounting"; +import request from "utils/request"; +import interval from "utils/interval"; +import { createListCommand, parseListOptions } from "utils/options"; export default function statistics(program: Command) { - createListCommand( - program, - "statistics", - "fetch a list of statistics or get a statistic by id", - ).action(async (...args) => { - const [id, query] = parseListOptions(...args); - - let response: APIResponse | undefined; - if (!!id) { - response = await HellHub.statistics(id, { query }); - } else { - response = await HellHub.statistics({ - ...query, - include: ["planet"], - } as any); - } - - if (!response) { - console.error("An error occurred while fetching data."); - process.exit(1); - } + const handler = async (...args: any[]) => { + const [id, query] = parseListOptions(...args); - const { data, error } = await response.json(); - - if (!response.ok || !!error || !data) { - console.error(error?.details?.[0]); - process.exit(1); - } + const { data, url } = await request(HellHub.statistics, id, { + ...query, + ...(!id ? { include: ["planet"] } : {}), + }); if (!!args[1].raw) { console.log(data); @@ -72,9 +53,8 @@ export default function statistics(program: Command) { ], }); - const items: (string | number)[][] = []; for (const p of entries) { - items.push( + table.push( [ p.planet?.name ?? "Entire Galaxy", formatMoney(p.deaths, "", 0, "'", "."), @@ -92,13 +72,21 @@ export default function statistics(program: Command) { ); } - table.push(...items); - console.log(table.toString()); if (!!args[1].url) { console.log(chalk.bold("\nRequest Source")); - console.log(chalk.gray(`/${response.url.split("/").slice(3).join("/")}`)); + console.log(chalk.gray(`/${url.split("/").slice(3).join("/")}`)); } + }; + + createListCommand( + program, + "statistics", + "fetch a list of statistics or get a statistic by id", + ).action(async (...args: any[]) => { + await handler(...args); + if (!args[1].watch) process.exit(0); + interval(async () => await handler(...args), args[1].watch); }); } diff --git a/commands/stratagems.ts b/commands/stratagems.ts index c5a7049..fcafe45 100644 --- a/commands/stratagems.ts +++ b/commands/stratagems.ts @@ -1,41 +1,20 @@ import chalk from "chalk"; import Table from "cli-table3"; import type { Command } from "commander"; - -import HellHub, { - type Stratagem, - type APIResponse, -} from "@hellhub-collective/sdk"; +import HellHub, { type Stratagem } from "@hellhub-collective/sdk"; import ascii from "utils/ascii"; -import { createListCommand, parseListOptions } from "utils/list-options"; +import request from "utils/request"; +import interval from "utils/interval"; +import { createListCommand, parseListOptions } from "utils/options"; export default function stratagems(program: Command) { - createListCommand( - program, - "stratagems", - "fetch a list of stratagems or get a stratagem by id", - ).action(async (...args) => { - const [id, query] = parseListOptions(...args); - - let response: APIResponse | undefined; - if (!!id) { - response = await HellHub.stratagems(id, { query }); - } else { - response = await HellHub.stratagems(query); - } - - if (!response) { - console.error("An error occurred while fetching data."); - process.exit(1); - } + const handler = async (...args: any[]) => { + const [id, query] = parseListOptions(...args); - const { data, error } = await response.json(); - - if (!response.ok || !!error || !data) { - console.error(error?.details?.[0]); - process.exit(1); - } + const { data, url } = await request(HellHub.stratagems, id, { + ...query, + }); if (!!args[1].raw) { console.log(data); @@ -69,9 +48,8 @@ export default function stratagems(program: Command) { ], }); - const items: (string | number)[][] = []; for (const p of entries) { - items.push([ + table.push([ p.id, p.codename ?? "", p.name, @@ -99,13 +77,21 @@ export default function stratagems(program: Command) { ]); } - table.push(...items); - console.log(table.toString()); if (!!args[1].url) { console.log(chalk.bold("\nRequest Source")); - console.log(chalk.gray(`/${response.url.split("/").slice(3).join("/")}`)); + console.log(chalk.gray(`/${url.split("/").slice(3).join("/")}`)); } + }; + + createListCommand( + program, + "stratagems", + "fetch a list of stratagems or get a stratagem by id", + ).action(async (...args: any[]) => { + await handler(...args); + if (!args[1].watch) process.exit(0); + interval(async () => await handler(...args), args[1].watch); }); } diff --git a/package.json b/package.json index 2a74304..a631aa2 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "license": "MIT", "private": false, "description": "The official CLI for HellHub API. Stay updated about the current war right without leaving your terminal.", - "version": "1.0.1", + "version": "1.1.0", "main": "build/index.mjs", "types": "build/index.d.ts", "keywords": [ @@ -33,6 +33,7 @@ "@types/chalk": "^2.2.0", "@typescript-eslint/eslint-plugin": "^7.4.0", "@typescript-eslint/parser": "^7.4.0", + "bun-plugin-dts": "^0.2.1", "bun-types": "^1.1.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", diff --git a/scripts/build.ts b/scripts/build.ts index ced5f51..7ab0fda 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -1,9 +1,10 @@ +import dts from "bun-plugin-dts"; + await Bun.build({ minify: true, target: "node", outdir: "./build", + plugins: [dts()], entrypoints: ["./index.ts"], naming: { entry: "[name].mjs" }, }); - -export {}; diff --git a/utils/ascii.ts b/utils/ascii.ts index b94a607..66f4dbf 100644 --- a/utils/ascii.ts +++ b/utils/ascii.ts @@ -5,6 +5,10 @@ export default async function ascii( name: string, replace: Record = {}, ) { + if (Bun.argv.includes("--no-ascii") || Bun.argv.includes("-a")) { + return; + } + const file = await fs.readFile( path.join(process.cwd(), "./ascii", `${name}.txt`), ); diff --git a/utils/interval.ts b/utils/interval.ts new file mode 100644 index 0000000..179a4da --- /dev/null +++ b/utils/interval.ts @@ -0,0 +1,25 @@ +import chalk from "chalk"; + +export default async function interval( + handler: () => Promise, + seconds: number, +) { + if (seconds < 60) { + console.error("Interval must be at least 60 seconds"); + process.exit(1); + } + + let i = 0; + while (true) { + if (i === 0) { + console.log(chalk.bold("\nWatcher Mode")); + console.log(chalk.gray("Waiting for the first update from source data")); + } + + i++; + await new Promise(resolve => setTimeout(resolve, seconds * 1000)); + await handler(); + console.log(chalk.bold("\nWatcher Mode")); + console.log(chalk.gray(`Update from source data ${i} times`)); + } +} diff --git a/utils/list-options.ts b/utils/options.ts similarity index 90% rename from utils/list-options.ts rename to utils/options.ts index d42f6e6..18d9358 100644 --- a/utils/list-options.ts +++ b/utils/options.ts @@ -1,5 +1,5 @@ import { Command } from "commander"; -import type { QueryObject } from "@hellhub-collective/sdk"; +import type { Entity, QueryObject } from "@hellhub-collective/sdk"; import type { ListOptions } from "types/list"; @@ -12,11 +12,17 @@ export function createListCommand( .command(command) .description(description) .argument("[id]", "the id of the entry to be fetched") - .option("-o, --order-by ", "the field to order by") .option("-u, --url [boolean]", "prints the request url") + .option("-o, --order-by ", "the field to order by") .option("-r, --raw [boolean]", "outputs the raw response body") + .option("-a, --no-ascii [boolean]", "disables the ascii art headers") .option("-s, --start ", "the number of entries to skip", parseInt) .option("-l, --limit ", "the number of entries to fetch", parseInt) + .option( + "-w, --watch [interval]", + "watch the data with a specified interval in seconds", + parseInt, + ) .option("-d, --direction ", "the direction to sort by", val => { if (["asc", "desc"].includes(val)) return val; console.error("Invalid direction. Use 'asc' or 'desc'"); @@ -50,9 +56,9 @@ export function createListCommand( ); } -export function parseListOptions( +export function parseListOptions( ...args: any[] -): [string | undefined, QueryObject] { +): [string | undefined, QueryObject] { const [id, options] = args as [string | undefined, ListOptions]; if (!!id && isNaN(parseInt(id)) && id !== "galaxy") { diff --git a/utils/request.ts b/utils/request.ts new file mode 100644 index 0000000..1e2080e --- /dev/null +++ b/utils/request.ts @@ -0,0 +1,52 @@ +import type { + Entity, + APIResponse, + QueryObject, + APIRequestInit, +} from "@hellhub-collective/sdk"; + +type RequestHandler = ( + input: any, + options?: APIRequestInit, +) => Promise>; + +export default async function request( + handler: RequestHandler, + id?: string | number | undefined, + query?: QueryObject | undefined, + options?: APIRequestInit, +) { + let response: APIResponse; + + if (!!id) { + response = await handler(id, { query, ...options }); + } else { + response = await handler(query ?? {}, options); + } + + if (!response) { + console.error("An unknown error occurred while fetching data."); + process.exit(1); + } + + if (response.status === 429) { + const now = Date.now(); + const reset = parseInt(response.headers.get("x-rate-reset") ?? "0", 10); + const seconds = Math.max(0, Math.ceil((reset - now) / 1000)); + + console.error( + `You are being rate limited. Please again in ${seconds} seconds.`, + ); + + process.exit(1); + } + + const { data, error } = await response.json(); + + if (!response.ok || !!error || !data) { + console.error(error?.details?.[0]); + process.exit(1); + } + + return { data, url: response.url } as any as { data: T | T[]; url: string }; +}