Source: https://www.hype-stack.dev/docs/packs-templates/run-your-own-registry

# Run your own registry

A registry is anywhere that answers one GET with one JSON document. Buyers point a namespace at it in `stack.json` and
install with `@you/pack-name`. Whether they're allowed to have the pack is your server's call, made before it serves a
byte. The CLI attaches a credential and reads the answer. It never decides entitlement, and it never sees your prices.

This is the same shape shadcn uses for its registries, on purpose. If you've hosted one of those, you've hosted one of
these.

## The document

For each pack, serve:

```json
{
  "manifest": { "name": "pack-analytics", "version": "1.2.0", "category": "feature", "...": "the normal manifest" },
  "files": [{ "path": "files/frontend/src/features/analytics/index.ts", "content": "<base64>" }],
  "revision": { "commit": "3f2a..." }
}
```

- `manifest` is exactly the [manifest](/docs/packs-templates/pack-manifest) you'd write for a local pack. Its `name`
  must match the name that was requested.
- `files` carries every file the manifest references, path relative to the pack root, content base64 encoded. A static
  host can serve this; nothing has to be dynamic.
- `revision` is optional. The CLI hashes the files itself either way.

The document may be up to 16 MB.

## The buyer's side

In `stack.json`, or in a `registries.json` in the CLI's config directory for every project on a machine
(`~/Library/Application Support/hype-stack` on macOS, `~/.config/hype-stack` on Linux, `%APPDATA%\hype-stack` on
Windows):

```json
"registries": {
  "@you": "https://packs.you.dev/{name}.json",
  "@vendor": {
    "url": "https://api.vendor.com/hype/{name}",
    "headers": { "Authorization": "Bearer ${VENDOR_TOKEN}" },
    "params": { "license": "${VENDOR_LICENSE}", "channel": "stable" }
  }
}
```

- The value is a URL with `{name}` in it, or an object with `url`, `headers`, and `params`.
- `${VAR}` anywhere in those three expands from the buyer's environment when the request is built. The token never sits
  in a file that gets committed, and a missing variable is a clear error naming it, not an empty header.
- A project entry wins over the user file for the same namespace.

Then:

```bash
npx @hype-stack/cli community add @vendor/pack-analytics
```

A pack from a registry is a community pack like any other: it goes through the trust prompt, the plan summary names
where it came from and every npm package it adds, the path guards apply to every file in the document, and nothing in it
ever executes.

## Selling a pack

Check whatever your `headers` or `params` carry, and answer `401` or `403` when it doesn't check out:

```json
{ "reason": "no-access", "purchaseUrl": "https://you.dev/buy/pack-analytics" }
```

The buyer sees the reason and the URL. That's the whole integration: your server, your key format, your checkout, your
refund policy. The CLI carries the key.

Two things the CLI will refuse, so don't rely on them:

- **Redirects.** Following one would carry the buyer's credentials to whatever host you pointed at. Answer directly.
- **Files outside the pack.** A `path` with `..` in it is rejected before anything is written.

## Dependencies between your packs

A registry pack can depend on another pack from the same registry by its namespaced name:

```json
"dependencies": ["@you/pack-base", "starter-saas"]
```

`@you/pack-base` is fetched from your registry. `starter-saas` is the Hype Stack catalog, here the whole starter family
rather than one engine. A bare name always means the catalog; a namespaced one always means that namespace. There's no
search order to reason about.

## Or just use git or npm

You may not need any of this. A private GitHub repo or a private npm package is already a paid pack:

```bash
npx @hype-stack/cli community add github:you/pack-analytics#v1.2.0
npx @hype-stack/cli community add npm:@you/pack-analytics
```

The buyer's own git or npm credentials get the fetch through, and you never run a server. Reach for a registry when you
want your own URL, your own key format, or a purchase link in the refusal.
