Extend

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:

  1. What it's for, in two or three sentences, and when not to use it.
  2. Install: the kitr add command and what it changes.
  3. A first working example they can paste.
  4. Guides for the common tasks.
  5. Configuration: a table of every option with its default.
  6. 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:check

First 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.