SukkaW/tayori(opens in a new tab)
Language: TypeScript
An opinionated React client-side data fetching stack built with Ky, SWR, Zod, and Hey API
- stars
- 13
- watchers
- 0
- forks
- 2
- open issues
- 0
- Last updated
- 10/10/2026
Language: TypeScript
An opinionated React client-side data fetching stack built with Ky, SWR, Zod, and Hey API
(便り, news from afar in Japanese)
An opinionated React client-side data fetching stack built on top of SWR, for Hey API and ConnectRPC backends
| Package | Backend | Docs |
|---|---|---|
tayori |
Hey API (OpenAPI) generated SDKs | tayori.skk.moe |
tayori-connect |
ConnectRPC (@connectrpc/connect v2 + @bufbuild/protobuf v2) |
tayori.skk.moe |
tayori-core |
Shared runtime, for adapter authors | – |
The documentation can be found at https://tayori.skk.moe.
The LLM friendly version of the documentation can be found at https://tayori.skk.moe/llms-full.txt.
Usage example can be found in the example-nextjs-app.
const { data, error } = useData( getAllPlanets, { query: { page: 1, per_page: 20 } } );
const { data, error } = useData( getAllPlanets, searchQuery ? { query: { q: searchQuery } } : null );
const { data } = useData( getPlanetById, () => (astronomer?.asteroidNamedAfter ? { path: { planetId: astronomer.asteroidNamedAfter } } : null) );
const { trigger, isMutating } = useMutation(updatePlanet); await trigger({ path: { planetId }, body: { name: nextName } });
const { data, size, setSize } = useInfinite( getAllPlanets, (i, prev) => (i > 0 && !prev?.nextCursor ? null // reached the end : { query: { cursor: prev?.nextCursor, perPage: 20 } }) );
The same hooks for a ConnectRPC backend, with tayori-connect:
import { tayoriConnect } from 'tayori-connect'; import { ElizaService } from './gen/connectrpc/eliza/v1/eliza_pb'; export const { TayoriProvider, useData, useMutation } = tayoriConnect(); // the method descriptor is the "SDK method", the second argument describes the request: // the request message under `message`, next to Connect's per-call options (`headers`, ...) const { data, error } = useData(ElizaService.method.say, { message: { sentence: 'Hello' } }); // mutations take the same request object (plus an optional `signal`) const { trigger, isMutating } = useMutation(ElizaService.method.say); await trigger({ message: { sentence: 'Save me' }, headers: { 'x-request-id': id } });
tayori © Sukka, Released under the MIT License. Authored and maintained by Sukka with help from contributors (list).
Personal Website · Blog · GitHub @SukkaW · Telegram Channel @SukkaChannel · Mastodon @sukka@acg.mn · Twitter @isukkaw · BlueSky @skk.moe