Building a package
Write a kitr package that the CLI can install and this site can list, with docs and a live example.
Every package on this site, official or not, is an ordinary npm package with three additions: a kitr block in its package.json, a docs folder, and optionally an examples folder. Publish it with the kitr-package keyword and it can be listed here.
The manifest
{
"name": "kitr-stripe",
"version": "1.0.0",
"keywords": ["kitr", "kitr-package"],
"files": ["dist", "docs"],
"kitr": {
"name": "stripe",
"title": "Stripe",
"summary": "Take card payments and subscriptions, with checkout pages you can restyle.",
"category": "backend",
"runsOn": "both",
"builtOn": ["stripe"],
"requires": ["server"],
"docs": "docs"
}
}
| Field | Required | Description |
|---|---|---|
name |
yes | The short name people type: kitr add stripe. |
title |
yes | Display name on this site. |
summary |
yes | One sentence, 140 characters at most, on what it does for the app. See below. |
category |
yes | Where the package is listed: data-fetching, app-state, backend, realtime, interface, forms, auth, pages, platforms, device, insights, dev-tools or kits. |
kind |
package (default), platform (added as kitr add <type> <name>) or kit (run by kitr new --kit <name>). |
|
runsOn |
yes | client, server or both. Shown as a badge. |
builtOn |
Upstream libraries it wraps, shown as "Built on". | |
requires |
Other kitr packages that must be added first. | |
client |
true if it needs a React frontend, so server-only projects refuse it. |
|
docs |
The docs folder, relative to the package root. Include it in files. |
Writing the summary
The summary is the first thing a beginner reads on the packages page, so it answers what will this do for my app? in plain words:
- Good: "Show rows of data with sorting, paging and filters that stay in the URL."
- Not: "TanStack Table v9 with URL-bound state." That only helps people who already know TanStack.
Put library names in builtOn, where they show as a separate note.
Docs
docs/
├── index.md # overview: what it's for, install, a working example, guides, configuration
└── api.md # reference: every export, option and type
Each file starts with frontmatter:
---
title: Stripe
description: Take card payments and subscriptions, with checkout pages you can restyle.
order: 1
---
The description of index.md must match the manifest summary. Follow the order the official packages use, so readers always know where to look:
- What it's for, in two or three sentences, and when not to use it.
- Install: the
kitr addcommand and what it changes. - A first working example they can paste.
- Guides for the common tasks.
- Configuration: a table of every option with its default.
- Next steps: the API page and the upstream docs.
Shell blocks that only contain kitr commands get the package-manager picker automatically. Link to other packages as /packages/<name>.
Follow docs/STYLE.md in the repo for the full rulebook. Check the manifest and docs before publishing:
kitr package:checkFirst time? Run npm i -g @kitr/kitr once. Inside a project, the global kitr runs your project's own version.
Live examples
Each examples/<name>.tsx becomes a live demo at the top of the package page, running in a sandboxed frame with a refresh button so readers can see what persists.
// examples/checkout.tsx
export const meta = {
title: 'Checkout',
description: 'Pay with a test card. Reload to see the order is kept.',
}
export default function Example() {
return <CheckoutButton priceId="price_test_123" />
}
Anything an example stores in the browser is namespaced to it, so examples never see each other's data.
Setup with kitr add
To let kitr add stripe wire your package, export a setup module as ./kitr:
// src/kitr.ts
import { definePackage } from '@kitr/core/package'
export default definePackage({
name: 'stripe',
requires: ['server'],
questions: [
{ name: 'mode', type: 'select', message: 'Checkout mode?', default: 'hosted',
options: [{ value: 'hosted' }, { value: 'embedded' }] },
],
add(ctx) {
ctx.provider.add('kitr-stripe/provider')
ctx.config('stripe', `export default { mode: '${ctx.answers.mode}' }\n`)
ctx.env.add({ STRIPE_SECRET_KEY: 'sk_test_...' })
ctx.agents.add('stripe', '- Payments go through the `stripe` service ...')
},
remove(ctx) {
ctx.provider.remove('kitr-stripe/provider')
ctx.agents.remove('stripe')
},
commands: () => import('./commands'), // `kitr stripe:sync-products`
generators: { webhook: { description: 'A Stripe webhook handler', target, stub } },
})
A generator follows the app's project structure when its target is one call to generatorFile from @kitr/core/package, which handles kebab-casing, the kind suffix and nested names (make:webhook billing/refunds writes server/webhooks/billing/refunds-webhook.ts):
import { generatorFile } from '@kitr/core/package'
const webhook = {
description: 'Create a Stripe webhook handler in server/webhooks',
definition: 'A handler for one Stripe event type.', // shown by `kitr make`
target: (name, project) => generatorFile(project, 'server', 'webhooks', name, { suffix: '-webhook' }),
stub: ({ name, pascal }) => `export default async function handle${pascal}Webhook() {}\n`,
}
Every question is also a flag: kitr add stripe --mode embedded. add and remove get helpers for the files kitr owns, such as kitrrc.ts, config/<name>.ts and package.json; ctx.write and ctx.edit cover anything else. Add "setup": "./kitr" to the manifest. Every ctx method is in the package contract.
A platform or a kit is the same package with a kind: a platform adds a platform block with its definePlatform factory, a kit adds a kit block naming the platforms, packages, components and files kitr new --kit sets up. The kits page shows a complete kit.
Publishing
npm publish
Add the kitr-package keyword so the package can be found.