Skip to content

refactor: use @openrouter/sdk typed client in scripts instead of hand-rolled fetch to eliminate API shape drift #12

@perry-the-pr-reviewer

Description

@perry-the-pr-reviewer

Problem

All scripts (list-models.ts, get-endpoints.ts, compare-models.ts, etc.) share a hand-rolled HTTP layer in lib.ts:

export async function fetchApi(path: string, apiKey?: string): Promise<any> {
  const url = `https://openrouter.ai/api/v1${path}`;
  const res = await fetch(url, { headers });
  // manual switch(res.status) error handling...
  return res.json(); // return type: any
}

The return type is any throughout. This means:

  • New API fields (canonical_slug, knowledge_cutoff, default_parameters) go undiscovered until someone manually audits the response and files a docs PR like docs: add API response shapes across skills #10
  • Error handling is duplicated across scripts
  • There's no compile-time signal when the API shape changes

PR #10 is a direct symptom: it exists because the skill docs drifted from the live API, and the fix was to manually embed JSON shapes in SKILL.md — creating a second source of truth that will drift again.

What to do instead

Replace fetchApi() in each lib.ts with the @openrouter/sdk typed client (@openrouter/sdk covers model listing, chat completions, credits, and OAuth). This gives:

  • Typed responses — new/removed fields surface as compile errors, not silent drift
  • Standardized error handling — no more per-script switch (res.status) blocks
  • Free updates — SDK version bumps propagate API changes to all scripts automatically

The CLI interface, custom formatting logic (formatModel(), pricing per-million conversion, status code → string), and custom algorithms stay in the scripts. Only the HTTP transport layer changes.

Tradeoff to consider

Adding @openrouter/sdk as a dependency increases the install footprint. The current scripts have only tsx as a devDep. If portability across minimal agent environments is a hard constraint, an alternative is generating TypeScript types from openrouter.ai/openapi.yaml at build time (no runtime dependency, types only).

Reviewed by Perry

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions