dannykeane
v0.1.0
Published
Official TypeScript SDK and CLI for the dannykeane.com public API: work history, GitHub contributions, live stats, and the Habbo NPC chat. Zero dependencies.
Maintainers
Readme
dannykeane
Official TypeScript SDK and CLI for the dannykeane.com public API: Danny Keane's work history, GitHub contribution calendar, live visitor stats, and the Habbo room NPC chat.
Zero dependencies, native fetch. ESM with bundled types, Node 18.3+.
npm i dannykeaneUsage
import { DannyKeane } from "dannykeane";
const dk = new DannyKeane();
for await (const role of dk.iterWork()) console.log(role.company, role.years);Every endpoint is public, so there is no API key. Pass baseUrl to point at a local or preview deploy.
| Method | API operation | Endpoint |
| --- | --- | --- |
| listWork({ limit?, cursor? }) | listWork | GET /api/v1/work |
| iterWork({ limit? }) | listWork, every page | GET /api/v1/work |
| getStats() | getStats | GET /api/v1/stats |
| getGithubContributions() | getGithubContributions | GET /api/v1/github-contributions |
| npcChat({ message, npcId, context? }) | npcChat | POST /api/v1/npc-chat |
| npcChatHealth() | npcChatHealth | GET /api/v1/npc-chat |
| runBatch(["getStats", ...]) | runBatch | POST /api/v1/batch |
Every method also takes a last { signal } argument for cancellation. The full contract is the OpenAPI document at https://dannykeane.com/openapi.json.
Pagination
listWork returns one page: { data, next_cursor }, with next_cursor null on the last page. iterWork is an async iterator that follows the cursors for you.
Errors
Every non-2xx response rejects with ApiError, parsed from the API's ErrorResponse body:
import { ApiError, DannyKeane } from "dannykeane";
try {
await new DannyKeane().listWork({ limit: 50 });
} catch (error) {
if (error instanceof ApiError) console.log(error.status, error.code, error.message, error.hint);
// 400 invalid_parameter limit must be an integer from 1 to 20 ...
}error.body holds the full parsed body. Network failures reject with fetch's own error.
Rate limits
On a 429 the client waits out Retry-After and retries, up to maxRetries (default 2). A Retry-After longer than maxRetryDelay (default 60 seconds) rejects immediately instead, with the wait on error.retryAfter. Set maxRetries: 0 to handle every 429 yourself.
Options
new DannyKeane({
baseUrl: "http://localhost:3000", // default https://dannykeane.com
maxRetries: 2,
maxRetryDelay: 60, // seconds
timeout: 30_000, // ms, per attempt
userAgent: "my-agent/1.0", // appended to dannykeane-typescript/<version>
fetch: customFetch,
});CLI
The package ships a dannykeane command. Run it without installing:
npx dannykeane work --limit 5| Command | Operation |
| --- | --- |
| dannykeane work [--limit N] [--cursor TOKEN] [--all] | listWork; --all walks every page and prints one array |
| dannykeane stats | getStats |
| dannykeane github-contributions | getGithubContributions |
| dannykeane npc-chat [--npc-id ID] <message> | npcChat |
| dannykeane npc-chat-health | npcChatHealth |
| dannykeane batch <operationId>... | runBatch |
The API's JSON goes to stdout, indented when stdout is a terminal (--pretty forces it). Failures go to stderr as one line of ErrorResponse JSON, with stdout empty. --base-url or DANNYKEANE_BASE_URL points it at another deploy.
Exit codes: 0 success, 1 the API returned an error, 2 usage error, 3 the API could not be reached.
The PyPI package dannykeane ships the same client and CLI for Python.
Links
- Developer docs: https://dannykeane.com/developers
- OpenAPI spec: https://dannykeane.com/openapi.json
- Contact: [email protected]
License
MIT
