BizzPocket

The registry: add, diff and how it stays safe

On this page

BizzPocket publishes small pieces of source code: blocks, shared components, data helpers and setting traits. bizzpocket add <name> copies the source into your theme. After that it is your code. Use it as it is, change it, or tweak it. The idea is the same as shadcn/ui: you install source, not a black box.

Contents: Add · Diff · What the registry holds · Setup · Security: who gets your token


bizzpocket add

bash
bunx bizzpocket add money-price
bunx bizzpocket add money-price products-data      # several at once
bunx bizzpocket add hello --overwrite              # replace files you have changed
added money-price

What it does:

  1. Looks the names up in the registry. An unknown name stops everything with UNKNOWN_ITEM.
  2. Also adds anything the item depends on (registryDependencies), so you get a working set.
  3. Checks the whole plan before writing anything. If one file is unsafe or changed, nothing is written.
  4. Writes the files into your theme and records them in bizzpocket.json.

Where files go:

Item kind Copied to
block blocks/<name>/<file>
component components/<name>/<file>
data data/<name>.ts
trait traits/<name>.ts

bizzpocket.json

json
{
  "registry": { "name": "@bizzpocket/blocks", "version": "0.1.0" },
  "items": {
    "money-price": {
      "version": "0.1.0",
      "files": { "components/money-price/money-price.tsx": "fb52e883a918...(a sha-256 of the file as installed)" }
    }
  }
}

It records what you installed and a fingerprint of each file as it was installed. Commit it. It lets add and diff tell your changes from the registry's.

If you changed the file

Run add again for an item whose files you edited and you get:

MODIFIED_FILE: data/products-data.ts has local changes; re-run with --overwrite to replace it

Your work is not lost. Use --overwrite only when you want the registry's version back. Running add again on an item you have not changed is harmless.

Packages the item needs

Items list the npm packages they use (for example @bizzpocket/theme). add does not install them. Make sure they are in your package.json.


bizzpocket diff

diff shows how the registry's current version differs from the copy in your theme. It only reads and prints. Nothing is changed and nothing is run.

bash
bunx bizzpocket diff                 # every installed item
bunx bizzpocket diff products-data   # one item
diff
--- a/data/products-data.ts
+++ b/data/products-data.ts
@@ -4,3 +4,4 @@
 export const productsData = ({ collection, count }: { collection: string; count: number }) => ({
   items: products({ collection, first: count }),
 });
+// mine
  • Lines starting with - are in the registry and not in your file.
  • Lines starting with + are in your file and not in the registry (your changes).
  • No output means your file is the same as the registry's.
  • diff some-name for something you never installed gives NOT_INSTALLED.

To take an upstream change, read the diff and copy the lines you want by hand, or run add <name> --overwrite if you have no changes of your own to keep.


What the registry holds

Today (@bizzpocket/blocks 0.4.0) the registry has 38 items. Four are hand-written and 34 are generated from the toyshop theme:

Kind Count Items
block 20 hello and group (a CSS-only container for other blocks, group.md), both hand-written, and 18 from toyshop: breadcrumbs, cart, category-showcase-by-age, category-showcase-by-category, collection-cards, content-page, footer, grid-best-sellers-toyshop, header, hero, login-form, newsletter, not-found, policy-content, product-detail-fashion, promo-banner, signup-form, testimonials
component 14 money-price (hand-written) and 13 from toyshop: add-to-cart, customer-auth, discount-handoff, home-products, json-ld, paths, pick-categories, price, product-image, safe-url (requireSafeUrl), store-home, store-query, variant-picker

0.3.0 dropped the responsive-image component and the copied URL checks: responsiveImage, isSafeUrl, isSafeMediaUrl and toSafeUrl are @bizzpocket/theme exports now (data.md). A theme that installed the old components/responsive-image keeps working; switch its imports to @bizzpocket/theme and delete the folder. | data | 1 | products-data: a function that returns a products() need for a block with collection and count fields (hand-written). | | trait | 3 | spacing, color-scheme, typography (generated) |

A note on products-data: it is a plain function that calls products(...). A block that calls it inside data() becomes runtime, not static, because only bare calls of the built-in helpers are static (data.md). Copy the one line into your block instead, or use the function in load().

Where the toyshop items come from

The toyshop items are generated, never edited by hand. The toyshop theme (packages/themes/toyshop) is the source of truth, so add installs exactly what the toyshop test suite covers:

bash
bun packages/blocks/scripts/sync-toyshop.ts            # regenerate registry/items and registry.json
bun packages/blocks/scripts/sync-toyshop.ts --check    # exit 1 if anything is out of date or impure

--check fails when an item differs from what toyshop would generate (or is stale), when an item imports anything except @bizzpocket/theme, @bizzpocket/theme/client, react and its own components, and when its CSS has an unguarded custom property (below). The registry tests run it too. Eight toyshop blocks (shop listing, filter rail, account area) still lean on theme-sdk helpers and are skipped. To change an item, change toyshop (or the generator) and regenerate. The four hand-written items (hello, money-price, products-data, group) are the generator's SEEDED list: it leaves them alone but checks them for purity too.

The generator rewrites the theme scope [data-theme="toyshop"] to [data-theme], so the styles apply under any theme's wrapper, and it prepends the shared toyshop class rules a block uses.

Required CSS custom properties

Item CSS reads your theme's tokens as CSS variables. Three groups need nothing from you, because every theme defines them through its theme() config: --colors-*, --fonts-* and --radii-*. Everything else is written with a fallback, so the item still looks right in a theme that does not define it:

Variable Fallback
--ts-on-media-ink #fff (text over a photo and its dark scrim; hero, promo-banner, category-showcase-by-category)
--spacing-page-x / --spacing-section-y / --spacing-block-gap clamp(1rem, 4vw, 3rem) / clamp(2.5rem, 6vw, 5rem) / clamp(1.25rem, 3vw, 2rem)
--motion-fast / --motion-medium / --motion-slow 200ms / 300ms / 500ms
--shadows-sm / --shadows-md / --shadows-lg toyshop's light-mode shadows

Define these in your theme to override the fallbacks. A fallback is only used when the variable is undefined, so toyshop itself renders as before.


Setup

add and diff find the registry in this order:

  1. Inside the BizzPocket repository (the CLI runs from a checkout, or your theme sits inside one), the registry folder packages/blocks/registry is used directly.
  2. Otherwise the npm package @bizzpocket/blocks is downloaded from your registry.

For the second case, tell your package manager where the BizzPocket registry is. Put this .npmrc in your theme folder:

ini
@bizzpocket:registry=https://npm.bizzpocket.com
//npm.bizzpocket.com/:_authToken=${NPM_TOKEN}
  • The registry line can be @bizzpocket:registry=... or registry=.... With neither, the default is https://npm.bizzpocket.com.
  • The token line is only needed if your registry access needs one. The token is read from an environment variable, never written into the file. Only NPM_TOKEN, BIZZPOCKET_NPM_TOKEN and VERDACCIO_TOKEN may be named in .npmrc; any other ${NAME} is refused with INVALID_REGISTRY. The rule is absolute: .npmrc may only reference NPM_TOKEN, BIZZPOCKET_NPM_TOKEN or VERDACCIO_TOKEN. Note: the CLI only checks this on the token line it is about to send. A token line for another host, or one that is skipped because the host is not trusted, is never read, so the error appears only when that token would really be used.
  • The registry address itself cannot contain ${...}.

If the package cannot be found (wrong address, no access, no network) you get REGISTRY_NOT_FOUND.


Security: who gets your token

A theme folder is untrusted input: it may come from a stranger. Its .npmrc and even a .env file next to it could try to trick the CLI into sending your registry token somewhere else. The CLI therefore follows a few strict rules. In plain words:

1. Only known hosts get the token. The token goes to npm.bizzpocket.com and to nothing else, unless you name another host on the command line:

bash
bunx bizzpocket add money-price --trust-registry registry.mycompany.com

--trust-registry takes a bare host name (no https://, no port, no path) and can be repeated. Nothing else can add trust: not an environment variable, not .npmrc, not .env, not any file. If the host is not trusted, the CLI still downloads (anonymously), and prints a warning that it ignored your token.

2. Only over a safe connection. Tokens are sent over https on the normal port. The one exception is plain http to localhost, 127.0.0.1 or [::1], and only if you also trusted that host.

3. Not when something may be listening in the middle. If a proxy variable (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, in any letter case) or NODE_TLS_REJECT_UNAUTHORIZED is set, the token is withheld and the CLI warns. Bun loads a .env file from the folder you run in, so a stranger's theme could use one of these variables to route your token through their server. If you really are behind a proxy you trust, add --allow-proxy:

bash
bunx bizzpocket add money-price --allow-proxy

It still prints a warning. Certificate checking stays on for every request, and the token is never sent over plain http through a proxy.

4. Never with a custom certificate authority. If NODE_EXTRA_CA_CERTS, SSL_CERT_FILE or SSL_CERT_DIR is set, the token is always withheld, and --allow-proxy does not change that. A planted certificate authority would make an interceptor look legitimate. Unset the variable to authenticate.

5. Only to the registry's own address. The token is attached only to requests to the registry's origin, and a redirect on such a request is an error instead of being followed. So it cannot be forwarded to a tarball on another host.

6. The download is checked. The package is verified against the registry's sha512 (or sha1) checksum before anything is read.

7. Files stay inside your theme. Item names and file paths are checked. A path that leaves the theme folder, goes through a symlink, or uses a reserved Windows name is refused with UNSAFE_PATH. Files are written safely (to a temporary file first, then renamed), and add and diff never run any of the code they copy.

If a withheld token means the registry refuses you, the symptom is REGISTRY_NOT_FOUND. Read the warning printed just above it: it names the variable.

Next: migrate.md.