cohost-client
v0.2.5
Published
TypeScript SDK for the Cohost API — auto-generated from OpenAPI spec
Maintainers
Readme
cohost-client
TypeScript SDK for the Cohost External API. Fully typed API client auto-generated from the OpenAPI spec using Orval.
Features
- Fully typed request/response types generated from OpenAPI spec
- Works in both browser and Node.js (18+)
- Two auth modes: API Key (backend) and JWT Bearer (frontend)
- Self-updating — regenerate types and functions with
npm run generate - Zero runtime dependencies (uses native
fetch)
Installation
npm install cohost-clientThe Auth Architecture
The Cohost API uses two distinct auth mechanisms:
| Endpoint group | Auth required | Who calls it |
|---|---|---|
| /api/v1/external/* | X-API-Key header | Your server only |
| /api/v1/checkout/*, /api/v1/bookings/my, /api/v1/auth/me | Bearer <JWT> | Your frontend |
Never expose your API key in client-side code. Environment variables prefixed with
NEXT_PUBLIC_,VITE_,REACT_APP_, etc. get bundled into your JS and are readable by anyone in DevTools. Keep the key in unprefixed server-only env vars.
The intended flow:
Browser Your Server Cohost API
│ │ │
│── POST /auth/login ───────►│ │
│ │── customerLogin...() ─►│ (X-API-Key)
│ │◄── { access_token } ───│
│◄── { access_token } ──────│ │
│ │ │
│ setBearerToken(token) │ │
│── getListings...() ───────────────────────────────►│ (Bearer JWT)Quick Start
Server-side (API key)
// lib/cohost-server.ts — never import from a 'use client' component
import {
configureClient,
getListingsApiV1ExternalListingsGet,
} from "cohost-client";
configureClient({
apiKey: process.env.COHOST_API_KEY, // no NEXT_PUBLIC_ prefix
});
export async function fetchListings() {
const res = await getListingsApiV1ExternalListingsGet();
return res.data;
}After login (JWT)
import {
configureClient,
customerLoginApiV1ExternalCustomersLoginPost,
setBearerToken,
getListingsApiV1ExternalListingsGet,
} from "cohost-client";
configureClient({ apiKey: "cohost_api_xxx" });
const login = await customerLoginApiV1ExternalCustomersLoginPost({
email: "[email protected]",
password: "…",
});
setBearerToken(login.data.access_token);
const listings = await getListingsApiV1ExternalListingsGet();Configuration
configureClient(options)
Call once at startup (or per request in server code). All generated functions use this global config.
import { configureClient } from "cohost-client";
configureClient({
baseUrl: "https://v2-staging.api.cohost.ai",
apiKey: process.env.COHOST_API_KEY,
bearerToken: "eyJhbGciOi...", // optional pre-set JWT
customFetch: myFetch, // optional — see below
onRequest: (url, init) => init,
onResponseError: (response, url) => {},
});Auth headers
- If
apiKeyis set → every request getsX-API-Key(unless already present). - If
bearerTokenis set (viaconfigureClientorsetBearerToken) →Authorization: Bearer …is added.
JWT persistence (localStorage, cookies, etc.) is your responsibility — read the token and call setBearerToken when your app loads or after login.
setBearerToken / setApiKey
Update credentials at runtime without re-calling configureClient.
Custom fetch implementation
By default the SDK uses the global fetch. Pass customFetch to replace it with any compatible transport — useful for Angular, testing, or custom middleware.
Angular (HttpClient)
Angular's HttpClient returns Observables rather than Promise<Response>, so wrap it to match the fetch signature:
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { firstValueFrom } from "rxjs";
import { configureClient } from "cohost-client";
@Injectable({ providedIn: "root" })
export class CohostService {
constructor(private http: HttpClient) {
configureClient({
apiKey: "cohost_api_xxx",
customFetch: (url, init) =>
firstValueFrom(
this.http.request(
new Request(url, init)
)
),
});
}
}Testing (mock fetch)
import { configureClient } from "cohost-client";
configureClient({
customFetch: async (url, init) => {
return new Response(JSON.stringify({ data: "mocked" }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
},
});Node.js (custom agent, proxies, etc.)
import { configureClient } from "cohost-client";
import { fetch, Agent } from "undici";
configureClient({
customFetch: (url, init) =>
fetch(url, {
...init,
dispatcher: new Agent({ connect: { timeout: 10_000 } }),
}) as Promise<Response>,
});Error Handling
Non-2xx responses throw CohostApiError with status, statusText, body, and url:
import {
CohostApiError,
listCustomersApiV1ExternalCustomersGet,
} from "cohost-client";
try {
await listCustomersApiV1ExternalCustomersGet();
} catch (error) {
if (error instanceof CohostApiError) {
console.error(error.status, error.body);
}
}Successful responses are { data, status, headers } (Orval fetch client shape). Inspect status on the returned object if you need to branch on 200 vs 201, etc.
API Reference (generated)
Function names follow the OpenAPI operationIds. Import from cohost-client — they are grouped in modules by tag: customers, bookings, listings, reference.
Customers (./generated/customers re-exported)
| Function | Description |
|---|---|
| customerLoginApiV1ExternalCustomersLoginPost | Customer login |
| registerCustomerApiV1ExternalCustomersRegisterPost | Register customer |
| listCustomersApiV1ExternalCustomersGet | List customers |
| getCustomerApiV1ExternalCustomersUserIdGet | Get customer |
| updateCustomerApiV1ExternalCustomersUserIdPatch | Update customer |
| removeCustomerFromTeamApiV1ExternalCustomersUserIdTeamsTeamIdDelete | Remove from team |
| resendVerificationApiV1ExternalCustomersUserIdResendVerificationPost | Resend verification |
| checkCustomerEmailVerificationApiV1ExternalCustomersUserIdEmailVerificationGet | Email verification status |
Listings
| Function | Description |
|---|---|
| getListingsApiV1ExternalListingsGet | List listings |
| getListingDetailApiV1ExternalListingsListingIdGet | Detail by ID |
| getListingDetailBySlugApiV1ExternalListingsSlugSlugGet | Detail by slug |
| getListingAvailabilityApiV1ExternalListingsListingIdAvailabilityGet | Availability by ID |
| getListingAvailabilityBySlugApiV1ExternalListingsSlugSlugAvailabilityGet | Availability by slug |
Bookings
| Function | Description |
|---|---|
| previewExternalBookingApiV1ExternalBookingsPreviewPost | Preview pricing |
| createExternalBookingApiV1ExternalBookingsPost | Create booking |
| listExternalBookingsApiV1ExternalBookingsGet | List bookings |
| getExternalBookingDetailApiV1ExternalBookingsBookingIdGet | Booking detail |
Reference
| Function | Description |
|---|---|
| getCatalogsApiV1ExternalCatalogsGet | Catalogs |
| getAmenitiesApiV1ExternalAmenitiesGet | Amenities |
| listCountriesApiV1ExternalLocationsCountriesGet | Countries |
| listProvincesApiV1ExternalLocationsCountryCodeProvincesGet | Provinces |
Request/response types live under export * from "./generated/schemas" — import named types from cohost-client (e.g. CustomerLoginRequest).
Updating the SDK
When the Cohost API spec changes, regenerate the client:
# Fetch latest spec and regenerate all types + functions
npm run generate
# Or step by step:
npm run generate:fetch # Download latest OpenAPI spec
npm run generate:clean # Remove old generated code
npm run generate:orval # Regenerate TypeScript client
# Then rebuild
npm run build:onlyThe full npm run build command runs the entire pipeline: fetch spec → generate code → bundle.
CI/CD Auto-Update
You can set up a scheduled CI job to auto-detect API changes:
# .github/workflows/update-sdk.yml
name: Update SDK
on:
schedule:
- cron: "0 */6 * * *" # Every 6 hours
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run generate
- run: npm run build:only
- uses: peter-evans/create-pull-request@v6
with:
title: "chore: update SDK from latest API spec"
commit-message: "chore: regenerate SDK from latest OpenAPI spec"
branch: auto-update-sdkDevelopment
# Install dependencies
npm install
# Generate client from OpenAPI spec
npm run generate
# Build library
npm run build:only
# Full pipeline (generate + build)
npm run build
# Type check
npm run typecheck
# Watch mode
npm run devArchitecture
src/
├── fetcher.ts # configureClient + mutator used by Orval-generated functions
├── index.ts # Barrel exports
└── generated/ # Auto-generated by Orval (do not edit)
├── customers/
├── bookings/
├── listings/
├── reference/
└── schemas/Compatibility
Runtime environments
The SDK uses only standard Web APIs (fetch, Headers, Request, Response) with no runtime dependencies, so it runs anywhere these are natively available:
| Environment | Min version | Notes |
|---|---|---|
| Node.js | 18.0.0+ | Native fetch added in Node 18 |
| Bun | Any stable | Native fetch supported |
| Deno | Any stable | Native fetch supported |
| Cloudflare Workers | — | Fully supported |
| Vercel Edge / Netlify Edge | — | Fully supported |
| Modern browsers | — | All evergreen browsers |
Node 16 and below are not supported — they do not have native
fetch.
Module formats
The package ships both formats so it works regardless of your project setup:
| Format | File | Use case |
|---|---|---|
| ESM | dist/index.mjs | import in modern projects, bundlers, Vite, Next.js |
| CJS | dist/index.cjs | require() in older Node.js setups |
TypeScript declarations are included for both formats (.d.mts / .d.cts).
Frontend frameworks
The SDK is framework-agnostic and works with any frontend framework out of the box:
| Framework | Works | Notes |
|---|---|---|
| React / Next.js / Remix | ✓ | Wrap calls in @tanstack/react-query or swr for loading/caching |
| Vue / Nuxt | ✓ | Wrap in a composable or use vue-query |
| Svelte / SvelteKit | ✓ | Use in load functions or stores |
| Solid.js | ✓ | Use with createResource |
| Astro | ✓ | Use in .astro frontmatter or API routes |
| Angular | ✓ | Wrap in an @Injectable service; plug in HttpClient via customFetch |
| Plain JS/TS | ✓ | No framework required |
The SDK does not ship framework-specific hooks or bindings. This keeps it lean and lets you integrate it with whichever data-fetching layer your app already uses.
TypeScript
TypeScript 5.0+ is recommended. The generated types use modern TypeScript features. Older versions may work but are not tested.
License
MIT
