npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

kyro-connect

v0.11.1

Published

Universal SDK for Kyro CMS. Type-safe client + codegen for any platform.

Readme

kyro-connect

Universal SDK for Kyro CMS. Type-safe client for any platform — Node.js, browser, Deno, Bun.

npm install kyro-connect

Quick Start

1. Generate types

npx kyro-codegen --url http://localhost:4321/api --api-key kyro_xxx

Fetches your CMS schema and generates kyro.generated.d.ts with full type definitions for every collection, global, and procedure.

2. Use the client

import { createClient } from "kyro-connect";
import type { AppRouter } from "./kyro.generated";

const api = createClient<AppRouter>({
  url: "http://localhost:4321/api/trpc",
  apiKey: "kyro_xxx",
});

API

createClient(options)

Creates a proxy-based client for your Kyro CMS tRPC endpoint. Each property access builds a procedure path, and calling it triggers the request.

All three calling patterns are supported and interchangeable:

  • api["posts"].find(input) — direct call
  • api["posts"].find.query(input) — explicit query
  • api["posts"].create.mutate(input) — explicit mutation (for writes)
const api = createClient<AppRouter>({
  url: "http://localhost:4321/api/trpc",
  apiKey: "kyro_xxx",
  fetch: globalThis.fetch,
});

| Option | Type | Default | Description | |---|---|---|---| | url | string | — | Base URL of the tRPC endpoint | | apiKey | string | — | API key for authenticated requests | | fetch | typeof globalThis.fetch | globalThis.fetch | Custom fetch implementation |

Using environment variables

const api = createClient<AppRouter>({
  url: process.env.KYRO_API_URL!,
  apiKey: process.env.KYRO_API_KEY!,
});

Query procedures (GET)

All three patterns work:

// Direct call
const { docs } = await api["posts"].find({ page: 1, limit: 10 });
// docs: Post[]

// Explicit .query()
const { docs } = await api["posts"].find.query({ page: 1, limit: 10 });

const post = await api["posts"].findByID({ id: "abc123" });
// post: Post

const { totalDocs } = await api["posts"].count({
  where: { status: { equals: "published" } },
});
// totalDocs: number

Mutation procedures (POST)

// Direct call (creates/updates/deletes are auto-detected as POST)
const { doc } = await api["posts"].create({
  data: { title: "Hello", slug: "hello" },
});
// doc: Post

// Explicit .mutate()
const { doc } = await api["posts"].create.mutate({
  data: { title: "Hello", slug: "hello" },
});

const { doc } = await api["posts"].update({
  id: "abc",
  data: { title: "Updated" },
});
// doc: Post

const { doc, message } = await api["posts"].delete({ id: "abc" });
// doc: Post, message: string

Globals

const settings = await api["_globals_site-settings"].get();
// settings: SiteSettingsGlobal

await api["_globals_site-settings"].update({
  data: { siteName: "New Name" },
});

Collections with hyphens in slug

Use bracket notation:

const data = await api["my-collection"].find({ page: 1 });

Codegen

CLI

# Basic
npx kyro-codegen --url http://localhost:4321/api --api-key kyro_xxx

# Custom output path
npx kyro-codegen --url http://localhost:4321/api --api-key kyro_xxx --output src/types/kyro.d.ts

Generated types

Running codegen produces kyro.generated.d.ts containing:

  • Doc types — TypeScript interfaces for each collection and global, derived from field definitions
  • Input types — typed inputs for every procedure (PostsFindInput, PostsCreateInput, etc.)
  • Output types — typed outputs for every procedure (PostsFindOutput, etc.)
  • AppRouter — mapped type linking all collection/global procedures to their input/output types

Without codegen

The client works without types — everything is any:

const api = createClient({ url: "...", apiKey: "..." });
const posts = await api["posts"].find({ page: 1 });
// posts: any

Transport

Request format

The client communicates with the Kyro tRPC endpoint. Each procedure call maps to an HTTP request:

| Procedure type | HTTP method | URL | Body | |---|---|---|---| | find, findByID, count | GET | /api/trpc/{slug}.{proc}?input={json} | — | | create, update, delete | POST | /api/trpc/{slug}.{proc} | JSON body |

Authentication

API key is sent as the x-api-key header on every request. If the server session cookie is already present (browser environment), the apiKey option can be omitted.


Errors

KyroConnectError

Thrown when the server responds with a non-2xx status code.

import { createClient, KyroConnectError } from "kyro-connect";

try {
  await api["posts"].find({ page: 1 });
} catch (err) {
  if (err instanceof KyroConnectError) {
    console.error(err.message); // Server error message
    console.error(err.status);  // HTTP status code
  }
}

Error scenarios

| Scenario | Error type | Cause | |---|---|---| | Network failure | TypeError | DNS, connection refused, timeout | | Server error response | KyroConnectError | 4xx or 5xx status with JSON body | | Invalid response body | SyntaxError | Non-JSON response | | Access denied | KyroConnectError with status: 403 | Missing or invalid API key | | Not found | KyroConnectError with status: 404 | Collection or document not found |


Platform support

| Platform | Native fetch | Status | |---|---|---| | Node.js 18+ | ✅ | Full support | | Browser | ✅ | Full support | | Deno | ✅ | Full support | | Bun | ✅ | Full support | | Cloudflare Workers | ✅ | Full support | | Vercel Edge Runtime | ✅ | Full support | | Node.js 16-17 | ⚠️ | Requires polyfill or --experimental-fetch |


TypeScript configuration

Ensure the generated types are visible to the TypeScript compiler:

// tsconfig.json
{
  "include": ["src", "kyro.generated.d.ts"]
}

Or place kyro.generated.d.ts inside your src/ directory.


Development

git clone <repo>
cd packages/kyro-connect
pnpm install
pnpm build

Local testing

# Link the package globally
pnpm link --global

# In your consumer project
pnpm link kyro-connect
npx kyro-codegen --url http://localhost:4321/api --api-key kyro_xxx

License

MIT